Selaa lähdekoodia

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 vuotta sitten
vanhempi
commit
be1d3250bd
100 muutettua tiedostoa jossa 3688 lisäystä ja 130 poistoa
  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 Näytä tiedosto

@@ -365,9 +365,16 @@ list of possible build targets.
<include name="**/*.java"/>
<exclude name="org/apache/fop/render/*/**/*.java"/>
<exclude name="org/apache/fop/afp/**/*.java"/>
<exclude name="org/apache/fop/accessibility/**/*.java"/>
</fileset>
</eventResourceGenerator>
<fixcrlf file="${src.java.dir}/org/apache/fop/events/EventFormatter.xml" tab="remove" tablength="2"/>
<eventResourceGenerator modelfile="${build.gensrc.dir}/org/apache/fop/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">
<fileset dir="${src.java.dir}">
<include name="org/apache/fop/afp/**/*.java"/>

+ 1
- 0
src/documentation/content/xdocs/site.xml Näytä tiedosto

@@ -159,6 +159,7 @@
<extensions label="Extensions" href="extensions.html"/>
<events label="Events" href="events.html"/>
<metadata label="Metadata" href="metadata.html"/>
<accessibility label="Accessibility" href="accessibility.html"/>
</features>
</trunk>

+ 152
- 0
src/documentation/content/xdocs/trunk/accessibility.xml Näytä tiedosto

@@ -0,0 +1,152 @@
<?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 Näytä tiedosto

@@ -53,8 +53,9 @@
lack of a full license to get a detailed error protocol.
</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>
</section>
<section id="command-line">
@@ -64,6 +65,9 @@
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.
</p>
<p>
PDF/A-1a is enabled by specifying "-pdfprofile PDF/A-1a".
</p>
</section>
<section id="embedded">
<title>Usage (embedded)</title>
@@ -80,6 +84,9 @@ Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent);
If one of the validation rules of PDF/A is violated, an PDFConformanceException
(descendant of RuntimeException) is thrown.
</p>
<p>
For PDF/A-1a, just use the string "PDF/A-1a" instead of "PDF/A-1b".
</p>
</section>
<section id="rules">
<title>PDF/A in Action</title>
@@ -118,12 +125,17 @@ Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent);
embedded in clear text so non-PDF-aware applications can extract the XMP metadata.
</li>
</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 id="profile-compatibility">
<title>PDF profile compatibility</title>
<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>
</section>
<section id="interoperability">

+ 2
- 1
src/java/META-INF/services/org.apache.fop.fo.ElementMapping Näytä tiedosto

@@ -2,9 +2,10 @@ org.apache.fop.fo.FOElementMapping
org.apache.fop.fo.extensions.svg.SVGElementMapping
org.apache.fop.fo.extensions.svg.BatikExtensionElementMapping
org.apache.fop.fo.extensions.ExtensionElementMapping
org.apache.fop.fo.extensions.InternalElementMapping
org.apache.fop.fo.extensions.OldExtensionElementMapping
org.apache.fop.fo.extensions.xmp.XMPElementMapping
org.apache.fop.fo.extensions.xmp.RDFElementMapping
org.apache.fop.render.ps.extensions.PSExtensionElementMapping
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 Näytä tiedosto

@@ -0,0 +1,87 @@
/*
* 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 Näytä tiedosto

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

/* $Id$ */

package org.apache.fop.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 Näytä tiedosto

@@ -0,0 +1,4 @@
<?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 Näytä tiedosto

@@ -0,0 +1,95 @@
/*
* 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 Näytä tiedosto

@@ -0,0 +1,102 @@
/*
* 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 Näytä tiedosto

@@ -0,0 +1,95 @@
/*
* 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 Näytä tiedosto

@@ -0,0 +1,88 @@
<?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 Näytä tiedosto

@@ -0,0 +1,100 @@
<?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 Näytä tiedosto

@@ -37,6 +37,8 @@ import org.apache.xmlgraphics.image.loader.ImageSessionContext;
import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext;

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.Event;
import org.apache.fop.events.EventBroadcaster;
@@ -99,6 +101,8 @@ public class FOUserAgent {
private boolean conserveMemoryPolicy = false;
private EventBroadcaster eventBroadcaster = new FOPEventBroadcaster();

private StructureTree structureTree;

/** Producer: Metadata element for the system/software that produces
* the document. (Some renderers can store this in the document.)
*/
@@ -152,6 +156,7 @@ public class FOUserAgent {
this.factory = factory;
setBaseURL(factory.getBaseURL());
setTargetResolution(factory.getTargetResolution());
setAccessibility(factory.isAccessibilityEnabled());
}

/** @return the associated FopFactory instance */
@@ -196,6 +201,7 @@ public class FOUserAgent {
return rendererOverride;
}


/**
* Sets an explicit FOEventHandler instance which overrides the one
* defined by the render type setting.
@@ -642,5 +648,49 @@ public class FOUserAgent {
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 Näytä tiedosto

@@ -24,6 +24,7 @@ import java.io.OutputStream;

import org.xml.sax.helpers.DefaultHandler;

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

/**
@@ -110,7 +111,11 @@ public class Fop {
if (foTreeBuilder == null) {
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 Näytä tiedosto

@@ -100,6 +100,11 @@ public class FopFactory implements ImageContext {
*/
private String base = null;

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

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

