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]

Reply via email to