]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Bugzilla #54037: Issue a warning when accessibility is enabled for PDF output and...
authorVincent Hennebert <vhennebert@apache.org>
Mon, 22 Oct 2012 14:13:42 +0000 (14:13 +0000)
committerVincent Hennebert <vhennebert@apache.org>
Mon, 22 Oct 2012 14:13:42 +0000 (14:13 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1400890 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/fop/area/Block.java
src/java/org/apache/fop/fo/FONode.java
src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
src/java/org/apache/fop/render/intermediate/IFContext.java
src/java/org/apache/fop/render/intermediate/IFRenderer.java
src/java/org/apache/fop/render/pdf/PDFEventProducer.java
src/java/org/apache/fop/render/pdf/PDFEventProducer.xml
src/java/org/apache/fop/render/pdf/PDFPainter.java
status.xml

index c6e31f71d2053163a59c7e2b2196212aefd7c878..337d1fb377203e1c74805c145c41b513fe13ecad 100644 (file)
@@ -19,6 +19,8 @@
 
 package org.apache.fop.area;
 
+import java.util.Locale;
+
 
 // block areas hold either more block areas or line
 // areas can also be used as a block spacer
@@ -63,8 +65,9 @@ public class Block extends BlockParent {
     /** if true, allow BPD update */
     protected transient boolean allowBPDUpdate = true;
 
-    // a block with may contain the dominant styling info in
-    // terms of most lines or blocks with info
+    private Locale locale;
+
+    private String location;
 
     /**
      * Add the block to this block area.
@@ -140,5 +143,37 @@ public class Block extends BlockParent {
         return (endIndent != null ? endIndent : 0);
     }
 
+    /**
+     * Sets the language information coming from the FO that generated this area.
+     */
+    public void setLocale(Locale locale) {
+        this.locale = locale;
+    }
+
+    /**
+     * Returns the language information for the FO that generated this area.
+     */
+    public Locale getLocale() {
+        return locale;
+    }
+
+    /**
+     * Sets the location in the source XML of the FO that generated this area.
+     *
+     * @location the line and column location
+     */
+    public void setLocation(String location) {
+        this.location = location;
+    }
+
+    /**
+     * Returns the location in the source XML of the FO that generated this area.
+     *
+     * @return the line and column location, {@code null} if that information is not available
+     */
+    public String getLocation() {
+        return location;
+    }
+
 }
 
index 707dae91edf2e2333889667a8842a410fdcff409..2fae054fede9e797619a1312e1301abd1d8888ec 100644 (file)
@@ -565,7 +565,7 @@ public abstract class FONode implements Cloneable {
     /**
      * Helper function to return "not supported child" exceptions. Note that the child is valid, just not
      * supported yet by FOP.
-     * 
+     *
      * @param loc org.xml.sax.Locator object of the error (*not* parent node)
      * @param nsURI namespace URI of incoming invalid node
      * @param lName local name (i.e., no prefix) of incoming node
@@ -663,7 +663,7 @@ public abstract class FONode implements Cloneable {
         if (loc == null) {
             return "Unknown location";
         } else {
-            return loc.getLineNumber() + "/" + loc.getColumnNumber();
+            return loc.getLineNumber() + ":" + loc.getColumnNumber();
         }
     }
 
index f62d7f946550cb33d783b5b92b87c8dbbfffbf94..1420d1b98d0124682782c79934f6c82e33bd9d19 100644 (file)
@@ -31,6 +31,7 @@ import org.apache.fop.area.Area;
 import org.apache.fop.area.Block;
 import org.apache.fop.area.LineArea;
 import org.apache.fop.datatypes.Length;
+import org.apache.fop.fo.FONode;
 import org.apache.fop.fo.properties.KeepProperty;
 import org.apache.fop.fonts.Font;
 import org.apache.fop.fonts.FontInfo;
@@ -381,6 +382,8 @@ public class BlockLayoutManager extends BlockStackingLayoutManager implements Co
                     startIndent, endIndent,
                     this);
 
+            curBlockArea.setLocale(getBlockFO().getCommonHyphenation().getLocale());
+            curBlockArea.setLocation(FONode.getLocatorString(getBlockFO().getLocator()));
             setCurrentArea(curBlockArea); // ??? for generic operations
         }
         return curBlockArea;
index 681b996e452607c6474314d9f5c89032e6265416..62bbbe9c5c8b5cca8a4ffec078f0ca8cbb58c6f4 100644 (file)
@@ -51,6 +51,8 @@ public class IFContext {
 
     private String id = "";
 
+    private String location;
+
     /**
      * Main constructor.
      * @param ua the user agent
@@ -179,4 +181,23 @@ public class IFContext {
         return id;
     }
 
+    /**
+     * Sets the location of the object enclosing the current content.
+     *
+     * @location the line and column location of the object in the source FO file
+     */
+    public void setLocation(String location) {
+        this.location = location;
+    }
+
+    /**
+     * Returns the location of the object enclosing the current content.
+     *
+     * @return the line and column location of the object in the source FO file,
+     * {@code null} if that information is not available
+     */
+    public String getLocation() {
+        return location;
+    }
+
 }
index 771929809f30846d8bc71e5a1999b73333d155f7..fe3bbf72c4652859546c5bfa42ca6431d76ba7d2 100644 (file)
@@ -965,7 +965,14 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
         }
         saveBlockPosIfTargetable(block);
         pushdID(block);
