Author: jeremias
Date: Fri Apr 17 12:10:07 2009
New Revision: 765965
URL: http://svn.apache.org/viewvc?rev=765965&view=rev
Log:
Added support for adding natural language information on page-sequence and
document level to a tagged PDF.
The document-level language is assumed to be the language of the first
page-sequence.
Added:
xmlgraphics/fop/branches/Temp_Accessibility/test/java/org/apache/fop/util/XMLUtilTestCase.java
(with props)
Modified:
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/area/AreaTreeParser.java
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/pdf/PDFStructElem.java
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFContext.java
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFParser.java
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFRenderer.java
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFSerializer.java
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/util/XMLUtil.java
xmlgraphics/fop/branches/Temp_Accessibility/test/layoutengine/standard-testcases/page-sequence_language.xml
Modified:
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/area/AreaTreeParser.java
URL:
http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/area/AreaTreeParser.java?rev=765965&r1=765964&r2=765965&view=diff
==============================================================================
---
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/area/AreaTreeParser.java
(original)
+++
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/area/AreaTreeParser.java
Fri Apr 17 12:10:07 2009
@@ -85,6 +85,7 @@
import org.apache.fop.util.ContentHandlerFactoryRegistry;
import org.apache.fop.util.ConversionUtils;
import org.apache.fop.util.DefaultErrorListener;
+import org.apache.fop.util.XMLConstants;
import org.apache.fop.util.XMLUtil;
/**
@@ -1134,7 +1135,7 @@
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));
Modified:
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/pdf/PDFStructElem.java
URL:
http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/pdf/PDFStructElem.java?rev=765965&r1=765964&r2=765965&view=diff
==============================================================================
---
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/pdf/PDFStructElem.java
(original)
+++
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/pdf/PDFStructElem.java
Fri Apr 17 12:10:07 2009
@@ -19,6 +19,10 @@
package org.apache.fop.pdf;
+import java.util.Locale;
+
+import org.apache.fop.util.XMLUtil;
+
/**
* Class representing a PDF Structure Element.
*/
@@ -144,4 +148,29 @@
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")
+ */
+ public void setLanguage(String language) {
+ put("Lang", language);
+ }
+
+ /**
+ * Sets the language of this structure element.
+ * @param language the language
+ */
+ public void setLanguage(Locale language) {
+ setLanguage(XMLUtil.toRFC3066(language));
+ }
+
+ /**
+ * Returns the language of this structure element.
+ * @return the language (or null if no language was specified)
+ */
+ public String getLanguage() {
+ return (String)get("Lang");
+ }
}
Modified:
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFContext.java
URL:
http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFContext.java?rev=765965&r1=765964&r2=765965&view=diff
==============================================================================
---
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFContext.java
(original)
+++
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFContext.java
Fri Apr 17 12:10:07 2009
@@ -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,8 @@
/** foreign attributes: Map<QName, Object> */
private Map foreignAttributes = Collections.EMPTY_MAP;
+ private Locale language;
+
private String structurePointer;
/**
@@ -111,6 +114,22 @@
}
/**
+ * 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
Modified:
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFParser.java
URL:
http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFParser.java?rev=765965&r1=765964&r2=765965&view=diff
==============================================================================
---
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFParser.java
(original)
+++
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFParser.java
Fri Apr 17 12:10:07 2009
@@ -25,6 +25,7 @@
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;
@@ -73,6 +74,15 @@
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
@@ -357,6 +367,11 @@
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);
@@ -365,6 +380,7 @@
public void endElement() throws IFException {
documentHandler.endPageSequence();
+ documentHandler.getContext().setLanguage(null);
}
}
@@ -643,11 +659,7 @@
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) {
Modified:
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFRenderer.java
URL:
http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFRenderer.java?rev=765965&r1=765964&r2=765965&view=diff
==============================================================================
---
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFRenderer.java
(original)
+++
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFRenderer.java
Fri Apr 17 12:10:07 2009
@@ -30,6 +30,7 @@
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 @@
try {
if (this.inPageSequence) {
documentHandler.endPageSequence();
+ documentHandler.getContext().setLanguage(null);
} else {
if (this.documentMetadata == null) {
this.documentMetadata = createDefaultDocumentMetadata();
@@ -502,6 +504,7 @@
this.inPageSequence = true;
}
establishForeignAttributes(pageSequence.getForeignAttributes());
+ documentHandler.getContext().setLanguage(toLocale(pageSequence));
documentHandler.startPageSequence(null);
resetForeignAttributes();
processExtensionAttachments(pageSequence);
@@ -510,6 +513,17 @@
}
}
+ 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);
Modified:
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFSerializer.java
URL:
http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFSerializer.java?rev=765965&r1=765964&r2=765965&view=diff
==============================================================================
---
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFSerializer.java
(original)
+++
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFSerializer.java
Fri Apr 17 12:10:07 2009
@@ -29,7 +29,9 @@
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
+import java.util.Stack;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
@@ -267,6 +269,7 @@
if (id != null) {
atts.addAttribute(XML_NAMESPACE, "id", "xml:id",
XMLUtil.CDATA, id);
}
+ applyLanguage(atts);
addForeignAttributes(atts);
handler.startElement(EL_PAGE_SEQUENCE, atts);
if (this.getUserAgent().isAccessibilityEnabled()) {
@@ -301,6 +304,7 @@
public void endPageSequence() throws IFException {
try {
handler.endElement(EL_PAGE_SEQUENCE);
+ popLanguage();
} catch (SAXException e) {
throw new IFException("SAX error in endPageSequence()", e);
}
@@ -831,4 +835,25 @@
}
}
+ private Stack languageStack = new Stack();
+
+ private void applyLanguage(AttributesImpl atts) {
+ Locale lang = getContext().getLanguage();
+ if (lang != null) {
+ if (languageStack.isEmpty() || !languageStack.peek().equals(lang))
{
+ atts.addAttribute(XML_NAMESPACE, "lang", "xml:lang",
XMLUtil.CDATA,
+ XMLUtil.toRFC3066(lang));
+ }
+ languageStack.push(lang);
+ } else {
+ assert languageStack.isEmpty();
+ }
+ }
+
+ private void popLanguage() {
+ if (!languageStack.isEmpty()) {
+ languageStack.pop();
+ }
+ }
+
}
Modified:
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java
URL:
http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java?rev=765965&r1=765964&r2=765965&view=diff
==============================================================================
---
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java
(original)
+++
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java
Fri Apr 17 12:10:07 2009
@@ -70,6 +70,7 @@
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;
/**
* {...@code IFDocumentHandler} implementation that produces PDF.
@@ -82,7 +83,7 @@
/** the following variables are used for accessibility */
private int pageSequenceCounter;
private DocumentBuilder parser = null;
- private Document doc = null;
+ private Document reducedFOTree = null;
private Map structElemType = new HashMap();
private boolean accessEnabled = false;
private int parentTreeKey = -1;
@@ -226,10 +227,6 @@
this.pdfDoc.addTrailerObject(structElemDocument);
structTreeRoot.addKid(structElemDocument);
- //TODO: make document language variable, see note on wiki page
PDF Accessibility
- //TODO: and follow-up emails on fop-dev
- this.pdfDoc.getRoot().setLanguage("en");
-
parentTree = new PDFParentTree();
pageSequenceCounter = 0;
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
@@ -271,7 +268,7 @@
getStructTreeRoot().addParentTree(parentTree);
pdfDoc.outputTrailer(this.outputStream);
parser = null;
- doc = null;
+ reducedFOTree = null;
structElemType = null;
parentTree = null;
structTreeMap = null;
@@ -298,17 +295,31 @@
/** {...@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 (getUserAgent().isAccessibilityEnabled()) {
try {
- if (doc == null) {
- doc = parser.parse(
+ if (this.pdfDoc.getRoot().getLanguage() == null) {
+ //No language has been set on the first page-sequence, so
fall back to "en".
+ this.pdfDoc.getRoot().setLanguage("en");
+ }
+
+ if (reducedFOTree == null) {
+ reducedFOTree = parser.parse(
new
ByteArrayInputStream(this.getUserAgent().getReducedFOTree()));
}
PDFStructElem parent =
(PDFStructElem)getStructTreeRoot().getFirstChild();
PDFStructElem structElemPart = new PDFStructElem(parent,
FOToPDFRoleMap.mapFormattingObject("page-sequence",
parent));
+ if (getContext().getLanguage() != null) {
+ structElemPart.setLanguage(getContext().getLanguage());
+ }
this.pdfDoc.assignObjectNumber(structElemPart);
this.pdfDoc.addTrailerObject(structElemPart);
parent.addKid(structElemPart);
@@ -320,7 +331,7 @@
"http://www.w3.org/1999/XSL/Format");
xpath.setNamespaceContext(namespaceContext);
- NodeList nodes = (NodeList) xpath.evaluate(xpathExpr, doc,
+ NodeList nodes = (NodeList) xpath.evaluate(xpathExpr,
reducedFOTree,
XPathConstants.NODESET);
for (int i = 0, n = nodes.getLength(); i < n; i++) {
Modified:
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/util/XMLUtil.java
URL:
http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/util/XMLUtil.java?rev=765965&r1=765964&r2=765965&view=diff
==============================================================================
---
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/util/XMLUtil.java
(original)
+++
xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/util/XMLUtil.java
Fri Apr 17 12:10:07 2009
@@ -21,6 +21,7 @@
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 @@
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]);
+ }
+ }
+
}
Added:
xmlgraphics/fop/branches/Temp_Accessibility/test/java/org/apache/fop/util/XMLUtilTestCase.java
URL:
http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/test/java/org/apache/fop/util/XMLUtilTestCase.java?rev=765965&view=auto
==============================================================================
---
xmlgraphics/fop/branches/Temp_Accessibility/test/java/org/apache/fop/util/XMLUtilTestCase.java
(added)
+++
xmlgraphics/fop/branches/Temp_Accessibility/test/java/org/apache/fop/util/XMLUtilTestCase.java
Fri Apr 17 12:10:07 2009
@@ -0,0 +1,45 @@
+/*
+ * 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 java.util.Locale;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests {...@link XMLUtil}.
+ */
+public class XMLUtilTestCase extends TestCase {
+
+ public void testLocaleToRFC3066() throws Exception {
+ assertNull(XMLUtil.toRFC3066(null));
+ assertEquals("en", XMLUtil.toRFC3066(new Locale("en")));
+ assertEquals("en-US", XMLUtil.toRFC3066(new Locale("en", "US")));
+ assertEquals("en-US", XMLUtil.toRFC3066(new Locale("EN", "us")));
+ }
+
+ public void testRFC3066ToLocale() throws Exception {
+ assertNull(XMLUtil.convertRFC3066ToLocale(null));
+ assertNull(XMLUtil.convertRFC3066ToLocale(""));
+ assertEquals(new Locale("en"), XMLUtil.convertRFC3066ToLocale("en"));
+ assertEquals(new Locale("en", "US"),
XMLUtil.convertRFC3066ToLocale("en-US"));
+ assertEquals(new Locale("en", "US"),
XMLUtil.convertRFC3066ToLocale("EN-us"));
+ }
+}
Propchange:
xmlgraphics/fop/branches/Temp_Accessibility/test/java/org/apache/fop/util/XMLUtilTestCase.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
xmlgraphics/fop/branches/Temp_Accessibility/test/java/org/apache/fop/util/XMLUtilTestCase.java
------------------------------------------------------------------------------
svn:keywords = Id
Modified:
xmlgraphics/fop/branches/Temp_Accessibility/test/layoutengine/standard-testcases/page-sequence_language.xml
URL:
http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/test/layoutengine/standard-testcases/page-sequence_language.xml?rev=765965&r1=765964&r2=765965&view=diff
==============================================================================
---
xmlgraphics/fop/branches/Temp_Accessibility/test/layoutengine/standard-testcases/page-sequence_language.xml
(original)
+++
xmlgraphics/fop/branches/Temp_Accessibility/test/layoutengine/standard-testcases/page-sequence_language.xml
Fri Apr 17 12:10:07 2009
@@ -65,4 +65,10 @@
<eval expected="de" xpath="/areaTree/pageSequence[4]/@language"/>
<true xpath="not(boolean(/areaTree/pageSequence[4]/@country))"/>
</checks>
+ <if-checks xmlns:if="http://xmlgraphics.apache.org/fop/intermediate">
+ <eval expected="en" xpath="//if:page-sequence[1]/@xml:lang"/>
+ <eval expected="en-US" xpath="//if:page-sequence[2]/@xml:lang"/>
+ <eval expected="de-CH" xpath="//if:page-sequence[3]/@xml:lang"/>
+ <eval expected="de" xpath="//if:page-sequence[4]/@xml:lang"/>
+ </if-checks>
</testcase>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]