@@ -184,6 +189,19 @@ public class FopFactory implements ImageContext {
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
* instance.

+ 9
- 0
src/java/org/apache/fop/apps/FopFactoryConfigurator.java Näytä tiedosto

@@ -92,6 +92,15 @@ public class FopFactoryConfigurator {
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
if (cfg.getChild("strict-configuration", false) != null) {
try {

+ 89
- 15
src/java/org/apache/fop/area/AreaTreeParser.java Näytä tiedosto

@@ -39,8 +39,6 @@ import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXTransformerFactory;
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.Document;
import org.xml.sax.Attributes;
@@ -50,12 +48,17 @@ import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;

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

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

import org.apache.fop.accessibility.AccessibilityEventProducer;
import org.apache.fop.accessibility.StructureTreeBuilder;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.area.Trait.Background;
import org.apache.fop.area.Trait.InternalLink;
@@ -84,6 +87,8 @@ import org.apache.fop.util.ContentHandlerFactory;
import org.apache.fop.util.ContentHandlerFactoryRegistry;
import org.apache.fop.util.ConversionUtils;
import org.apache.fop.util.DefaultErrorListener;
import org.apache.fop.util.DelegatingContentHandler;
import org.apache.fop.util.XMLConstants;
import org.apache.fop.util.XMLUtil;

/**
@@ -156,6 +161,26 @@ public class AreaTreeParser {
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,
ElementMappingRegistry elementMappingRegistry) {
this.treeModel = treeModel;
@@ -192,6 +217,11 @@ public class AreaTreeParser {
makers.put("bookmarkTree", new BookmarkTreeMaker());
makers.put("bookmark", new BookmarkMaker());
makers.put("destination", new DestinationMaker());

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

private Area findAreaType(Class clazz) {
@@ -265,19 +295,35 @@ public class AreaTreeParser {
delegate.startDocument();
delegate.startElement(uri, localName, qName, attributes);
} else {
lastAttributes = new AttributesImpl(attributes);
boolean handled = true;
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 {
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 {
ContentHandlerFactoryRegistry registry
@@ -304,6 +350,23 @@ public class AreaTreeParser {
}
}

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} */
public void endElement(String uri, String localName, String qName) throws SAXException {
if (delegate != null) {
@@ -700,6 +763,7 @@ public class AreaTreeParser {
setTraits(attributes, ip, SUBSET_BOX);
setTraits(attributes, ip, SUBSET_COLOR);
setTraits(attributes, ip, SUBSET_LINK);
setPtr(ip, attributes);
Area parent = (Area)areaStack.peek();
parent.addChildArea(ip);
areaStack.push(ip);
@@ -748,6 +812,7 @@ public class AreaTreeParser {
"tlsadjust", 0));
text.setTextWordSpaceAdjust(XMLUtil.getAttributeAsInt(attributes,
"twsadjust", 0));
setPtr(text, attributes);
Area parent = (Area)areaStack.peek();
parent.addChildArea(text);
areaStack.push(text);
@@ -840,6 +905,7 @@ public class AreaTreeParser {
viewport.setContentPosition(XMLUtil.getAttributeAsRectangle2D(attributes, "pos"));
viewport.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clip", false));
viewport.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
setPtr(viewport, attributes);
Area parent = (Area)areaStack.peek();
parent.addChildArea(viewport);
areaStack.push(viewport);
@@ -858,6 +924,7 @@ public class AreaTreeParser {
transferForeignObjects(attributes, image);
setAreaAttributes(attributes, image);
setTraits(attributes, image, SUBSET_COMMON);
setPtr(image, attributes);
getCurrentViewport().setContent(image);
}
}
@@ -991,10 +1058,10 @@ public class AreaTreeParser {
ExtensionAttachment attachment = (ExtensionAttachment)obj;
ato.addExtensionAttachment(attachment);
} 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) {
area.setIPD(Integer.parseInt(attributes.getValue("ipd")));
@@ -1133,7 +1200,7 @@ public class AreaTreeParser {
for (int i = 0, c = atts.getLength(); i < c; i++) {
String ns = atts.getURI(i);
if (ns.length() > 0) {
if ("http://www.w3.org/2000/xmlns/".equals(ns)) {
if (XMLConstants.XMLNS_NAMESPACE_URI.equals(ns)) {
continue;
}
QName qname = new QName(ns, atts.getQName(i));
@@ -1142,6 +1209,13 @@ public class AreaTreeParser {
}
}

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

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

+ 5
- 1
src/java/org/apache/fop/area/Trait.java Näytä tiedosto

@@ -194,9 +194,12 @@ public class Trait implements Serializable {
public static final Integer OVERLINE_COLOR = new Integer(35);
/** Trait for color of linethrough decorations when rendering inline parent. */
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 */
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];

@@ -225,6 +228,7 @@ public class Trait implements Serializable {
static {
// Create a hashmap mapping trait code to name for external representation
//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(EXTERNAL_LINK, new TraitInfo("external-link", ExternalLink.class));
put(FONT, new TraitInfo("font", FontTriplet.class));

+ 4
- 0
src/java/org/apache/fop/cli/CommandLineOptions.java Näytä tiedosto

@@ -36,6 +36,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.Version;
import org.apache.fop.accessibility.Accessibility;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FopFactory;
@@ -342,6 +343,8 @@ public class CommandLineOptions {
i = i + parseAreaTreeOption(args, i);
} else if (args[i].equals("-if")) {
i = i + parseIntermediateFormatOption(args, i);
} else if (args[i].equals("-a")) {
this.renderingOptions.put(Accessibility.ACCESSIBILITY, Boolean.TRUE);
} else if (args[i].equals("-v")) {
/* Currently just print the version */
printVersion();
@@ -1155,6 +1158,7 @@ public class CommandLineOptions {
+ " -nocopy PDF file will be encrypted without copy 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"
+ " -a enables accessibility features (Tagged PDF etc., default off)\n"
+ " -pdfprofile prof PDF file will be generated with the specified profile\n"
+ " (Examples for prof: PDF/A-1b or PDF/X-3:2003)\n\n"
+ " -conserve Enable memory-conservation policy (trades memory-consumption for disk I/O)\n"

+ 1
- 0
src/java/org/apache/fop/events/EventFormatter.xml Näytä tiedosto

@@ -107,4 +107,5 @@ Any reference to it will be considered a reference to the first occurrence in th
<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.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>

+ 9
- 1
src/java/org/apache/fop/fo/Constants.java Näytä tiedosto

@@ -771,8 +771,16 @@ public interface Constants {
* multi-column layouts.
*/
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 */
int PROPERTY_COUNT = 273;
int PROPERTY_COUNT = 275;

// compound property constants


+ 3
- 0
src/java/org/apache/fop/fo/FONode.java Näytä tiedosto

@@ -36,6 +36,7 @@ import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.extensions.ExtensionAttachment;
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.pagination.Root;
import org.apache.fop.util.CharUtilities;
@@ -415,6 +416,8 @@ public abstract class FONode implements Cloneable {
return "fo:" + localName;
} else if (namespaceURI.equals(ExtensionElementMapping.URI)) {
return "fox:" + localName;
} else if (namespaceURI.equals(InternalElementMapping.URI)) {
return "foi:" + localName; // used FOP internally for accessibility
} else if (namespaceURI.equals(SVGElementMapping.URI)) {
return "svg:" + localName;
} else {

+ 12
- 0
src/java/org/apache/fop/fo/FOPropertyMapping.java Näytä tiedosto

@@ -2515,6 +2515,18 @@ public final class FOPropertyMapping implements Constants {
m.setDefault("");
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
m = new LengthProperty.Maker(PR_PROVISIONAL_LABEL_SEPARATION);
m.setInherited(true);

+ 12
- 1
src/java/org/apache/fop/fo/FOValidationEventProducer.java Näytä tiedosto

@@ -36,7 +36,9 @@ public interface FOValidationEventProducer extends EventProducer {
/**
* Provider class for the event producer.
*/
class Provider {
final class Provider {

private Provider() { }

/**
* Returns an event producer.
@@ -354,4 +356,13 @@ public interface FOValidationEventProducer extends EventProducer {
void unknownFormattingObject(Object source, String elementName,
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 Näytä tiedosto

@@ -46,6 +46,8 @@ public class ExtensionElementMapping extends ElementMapping {
propertyAttributes.add("orphan-content-limit");
propertyAttributes.add("internal-destination");
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 Näytä tiedosto

@@ -31,7 +31,7 @@ import org.apache.fop.fo.pagination.AbstractPageSequence;
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 {


+ 73
- 0
src/java/org/apache/fop/fo/extensions/InternalElementMapping.java Näytä tiedosto

@@ -0,0 +1,73 @@
/*
* 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 Näytä tiedosto

@@ -29,6 +29,7 @@ import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.fo.properties.LengthRangeProperty;
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">
@@ -36,7 +37,8 @@ import org.apache.fop.fo.properties.SpaceProperty;
* and <a href="http://www.w3.org/TR/xsl/#fo_external-graphic">
* <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
// and external-graphics.
@@ -60,6 +62,7 @@ public abstract class AbstractGraphics extends FObj implements GraphicsPropertie
private int scaling;
private int textAlign;
private Length width;
private String ptr; // used for accessibility
// Unused but valid items, commented out for performance:
// private CommonAccessibility commonAccessibility;
// private CommonAural commonAural;
@@ -94,6 +97,7 @@ public abstract class AbstractGraphics extends FObj implements GraphicsPropertie
dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum();
height = pList.get(PR_HEIGHT).getLength();
id = pList.get(PR_ID).getString();
ptr = pList.get(PR_X_PTR).getString(); // used for accessibility
inlineProgressionDimension = pList.get(PR_INLINE_PROGRESSION_DIMENSION).getLengthRange();
keepWithNext = pList.get(PR_KEEP_WITH_NEXT).getKeep();
keepWithPrevious = pList.get(PR_KEEP_WITH_PREVIOUS).getKeep();
@@ -102,6 +106,12 @@ public abstract class AbstractGraphics extends FObj implements GraphicsPropertie
scaling = pList.get(PR_SCALING).getEnum();
textAlign = pList.get(PR_TEXT_ALIGN).getEnum();
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());
}
}
}

/**
@@ -207,6 +217,11 @@ public abstract class AbstractGraphics extends FObj implements GraphicsPropertie
return keepWithPrevious;
}

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

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


+ 11
- 2
src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java Näytä tiedosto

@@ -21,8 +21,8 @@ package org.apache.fop.fo.flow;

import java.awt.Color;

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

import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Length;
@@ -35,6 +35,7 @@ import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.CommonFont;
import org.apache.fop.fo.properties.CommonTextDecoration;
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">
@@ -42,7 +43,8 @@ import org.apache.fop.fo.properties.SpaceProperty;
* <a href="http://www.w3.org/TR/xsl/#fo_page-number-citation-last">
* <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).
private CommonBorderPaddingBackground commonBorderPaddingBackground;
@@ -51,6 +53,7 @@ public abstract class AbstractPageNumberCitation extends FObj {
private int alignmentBaseline;
private Length baselineShift;
private int dominantBaseline;
private String ptr; // used for accessibility
// private ToBeImplementedProperty letterSpacing;
private SpaceProperty lineHeight;
private String refId;
@@ -96,6 +99,7 @@ public abstract class AbstractPageNumberCitation extends FObj {
dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum();
// letterSpacing = pList.get(PR_LETTER_SPACING);
lineHeight = pList.get(PR_LINE_HEIGHT).getSpace();
ptr = pList.get(PR_X_PTR).getString(); // used for accessibility
refId = pList.get(PR_REF_ID).getString();
textDecoration = pList.getTextDecorationProps();
// textShadow = pList.get(PR_TEXT_SHADOW);
@@ -138,6 +142,11 @@ public abstract class AbstractPageNumberCitation extends FObj {
return textDecoration;
}

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

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

+ 11
- 2
src/java/org/apache/fop/fo/flow/Block.java Näytä tiedosto

@@ -21,6 +21,8 @@ package org.apache.fop.fo.flow;

import java.awt.Color;

import org.xml.sax.Locator;

import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Length;
import org.apache.fop.datatypes.Numeric;
@@ -38,13 +40,13 @@ import org.apache.fop.fo.properties.CommonMarginBlock;
import org.apache.fop.fo.properties.CommonRelativePosition;
import org.apache.fop.fo.properties.KeepProperty;
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">
* <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
private boolean blockOrInlineItemFound = false;
@@ -71,6 +73,7 @@ public class Block extends FObjMixed implements BreakPropertySet {
private int lineHeightShiftAdjustment;
private int lineStackingStrategy;
private Numeric orphans;
private String ptr; //used for accessibility
private int whiteSpaceTreatment;
private int span;
private int textAlign;
@@ -122,6 +125,7 @@ public class Block extends FObjMixed implements BreakPropertySet {
lineHeightShiftAdjustment = pList.get(PR_LINE_HEIGHT_SHIFT_ADJUSTMENT).getEnum();
lineStackingStrategy = pList.get(PR_LINE_STACKING_STRATEGY).getEnum();
orphans = pList.get(PR_ORPHANS).getNumeric();
ptr = pList.get(PR_X_PTR).getString(); //used for accessibility
whiteSpaceTreatment = pList.get(PR_WHITE_SPACE_TREATMENT).getEnum();
span = pList.get(PR_SPAN).getEnum();
textAlign = pList.get(PR_TEXT_ALIGN).getEnum();
@@ -171,6 +175,11 @@ public class Block extends FObjMixed implements BreakPropertySet {
return breakAfter;
}

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

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

+ 9
- 1
src/java/org/apache/fop/fo/flow/Character.java Näytä tiedosto

@@ -38,12 +38,13 @@ import org.apache.fop.fo.properties.CommonTextDecoration;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.fo.properties.Property;
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">
* <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.
private CommonBorderPaddingBackground commonBorderPaddingBackground;
private CommonFont commonFont;
@@ -62,6 +63,7 @@ public class Character extends FObj {
private CommonTextDecoration textDecoration;
// private ToBeImplementedProperty textShadow;
private Property wordSpacing;
private String ptr; // used for accessibility
// Unused but valid items, commented out for performance:
// private CommonAural commonAural;
// private CommonMarginInline commonMarginInline;
@@ -108,6 +110,7 @@ public class Character extends FObj {
lineHeight = pList.get(PR_LINE_HEIGHT).getSpace();
textDecoration = pList.getTextDecorationProps();
wordSpacing = pList.get(PR_WORD_SPACING);
ptr = pList.get(PR_X_PTR).getString(); // used for accessibility
}

/** {@inheritDoc} */
@@ -207,6 +210,11 @@ public class Character extends FObj {
return keepWithPrevious;
}

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

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

+ 9
- 1
src/java/org/apache/fop/fo/flow/Inline.java Näytä tiedosto

@@ -26,17 +26,19 @@ import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList;
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">
* <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.
// See also superclass InlineLevel
private Length alignmentAdjust;
private int alignmentBaseline;
private Length baselineShift;
private String ptr; // used for accessibility
private int dominantBaseline;
// Unused but valid items, commented out for performance:
// private CommonRelativePosition commonRelativePosition;
@@ -66,6 +68,7 @@ public class Inline extends InlineLevel {
alignmentBaseline = pList.get(PR_ALIGNMENT_BASELINE).getEnum();
baselineShift = pList.get(PR_BASELINE_SHIFT).getLength();
dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum();
ptr = pList.get(PR_X_PTR).getString(); // used for accessibility
}

/** {@inheritDoc} */
@@ -144,6 +147,11 @@ public class Inline extends InlineLevel {
return dominantBaseline;
}

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

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

+ 9
- 1
src/java/org/apache/fop/fo/flow/PageNumber.java Näytä tiedosto

@@ -34,12 +34,13 @@ import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.CommonFont;
import org.apache.fop.fo.properties.CommonTextDecoration;
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">
* <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.
private CommonBorderPaddingBackground commonBorderPaddingBackground;
private CommonFont commonFont;
@@ -47,6 +48,7 @@ public class PageNumber extends FObj {
private int alignmentBaseline;
private Length baselineShift;
private int dominantBaseline;
private String ptr; // used for accessibility
// private ToBeImplementedProperty letterSpacing;
private SpaceProperty lineHeight;
/** Holds the text decoration values. May be null */
@@ -92,6 +94,7 @@ public class PageNumber extends FObj {
// letterSpacing = pList.get(PR_LETTER_SPACING);
lineHeight = pList.get(PR_LINE_HEIGHT).getSpace();
textDecoration = pList.getTextDecorationProps();
ptr = pList.get(PR_X_PTR).getString(); // used for accessibility
// textShadow = pList.get(PR_TEXT_SHADOW);

// implicit properties
@@ -165,6 +168,11 @@ public class PageNumber extends FObj {
return lineHeight;
}

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

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

+ 12
- 3
src/java/org/apache/fop/fo/flow/table/TableFObj.java Näytä tiedosto

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

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.datatypes.Numeric;
import org.apache.fop.datatypes.ValidationPercentBaseContext;
@@ -33,19 +36,19 @@ import org.apache.fop.fo.properties.EnumProperty;
import org.apache.fop.fo.properties.NumberProperty;
import org.apache.fop.fo.properties.Property;
import org.apache.fop.fo.properties.PropertyMaker;
import org.apache.fop.fo.properties.StructurePointerPropertySet;
import org.apache.fop.layoutmgr.table.CollapsingBorderModel;
import org.xml.sax.Locator;
import org.xml.sax.Attributes;

/**
* 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 borderBeforePrecedence;
private Numeric borderEndPrecedence;
private Numeric borderStartPrecedence;
private String ptr;

ConditionalBorder borderBefore;
ConditionalBorder borderAfter;
@@ -71,6 +74,7 @@ public abstract class TableFObj extends FObj {
borderBeforePrecedence = pList.get(PR_BORDER_BEFORE_PRECEDENCE).getNumeric();
borderEndPrecedence = pList.get(PR_BORDER_END_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
&& getNameId() != FO_TABLE_CELL
&& getCommonBorderPaddingBackground().hasPadding(
@@ -235,6 +239,11 @@ public abstract class TableFObj extends FObj {
}
}

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

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

+ 34
- 0
src/java/org/apache/fop/fo/properties/StructurePointerPropertySet.java Näytä tiedosto

@@ -0,0 +1,34 @@
/*
* 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 Näytä tiedosto

@@ -391,6 +391,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager

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

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

+ 11
- 0
src/java/org/apache/fop/layoutmgr/TraitSetter.java Näytä tiedosto

@@ -583,6 +583,17 @@ public class TraitSetter {
}
}

/**
* 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
* generating FO node.

+ 1
- 0
src/java/org/apache/fop/layoutmgr/inline/AbstractGraphicsLayoutManager.java Näytä tiedosto

@@ -85,6 +85,7 @@ public abstract class AbstractGraphicsLayoutManager extends LeafNodeLayoutManage
transferForeignAttributes(viewportArea);

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

+ 1
- 0
src/java/org/apache/fop/layoutmgr/inline/AbstractPageNumberCitationLayoutManager.java Näytä tiedosto

@@ -138,6 +138,7 @@ public abstract class AbstractPageNumberCitationLayoutManager extends LeafNodeLa
text.setBaselineOffset(font.getAscender());
TraitSetter.addFontTraits(text, font);
text.addTrait(Trait.COLOR, fobj.getColor());
TraitSetter.addPtr(text, fobj.getPtr()); // used for accessibility
TraitSetter.addTextDecoration(text, fobj.getTextDecoration());
}


+ 6
- 4
src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java Näytä tiedosto

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

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.fo.flow.BasicLink;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.flow.BasicLink;
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
@@ -56,6 +57,7 @@ public class BasicLinkLayoutManager extends InlineLayoutManager {
private void setupBasicLinkArea(InlineArea area) {
BasicLink fobj = (BasicLink) this.fobj;
// internal destinations take precedence:
TraitSetter.addPtr(area, fobj.getPtr()); // used for accessibility
if (fobj.hasInternalDestination()) {
String idref = fobj.getInternalDestination();
PageSequenceLayoutManager pslm = getPSLM();

+ 1
- 0
src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java Näytä tiedosto

@@ -86,6 +86,7 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager {
}
TraitSetter.setProducerID(text, node.getId());
TraitSetter.addTextDecoration(text, node.getTextDecoration());
TraitSetter.addPtr(text, node.getPtr()); // used for accessibility
return text;
}


+ 1
- 1
src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java Näytä tiedosto

@@ -85,7 +85,7 @@ public class PageNumberLayoutManager extends LeafNodeLayoutManager {
text.setBaselineOffset(font.getAscender());
TraitSetter.addFontTraits(text, font);
text.addTrait(Trait.COLOR, fobj.getColor());
TraitSetter.addPtr(text, fobj.getPtr()); // used for accessibility
TraitSetter.addTextDecoration(text, fobj.getTextDecoration());

return text;

+ 18
- 1
src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java Näytä tiedosto

@@ -25,10 +25,13 @@ import java.util.ListIterator;

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

import org.apache.fop.area.Trait;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.fo.Constants;
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.FontSelector;
import org.apache.fop.layoutmgr.InlineKnuthSequence;
@@ -506,12 +509,26 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
}
TraitSetter.addFontTraits(textArea, font);
textArea.addTrait(Trait.COLOR, this.foText.getColor());
TraitSetter.addPtr(textArea, getPtr()); // used for accessibility
TraitSetter.addTextDecoration(textArea, this.foText.getTextDecoration());

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) {
if (this.letterAdjustArray[index] == null) {
this.letterAdjustArray[index] = new MinOptMax(width);

+ 12
- 1
src/java/org/apache/fop/pdf/PDFAMode.java Näytä tiedosto

@@ -44,7 +44,18 @@ public final class PDFAMode {
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() {
return (this != DISABLED);
//PDF/A-1a is a superset of PDF/A-1b!

+ 9
- 0
src/java/org/apache/fop/pdf/PDFArray.java Näytä tiedosto

@@ -106,6 +106,15 @@ public class PDFArray extends PDFObject {
}
}

/**
* 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
* @return the length of the array

+ 19
- 0
src/java/org/apache/fop/pdf/PDFDocument.java Näytä tiedosto

@@ -354,6 +354,25 @@ public class PDFDocument {
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.
*

+ 33
- 0
src/java/org/apache/fop/pdf/PDFFactory.java Näytä tiedosto

@@ -185,6 +185,10 @@ public class PDFFactory {
public PDFPage makePage(PDFResources resources, int pageIndex,
Rectangle2D mediaBox, Rectangle2D cropBox,
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);

getDocument().assignObjectNumber(page);
@@ -882,6 +886,35 @@ public class PDFFactory {
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).
*

+ 13
- 0
src/java/org/apache/fop/pdf/PDFLink.java Näytä tiedosto

@@ -42,6 +42,7 @@ public class PDFLink extends PDFObject {
private float bry;
private String color;
private PDFAction action;
private Integer structParent;

/**
* create objects associated with a link annotation (GoToR)
@@ -68,6 +69,16 @@ public class PDFLink extends PDFObject {
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}
*/
@@ -87,6 +98,8 @@ public class PDFLink extends PDFObject {
+ (brx) + " " + (bry) + " ]\n" + "/C [ "
+ this.color + " ]\n" + "/Border [ 0 0 0 ]\n" + "/A "
+ this.action.getAction() + "\n" + "/H /I\n"
+ (this.structParent != null
? "/StructParent " + this.structParent.toString() + "\n" : "")
+ fFlag + "\n>>\nendobj\n";
return s;
}

+ 20
- 2
src/java/org/apache/fop/pdf/PDFNumsArray.java Näytä tiedosto

@@ -52,13 +52,31 @@ public class PDFNumsArray extends PDFObject {
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.
* @param key the key of the value to set
* @param obj the new value
*/
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);
}

/**
@@ -67,7 +85,7 @@ public class PDFNumsArray extends PDFObject {
* @return the requested value
*/
public Object get(int key) {
return this.map.get(new Integer(key));
return get(new Integer(key));
}

/** {@inheritDoc} */

+ 29
- 0
src/java/org/apache/fop/pdf/PDFPage.java Näytä tiedosto

@@ -154,4 +154,33 @@ public class PDFPage extends PDFResourceContext {
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 Näytä tiedosto

@@ -0,0 +1,44 @@
/*
* 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 Näytä tiedosto

@@ -58,9 +58,6 @@ public class PDFProfile {
*/
protected void validateProfileCombination() {
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 (pdfXMode != PDFXMode.DISABLED && pdfXMode != PDFXMode.PDFX_3_2003) {
throw new PDFConformanceException(
@@ -192,6 +189,32 @@ public class PDFProfile {
}
}

/**
* 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. */
public boolean isIDEntryRequired() {
return isPDFAActive() || isPDFXActive();

+ 45
- 1
src/java/org/apache/fop/pdf/PDFRoot.java Näytä tiedosto

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

package org.apache.fop.pdf;

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

/**
* Class representing a Root (/Catalog) object.
*/
@@ -56,7 +59,7 @@ public class PDFRoot extends PDFDictionary {
* object must be created before the PDF document is
* generated, but it is not assigned an object ID until
* 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 pages the PDFPages object
@@ -68,6 +71,12 @@ public class PDFRoot extends PDFDictionary {
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.
*
@@ -252,4 +261,39 @@ public class PDFRoot extends PDFDictionary {
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 Näytä tiedosto

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

/* $Id$ */

package org.apache.fop.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 Näytä tiedosto

@@ -0,0 +1,55 @@
/*
* 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 Näytä tiedosto

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

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

import org.apache.fop.apps.FOUserAgent;

/**
@@ -29,7 +30,7 @@ import org.apache.fop.apps.FOUserAgent;
public abstract class AbstractRendererConfigurator extends AbstractConfigurator {

private static final String TYPE = "renderer";
/**
* Default constructor
* @param userAgent user agent
@@ -55,7 +56,7 @@ public abstract class AbstractRendererConfigurator extends AbstractConfigurator
protected Configuration getRendererConfig(String mimeType) {
return super.getConfig(mimeType);
}
/**
* {@inheritDoc}
*/

+ 1
- 0
src/java/org/apache/fop/render/afp/AFPEventProducer.xml Näytä tiedosto

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

+ 2
- 0
src/java/org/apache/fop/render/intermediate/IFConstants.java Näytä tiedosto

@@ -50,4 +50,6 @@ public interface IFConstants extends XMLConstants {
String EL_BORDER_RECT = "border-rect";
String EL_FONT = "font";
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 Näytä tiedosto

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

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

import org.apache.xmlgraphics.util.QName;
@@ -43,6 +44,10 @@ public class IFContext {
/** foreign attributes: Map<QName, Object> */
private Map foreignAttributes = Collections.EMPTY_MAP;

private Locale language;

private String structurePointer;

/**
* Main constructor.
* @param ua the user agent
@@ -108,4 +113,46 @@ public class IFContext {
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 Näytä tiedosto

@@ -25,6 +25,7 @@ import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.util.Map;
import java.util.Set;

import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
@@ -34,7 +35,6 @@ import javax.xml.transform.sax.SAXTransformerFactory;

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

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
@@ -46,6 +46,8 @@ import org.apache.commons.logging.LogFactory;

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.fo.ElementMapping;
import org.apache.fop.fo.ElementMappingRegistry;
@@ -59,6 +61,7 @@ import org.apache.fop.util.ContentHandlerFactory;
import org.apache.fop.util.ContentHandlerFactoryRegistry;
import org.apache.fop.util.DOMBuilderContentHandlerFactory;
import org.apache.fop.util.DefaultErrorListener;
import org.apache.fop.util.DelegatingContentHandler;
import org.apache.fop.util.XMLUtil;

/**
@@ -73,6 +76,15 @@ public class IFParser implements IFConstants {
private static SAXTransformerFactory tFactory
= (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.
* @param src the Source instance pointing to the intermediate file
@@ -140,6 +152,26 @@ public class IFParser implements IFConstants {

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,
ElementMappingRegistry elementMappingRegistry) {
this.documentHandler = documentHandler;
@@ -163,6 +195,11 @@ public class IFParser implements IFConstants {
elementHandlers.put(EL_LINE, new LineHandler());
elementHandlers.put(EL_BORDER_RECT, new BorderRectHandler());
elementHandlers.put(EL_IMAGE, new ImageHandler());

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

private void establishForeignAttributes(Map foreignAttributes) {
@@ -173,31 +210,50 @@ public class IFParser implements IFConstants {
documentHandler.getContext().resetForeignAttributes();
}

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

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

/** {@inheritDoc} */
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (delegate != null) {
//delegateStack.push(qName);
delegateDepth++;
delegate.startElement(uri, localName, qName, attributes);
} else {
boolean handled = true;
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 {
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)) {
if (this.navParser == null) {
@@ -241,6 +297,25 @@ public class IFParser implements IFConstants {
}
}

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 {
if (ife.getCause() instanceof SAXException) {
//unwrap
@@ -352,6 +427,11 @@ public class IFParser implements IFConstants {

public void startElement(Attributes attributes) throws IFException {
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);
establishForeignAttributes(foreignAttributes);
documentHandler.startPageSequence(id);
@@ -360,6 +440,7 @@ public class IFParser implements IFConstants {

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

}
@@ -484,7 +565,9 @@ public class IFParser implements IFConstants {
s = lastAttributes.getValue("word-spacing");
int wordSpacing = (s != null ? Integer.parseInt(s) : 0);
int[] dx = XMLUtil.getAttributeAsIntArray(lastAttributes, "dx");
setStructurePointer(lastAttributes);
painter.drawText(x, y, letterSpacing, wordSpacing, dx, content.toString());
resetStructurePointer();
}

public boolean ignoreCharacters() {
@@ -579,6 +662,7 @@ public class IFParser implements IFConstants {
int height = Integer.parseInt(lastAttributes.getValue("height"));
Map foreignAttributes = getForeignAttributes(lastAttributes);
establishForeignAttributes(foreignAttributes);
setStructurePointer(lastAttributes);
if (foreignObject != null) {
painter.drawImage(foreignObject,
new Rectangle(x, y, width, height));
@@ -592,6 +676,7 @@ public class IFParser implements IFConstants {
painter.drawImage(uri, new Rectangle(x, y, width, height));
}
resetForeignAttributes();
resetStructurePointer();
inForeignObject = false;
}

@@ -632,11 +717,7 @@ public class IFParser implements IFConstants {
for (int i = 0, c = atts.getLength(); i < c; i++) {
String ns = atts.getURI(i);
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;
}
if (foreignAttributes == null) {
@@ -649,6 +730,13 @@ public class IFParser implements IFConstants {
return foreignAttributes;
}

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

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

+ 33
- 3
src/java/org/apache/fop/render/intermediate/IFRenderer.java Näytä tiedosto

@@ -30,6 +30,7 @@ import java.io.OutputStream;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Stack;

@@ -493,6 +494,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
try {
if (this.inPageSequence) {
documentHandler.endPageSequence();
documentHandler.getContext().setLanguage(null);
} else {
if (this.documentMetadata == null) {
this.documentMetadata = createDefaultDocumentMetadata();
@@ -502,6 +504,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
this.inPageSequence = true;
}
establishForeignAttributes(pageSequence.getForeignAttributes());
documentHandler.getContext().setLanguage(toLocale(pageSequence));
documentHandler.startPageSequence(null);
resetForeignAttributes();
processExtensionAttachments(pageSequence);
@@ -510,6 +513,17 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
}
}

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() {
Metadata xmp = new Metadata();
DublinCoreAdapter dc = DublinCoreSchema.getAdapter(xmp);
@@ -604,6 +618,14 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
documentHandler.getContext().resetForeignAttributes();
}

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

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

/** {@inheritDoc} */
protected void saveGraphicsState() {
graphicContextStack.push(graphicContext);
@@ -824,17 +846,20 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
currentIPPosition = saveIP;
currentBPPosition = saveBP;

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

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

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

// warn if link trait found but not allowed, else create link
if (linkTraitFound) {
action.setStructurePointer(ptr); // used for accessibility
Link link = new Link(action, ipRect);
this.deferredLinks.add(link);
}
@@ -969,6 +996,8 @@ public class IFRenderer extends AbstractPathOrientedRenderer {

String fontName = getInternalFontNameForArea(text);
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
Typeface tf = getTypeface(fontName);
@@ -990,6 +1019,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer {

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

/** {@inheritDoc} */
@@ -1060,10 +1090,10 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
private static final int INITIAL_BUFFER_SIZE = 16;
private int[] dx = new int[INITIAL_BUFFER_SIZE];
private int lastDXPos = 0;
private StringBuffer text = new StringBuffer();
private final StringBuffer text = new StringBuffer();
private int startx, starty;
private int tls, tws;
private boolean combined = false;
private final boolean combined = false;

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

+ 36
- 3
src/java/org/apache/fop/render/intermediate/IFSerializer.java Näytä tiedosto

@@ -27,16 +27,19 @@ import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.w3c.dom.Document;

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

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

import org.apache.fop.accessibility.StructureTree;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.render.PrintRendererConfigurator;
import org.apache.fop.render.RenderingContext;
@@ -60,6 +63,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
implements IFConstants, IFPainter, IFDocumentNavigationHandler {

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

/** Holds the intermediate format state */
private IFState state;
@@ -210,8 +214,23 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
if (id != null) {
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);
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) {
throw new IFException("SAX error in startPageSequence()", e);
}
@@ -392,13 +411,14 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
addAttribute(atts, "width", Integer.toString(rect.width));
addAttribute(atts, "height", Integer.toString(rect.height));
addForeignAttributes(atts);
addStructurePointerAttribute(atts);
handler.element(EL_IMAGE, atts);
} catch (SAXException 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();
if (!foreignAttributes.isEmpty()) {
Iterator iter = foreignAttributes.entrySet().iterator();
@@ -418,6 +438,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
addAttribute(atts, "width", Integer.toString(rect.width));
addAttribute(atts, "height", Integer.toString(rect.height));
addForeignAttributes(atts);
addStructurePointerAttribute(atts);
handler.startElement(EL_IMAGE, atts);
new DOM2SAX(handler).writeDocument(doc, true);
handler.endElement(EL_IMAGE);
@@ -531,6 +552,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
if (dx != null) {
addAttribute(atts, "dx", IFUtil.toString(dx));
}
addStructurePointerAttribute(atts);
handler.startElement(EL_TEXT, atts);
char[] chars = text.toCharArray();
handler.characters(chars, 0, chars.length);
@@ -617,7 +639,8 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
}

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

@@ -625,6 +648,13 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
XMLUtil.addAttribute(atts, localName, value);
}

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

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

private Map incompleteActions = new java.util.HashMap();
@@ -696,6 +726,9 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
AttributesImpl atts = new AttributesImpl();
atts.addAttribute(null, "rect", "rect",
XMLConstants.CDATA, IFUtil.toString(link.getTargetRect()));
if (getUserAgent().isAccessibilityEnabled()) {
addAttribute(atts, "ptr", link.getAction().getStructurePointer());
}
try {
handler.startElement(DocumentNavigationExtensionConstants.LINK, atts);
serializeXMLizable(link.getAction());

+ 17
- 0
src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java Näytä tiedosto

@@ -27,6 +27,7 @@ import org.apache.xmlgraphics.util.XMLizable;
public abstract class AbstractAction implements XMLizable {

private String id;
private String structurePointer;

/**
* Sets an ID to make the action referencable.
@@ -44,6 +45,22 @@ public abstract class AbstractAction implements XMLizable {
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.
* @return true if the action has an ID

+ 9
- 0
src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java Näytä tiedosto

@@ -48,6 +48,8 @@ public class DocumentNavigationHandler extends DefaultHandler

private IFDocumentNavigationHandler navHandler;

private String structurePointer;

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

+ 150
- 0
src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java Näytä tiedosto

@@ -0,0 +1,150 @@
/*
* 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 Näytä tiedosto

@@ -56,6 +56,8 @@ public class PDFContentGenerator {
/** Text generation utility holding the current font status */
protected PDFTextUtil textutil;

private boolean inMarkedContentSequence;
private boolean inArtifactMode;

/**
* Main constructor. Creates a new PDF stream and additional helper classes for text painting
@@ -153,6 +155,40 @@ public class PDFContentGenerator {
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()}.
* @param popState true if the state should also be popped, false if only the PDF command
@@ -166,11 +202,42 @@ public class PDFContentGenerator {
}
}

/** {@inheritDoc} */
/**
* Same as {@link #restoreGraphicsState(boolean)}, with <code>true</code> as
* a parameter.
*/
protected void restoreGraphicsState() {
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. */
protected void beginTextObject() {
if (!textutil.isInTextObject()) {
@@ -178,9 +245,27 @@ public class PDFContentGenerator {
}
}

/**
* 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. */
protected void endTextObject() {
if (textutil.isInTextObject()) {
if (this.inMarkedContentSequence) {
endMarkedContentSequence();
}
textutil.endTextObject();
}
}
@@ -326,5 +411,28 @@ public class PDFContentGenerator {
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 Näytä tiedosto

@@ -28,6 +28,8 @@ import java.awt.geom.Rectangle2D.Double;
import java.io.IOException;
import java.util.Map;

import org.w3c.dom.NodeList;

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

@@ -50,6 +52,7 @@ import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator;
import org.apache.fop.render.intermediate.IFDocumentNavigationHandler;
import org.apache.fop.render.intermediate.IFException;
import org.apache.fop.render.intermediate.IFPainter;
import org.apache.fop.util.XMLUtil;

/**
* {@link IFDocumentHandler} implementation that produces PDF.
@@ -59,6 +62,12 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {
/** logging instance */
private static Log log = LogFactory.getLog(PDFDocumentHandler.class);

private int pageSequenceIndex;

private boolean accessEnabled;

private PDFLogicalStructureHandler logicalStructureHandler;

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

@@ -86,7 +95,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {
/** Used for bookmarks/outlines. */
protected Map pageReferences = new java.util.HashMap();

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

/**
@@ -97,7 +106,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {

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

/** {@inheritDoc} */
@@ -125,11 +134,20 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {
return this.pdfUtil;
}

PDFLogicalStructureHandler getLogicalStructureHandler() {
return logicalStructureHandler;
}

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

this.pdfDoc = null;

pdfResources = null;
@@ -160,7 +177,18 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {

/** {@inheritDoc} */
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} */
@@ -198,13 +226,17 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {
toPointAndScale(cropBox, scaleX, scaleY),
toPointAndScale(bleedBox, scaleX, scaleY),
toPointAndScale(trimBox, scaleX, scaleY));
if (accessEnabled) {
logicalStructureHandler.startPage(currentPage);
}

pdfUtil.generatePageLabel(index, name);

currentPageRef = new PageReference(currentPage, size);
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
AffineTransform basicPageTransform = new AffineTransform(1, 0, 0, -1, 0,
(scaleY * size.height) / 1000f);
@@ -221,7 +253,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {

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

/** {@inheritDoc} */
@@ -231,6 +263,9 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {

/** {@inheritDoc} */
public void endPage() throws IFException {
if (accessEnabled) {
logicalStructureHandler.endPage();
}
try {
this.documentNavigationHandler.commit();
this.pdfDoc.registerObject(generator.getStream());
@@ -267,8 +302,8 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {

static final class PageReference {

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

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

+ 8
- 3
src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java Näytä tiedosto

@@ -47,10 +47,10 @@ import org.apache.fop.render.pdf.PDFDocumentHandler.PageReference;
*/
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.
@@ -111,6 +111,11 @@ public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler
PDFLink pdfLink = getPDFDoc().getFactory().makeLink(
targetRect2D, pdfAction);
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);
}
}

+ 16
- 2
src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java Näytä tiedosto

@@ -35,6 +35,7 @@ import org.apache.fop.pdf.PDFXObject;
import org.apache.fop.render.AbstractImageHandlerGraphics2D;
import org.apache.fop.render.RendererContext;
import org.apache.fop.render.RenderingContext;
import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo;
import org.apache.fop.svg.PDFGraphics2D;

/**
@@ -63,6 +64,9 @@ public class PDFImageHandlerGraphics2D extends AbstractImageHandlerGraphics2D
renderer.currentPage,
renderer.getFontInfo());
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);
return null;
}
@@ -87,7 +91,13 @@ public class PDFImageHandlerGraphics2D extends AbstractImageHandlerGraphics2D
float sy = fheight / (float)imh;

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, true, null);

@@ -115,7 +125,11 @@ public class PDFImageHandlerGraphics2D extends AbstractImageHandlerGraphics2D
imageG2D.getGraphics2DImagePainter().paint(graphics, area);

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


+ 7
- 1
src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java Näytä tiedosto

@@ -34,6 +34,7 @@ import org.apache.fop.pdf.PDFXObject;
import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RendererContext;
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.
@@ -82,7 +83,12 @@ public class PDFImageHandlerRawJPEG implements PDFImageHandler, ImageHandler {
float y = (float)pos.getY() / 1000f;
float w = (float)pos.getWidth() / 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} */

+ 7
- 1
src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java Näytä tiedosto

@@ -34,6 +34,7 @@ import org.apache.fop.pdf.PDFXObject;
import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.RendererContext;
import org.apache.fop.render.RenderingContext;
import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo;

/**
* Image handler implementation which handles RenderedImage instances for PDF output.
@@ -83,7 +84,12 @@ public class PDFImageHandlerRenderedImage implements PDFImageHandler, ImageHandl
float y = (float)pos.getY() / 1000f;
float w = (float)pos.getWidth() / 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} */

+ 12
- 3
src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java Näytä tiedosto

@@ -40,6 +40,7 @@ import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.image.loader.batik.BatikImageFlavors;
import org.apache.fop.render.ImageHandler;
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.PDFBridgeContext;
import org.apache.fop.svg.PDFGraphics2D;
@@ -101,8 +102,8 @@ public class PDFImageHandlerSVG implements ImageHandler {
float w = (float)ctx.getDocumentSize().getWidth() * 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
AffineTransform scaling = new AffineTransform(
@@ -121,6 +122,10 @@ public class PDFImageHandlerSVG implements ImageHandler {
*/
generator.comment("SVG setup");
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, true);

@@ -168,7 +173,11 @@ public class PDFImageHandlerSVG implements ImageHandler {
eventProducer.svgRenderingError(this, e, image.getInfo().getOriginalURI());
}
generator.getState().restore();
generator.restoreGraphicsState();
if (context.getUserAgent().isAccessibilityEnabled()) {
generator.restoreGraphicsStateAccess();
} else {
generator.restoreGraphicsState();
}
generator.comment("SVG end");
}


+ 299
- 0
src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java Näytä tiedosto

@@ -0,0 +1,299 @@
/*
* 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 Näytä tiedosto

@@ -29,9 +29,6 @@ import java.io.IOException;

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.FontInfo;
import org.apache.fop.fonts.FontTriplet;
@@ -47,6 +44,7 @@ import org.apache.fop.render.intermediate.AbstractIFPainter;
import org.apache.fop.render.intermediate.IFContext;
import org.apache.fop.render.intermediate.IFException;
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.RuleStyle;
import org.apache.fop.util.CharUtilities;
@@ -56,26 +54,33 @@ import org.apache.fop.util.CharUtilities;
*/
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 */
protected PDFContentGenerator generator;

private PDFBorderPainter borderPainter;
private final PDFBorderPainter borderPainter;

private boolean accessEnabled;

private MarkedContentInfo imageMCI;

private PDFLogicalStructureHandler logicalStructureHandler;

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

/** {@inheritDoc} */
@@ -122,22 +127,36 @@ public class PDFPainter extends AbstractIFPainter {
}

/** {@inheritDoc} */
public void drawImage(String uri, Rectangle rect) throws IFException {
public void drawImage(String uri, Rectangle rect)
throws IFException {
PDFXObject xobject = getPDFDoc().getXObject(uri);
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} */
protected RenderingContext createRenderingContext() {
PDFRenderingContext pdfContext = new PDFRenderingContext(
getUserAgent(), generator, this.documentHandler.currentPage, getFontInfo());
pdfContext.setMarkedContentInfo(imageMCI);
return pdfContext;
}

@@ -158,11 +177,31 @@ public class PDFPainter extends AbstractIFPainter {
+ " cm " + xobj.getName() + " Do\n");
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} */
public void drawImage(Document doc, Rectangle rect) throws IFException {
if (accessEnabled) {
String ptr = getContext().getStructurePointer();
prepareImageMCID(ptr);
}
drawImageUsingDocument(doc, rect);

flushPDFDoc();
}

@@ -253,10 +292,22 @@ public class PDFPainter extends AbstractIFPainter {
}

/** {@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 {
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(
state.getFontFamily(), state.getFontStyle(), state.getFontWeight());
//TODO Ignored: state.getFontVariant()
@@ -277,7 +328,7 @@ public class PDFPainter extends AbstractIFPainter {
PDFTextUtil textutil = generator.getTextUtil();
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));
int l = text.length();

+ 87
- 8
src/java/org/apache/fop/render/pdf/PDFRenderer.java Näytä tiedosto

@@ -31,8 +31,12 @@ import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
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.ImageFlavor;
import org.apache.xmlgraphics.image.loader.ImageInfo;
@@ -61,6 +65,7 @@ import org.apache.fop.area.inline.InlineParent;
import org.apache.fop.area.inline.Leader;
import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.area.inline.Viewport;
import org.apache.fop.area.inline.WordArea;
import org.apache.fop.datatypes.URISpecification;
import org.apache.fop.events.ResourceEventProducer;
@@ -91,9 +96,11 @@ import org.apache.fop.pdf.PDFXObject;
import org.apache.fop.render.AbstractPathOrientedRenderer;
import org.apache.fop.render.Graphics2DAdapter;
import org.apache.fop.render.RendererContext;
import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo;
import org.apache.fop.traits.RuleStyle;
import org.apache.fop.util.AbstractPaintingState;
import org.apache.fop.util.CharUtilities;
import org.apache.fop.util.XMLUtil;
import org.apache.fop.util.AbstractPaintingState.AbstractData;

/**
@@ -127,7 +134,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
* this is used for prepared pages that cannot be immediately
* rendered
*/
protected Map pages = null;
private Map pages;

/**
* Maps unique PageViewport key to PDF page reference
@@ -193,6 +200,14 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
/** Image handler registry */
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
@@ -204,6 +219,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
public void setUserAgent(FOUserAgent agent) {
super.setUserAgent(agent);
this.pdfUtil = new PDFRenderingUtil(getUserAgent());
accessEnabled = agent.isAccessibilityEnabled();
}

PDFRenderingUtil getPDFUtil() {
@@ -225,6 +241,10 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
}
ostream = stream;
this.pdfDoc = pdfUtil.setupPDFDocument(stream);
if (accessEnabled) {
pdfDoc.getRoot().makeTagged();
logicalStructureHandler = new PDFLogicalStructureHandler(pdfDoc);
}
}

/**
@@ -274,8 +294,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
* {@inheritDoc}
*/
public boolean supportsOutOfOrder() {
//return false;
return true;
return !accessEnabled;
}

/**
@@ -394,17 +413,24 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
info.setTitle(str);
}
}
Locale language = null;
if (pageSequence.getLanguage() != null) {
String lang = pageSequence.getLanguage();
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) {
//Only set if not set already (first non-null is used)
//Note: No checking is performed whether the values are valid!
pdfDoc.getRoot().setLanguage(langCode);
pdfDoc.getRoot().setLanguage(XMLUtil.toRFC3066(language));
}
}
pdfUtil.generateDefaultXMPMetadata();
if (accessEnabled) {
NodeList nodes = getUserAgent().getStructureTree().getPageSequence(pageSequenceIndex++);
logicalStructureHandler.processStructureTree(nodes, language);
}
}

/**
@@ -457,6 +483,10 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
}
currentPageRef = currentPage.referencePDF();

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

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

@@ -474,6 +504,10 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf

super.renderPage(page);

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

this.pdfDoc.registerObject(generator.getStream());
currentPage.setContents(generator.getStream());
PDFAnnotList annots = currentPage.getAnnotations();
@@ -903,11 +937,22 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
+ pdfDoc.getProfile());
} else if (action != null) {
PDFLink pdfLink = factory.makeLink(ipRect, action);
if (accessEnabled) {
String ptr = (String) ip.getTrait(Trait.PTR);
logicalStructureHandler.addLinkContentItem(pdfLink, ptr);
}
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) {
Typeface tf = (Typeface) fontInfo.getFonts().get(fontName);
if (tf instanceof LazyFont) {
@@ -922,7 +967,16 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
Color ct = (Color) text.getTrait(Trait.COLOR);
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);
int size = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue();
@@ -1178,13 +1232,22 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
* @param xobj the image XObject
*/
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 "
+ format(-h) + " "
+ format(currentIPPosition / 1000f + x) + " "
+ format(currentBPPosition / 1000f + h + y)
+ " cm\n" + xobj.getName() + " Do\n");
restoreGraphicsState();
if (accessEnabled) {
generator.restoreGraphicsStateAccess();
} else {
restoreGraphicsState();
}
}

/** {@inheritDoc} */
@@ -1205,6 +1268,18 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
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.
* This renders a leader area which is an area with a rule.
@@ -1272,5 +1347,9 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf
public void setEncryptionParams(PDFEncryptionParams encryptionParams) {
this.pdfUtil.setEncryptionParams(encryptionParams);
}

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


+ 9
- 0
src/java/org/apache/fop/render/pdf/PDFRenderingContext.java Näytä tiedosto

@@ -25,6 +25,7 @@ import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.pdf.PDFPage;
import org.apache.fop.render.AbstractRenderingContext;
import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo;

/**
* Rendering context for PDF production.
@@ -34,6 +35,7 @@ public class PDFRenderingContext extends AbstractRenderingContext {
private PDFContentGenerator generator;
private FontInfo fontInfo;
private PDFPage page;
private MarkedContentInfo mci;

/**
* Main constructor.
@@ -79,4 +81,11 @@ public class PDFRenderingContext extends AbstractRenderingContext {
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 Näytä tiedosto

@@ -37,6 +37,7 @@ import org.apache.xmlgraphics.xmp.Metadata;
import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter;
import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;

import org.apache.fop.accessibility.Accessibility;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.extensions.xmp.XMPMetadata;
import org.apache.fop.pdf.PDFAMode;
@@ -109,7 +110,7 @@ class PDFRenderingUtil implements PDFConfigurationConstants {

private void initialize() {
PDFEncryptionParams params
= (PDFEncryptionParams)userAgent.getRendererOptions().get(ENCRYPTION_PARAMS);
= (PDFEncryptionParams)userAgent.getRendererOptions().get(ENCRYPTION_PARAMS);
if (params != null) {
this.encryptionParams = params; //overwrite if available
}
@@ -161,6 +162,10 @@ class PDFRenderingUtil implements PDFConfigurationConstants {
if (s != null) {
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);
if (s != null) {
this.pdfXMode = PDFXMode.valueOf(s);

+ 2
- 1
src/java/org/apache/fop/render/txt/TXTRenderer.java Näytä tiedosto

@@ -28,6 +28,8 @@ import java.io.OutputStream;
import java.util.List;
import java.util.Map;

import org.apache.xmlgraphics.util.UnitConv;

import org.apache.fop.apps.FOPException;
import org.apache.fop.area.Area;
import org.apache.fop.area.CTM;
@@ -37,7 +39,6 @@ import org.apache.fop.area.inline.TextArea;
import org.apache.fop.render.AbstractPathOrientedRenderer;
import org.apache.fop.render.txt.border.AbstractBorderElement;
import org.apache.fop.render.txt.border.BorderManager;
import org.apache.xmlgraphics.util.UnitConv;

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

+ 19
- 1
src/java/org/apache/fop/render/xml/XMLRenderer.java Näytä tiedosto

@@ -34,7 +34,8 @@ import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;

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

import org.apache.xmlgraphics.util.QName;
@@ -86,6 +87,7 @@ import org.apache.fop.render.Renderer;
import org.apache.fop.render.RendererContext;
import org.apache.fop.render.XMLHandler;
import org.apache.fop.util.ColorUtil;
import org.apache.fop.util.DOM2SAX;

/**
* Renderer that renders areas to XML for debugging purposes.
@@ -105,6 +107,8 @@ public class XMLRenderer extends AbstractXMLRenderer {
/** If not null, the XMLRenderer will mimic another renderer by using its font setup. */
protected Renderer mimic;

private int pageSequenceIndex;

/**
* Creates a new XML renderer.
*/
@@ -440,6 +444,20 @@ public class XMLRenderer extends AbstractXMLRenderer {
}
transferForeignObjects(pageSequence);
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());
LineArea seqTitle = pageSequence.getTitle();
if (seqTitle != null) {

+ 9
- 1
src/java/org/apache/fop/util/DOM2SAX.java Näytä tiedosto

@@ -26,7 +26,6 @@ import java.util.Stack;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
@@ -78,6 +77,15 @@ public class DOM2SAX {
}
}

/**
* 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
* only if the prefix is unknown or it is mapped to a different URI.

+ 160
- 0
src/java/org/apache/fop/util/TransformerDefaultHandler.java Näytä tiedosto

@@ -0,0 +1,160 @@
/*
* 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 Näytä tiedosto

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

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

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
@@ -170,4 +171,39 @@ public class XMLUtil implements XMLConstants {
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 Näytä tiedosto

@@ -324,8 +324,9 @@ public class SVGPainter extends AbstractIFPainter implements SVGConstants {
}

/** {@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 {
establish(MODE_TEXT);
AttributesImpl atts = new AttributesImpl();

+ 3
- 0
status.xml Näytä tiedosto

@@ -58,6 +58,9 @@
documents. Example: the fix of marks layering will be such a case when it's done.
-->
<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">
Added support for encoding CMYK bitmap images (IOCA FS45) and TIFF images as embedded objects.
</action>

+ 52
- 0
test/accessibility/README Näytä tiedosto

@@ -0,0 +1,52 @@
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 Näytä tiedosto

@@ -0,0 +1,34 @@
<?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 Näytä tiedosto

@@ -0,0 +1,36 @@
<?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 Näytä tiedosto

@@ -0,0 +1,34 @@
<?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 Näytä tiedosto

@@ -0,0 +1,36 @@
<?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 Näytä tiedosto

@@ -0,0 +1,34 @@
<?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 Näytä tiedosto

@@ -0,0 +1,36 @@
<?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 Näytä tiedosto

@@ -0,0 +1,205 @@
<?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 Näytä tiedosto

@@ -0,0 +1,23 @@
<?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 Näytä tiedosto

@@ -0,0 +1,24 @@
<?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 Näytä tiedosto

@@ -0,0 +1,35 @@
<?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 Näytä tiedosto

@@ -0,0 +1,35 @@
<?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 Näytä tiedosto

@@ -0,0 +1,45 @@
<?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 Näytä tiedosto

@@ -0,0 +1,35 @@
<?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 Näytä tiedosto


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

Loading…
Peruuta
Tallenna