+        IFContext context = documentHandler.getContext();
+        Locale oldLocale = context.getLanguage();
+        context.setLanguage(block.getLocale());
+        String oldLocation = context.getLocation();
+        context.setLocation(block.getLocation());
         super.renderBlock(block);
+        context.setLocation(oldLocation);
+        context.setLanguage(oldLocale);
         popID(block);
     }
 
index 4b825386747bfa27b76b36dd72de2105a2949fa3..addf216661df889ea55ed19c6a23af86ec8ef7ab 100644 (file)
@@ -74,4 +74,13 @@ public interface PDFEventProducer extends EventProducer {
      * @event.severity WARN
      */
     void incorrectEncryptionLength(Object source, int originalValue, int correctedValue);
+
+    /**
+     * The language of a piece of text is unknown.
+     *
+     * @param source the event source
+     * @param location location in the source FO file, if any
+     */
+    void unknownLanguage(Object source, String location);
+
 }
index bf930ea344d551a405e2ad4e6f0427e3ed902a4f..b954e61d5a3d36607597f2de40b0798c48eee35b 100644 (file)
@@ -3,4 +3,5 @@
   <message key="nonFullyResolvedLinkTargets">{count} link target{count,equals,1,,s} could not be fully resolved and now point{count,equals,1,,s} to the top of the page or {count,equals,1,is,are} dysfunctional.</message>
   <message key="nonStandardStructureType">‘{type}’ is not a standard structure type defined by the PDF Reference. Falling back to ‘{fallback}’.</message>
   <message key="incorrectEncryptionLength">Encryption length must be a multiple of 8 between 40 and 128. Setting encryption length to {correctedValue} instead of {originalValue}.</message>
+  <message key="unknownLanguage">A piece of text or an image’s alternate text is missing language information [(See position {location})|(No context info available)]</message>
 </catalogue>
index 0160ffc1c5f3d79b8a8c412f55537f1f3b7e9532..fa1c5031882e625921846bf9415a8bd6a8658261 100644 (file)
@@ -26,6 +26,9 @@ import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.geom.AffineTransform;
 import java.io.IOException;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
 
 import org.w3c.dom.Document;
 
@@ -40,6 +43,7 @@ import org.apache.fop.pdf.PDFTextUtil;
 import org.apache.fop.pdf.PDFXObject;
 import org.apache.fop.render.RenderingContext;
 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.intermediate.IFUtil;
@@ -65,6 +69,41 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> {
 
     private PDFLogicalStructureHandler logicalStructureHandler;
 
+    private final LanguageAvailabilityChecker languageAvailabilityChecker;
+
+    private static class LanguageAvailabilityChecker {
+
+        private final IFContext context;
+
+        private final Set<String> reportedLocations = new HashSet<String>();
+
+        LanguageAvailabilityChecker(IFContext context) {
+            this.context = context;
+        }
+
+        private void checkLanguageAvailability(String text) {
+            Locale locale = context.getLanguage();
+            if (locale == null && containsLettersOrDigits(text)) {
+                String location = context.getLocation();
+                if (!reportedLocations.contains(location)) {
+                    PDFEventProducer.Provider.get(context.getUserAgent().getEventBroadcaster())
+                            .unknownLanguage(this, location);
+                    reportedLocations.add(location);
+                }
+            }
+        }
+
+        private boolean containsLettersOrDigits(String text) {
+            for (int i = 0; i < text.length(); i++) {
+                if (Character.isLetterOrDigit(text.charAt(i))) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+    }
+
     /**
      * Default constructor.
      * @param documentHandler the parent document handler
@@ -78,6 +117,9 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> {
         this.borderPainter = new PDFBorderPainter(this.generator);
         this.state = IFState.create();
         accessEnabled = this.getUserAgent().isAccessibilityEnabled();
+        languageAvailabilityChecker = accessEnabled
+                ? new LanguageAvailabilityChecker(documentHandler.getContext())
+                : null;
     }
 
     /** {@inheritDoc} */
@@ -130,6 +172,9 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> {
 
     private void prepareImageMCID(PDFStructElem structElem) {
         imageMCI = logicalStructureHandler.addImageContentItem(structElem);
+        if (structElem != null) {
+            languageAvailabilityChecker.checkLanguageAvailability((String) structElem.get("Alt"));
+        }
     }
 
     /** {@inheritDoc} */
@@ -274,6 +319,7 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> {
             throws IFException {
         if (accessEnabled) {
             PDFStructElem structElem = (PDFStructElem) getContext().getStructureTreeElement();
+            languageAvailabilityChecker.checkLanguageAvailability(text);
             MarkedContentInfo mci = logicalStructureHandler.addTextContentItem(structElem);
             if (generator.getTextUtil().isInTextObject()) {
                 generator.separateTextElements(mci.tag, mci.mcid);
index dcda6901c168b37a9227fe2575119ee4cc099a36..5a61dff21a692d08a7835c2a9259c36951242d42 100644 (file)
       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="VH" type="add" fixes-bug="54037">
+        PDF output: Issue a warning when accessibility is enabled and language information is 
+        missing.
+      </action>
       <action context="Renderers" dev="VH" type="add" fixes-bug="53980">
         PDF accessibility: Store language information coming from fo:block or fo:character in the 
         structure tree.