aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop
diff options
context:
space:
mode:
authorVincent Hennebert <vhennebert@apache.org>2012-10-22 14:13:42 +0000
committerVincent Hennebert <vhennebert@apache.org>2012-10-22 14:13:42 +0000
commiteb45e0a46510827c4c58a7358d1c674a89c0becb (patch)
tree63ac5ac516249936b8464dd0e2129700c6448feb /src/java/org/apache/fop
parent1a5394a6bec2b67910062a8e45c92a473aec8627 (diff)
downloadxmlgraphics-fop-eb45e0a46510827c4c58a7358d1c674a89c0becb.tar.gz
xmlgraphics-fop-eb45e0a46510827c4c58a7358d1c674a89c0becb.zip
Bugzilla #54037: Issue a warning when accessibility is enabled for PDF output and language information is missing
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1400890 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop')
-rw-r--r--src/java/org/apache/fop/area/Block.java39
-rw-r--r--src/java/org/apache/fop/fo/FONode.java4
-rw-r--r--src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java3
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFContext.java21
-rw-r--r--src/java/org/apache/fop/render/intermediate/IFRenderer.java7
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFEventProducer.java9
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFEventProducer.xml1
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFPainter.java46
8 files changed, 126 insertions, 4 deletions
diff --git a/src/java/org/apache/fop/area/Block.java b/src/java/org/apache/fop/area/Block.java
index c6e31f71d..337d1fb37 100644
--- a/src/java/org/apache/fop/area/Block.java
+++ b/src/java/org/apache/fop/area/Block.java
@@ -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;
+ }
+
}
diff --git a/src/java/org/apache/fop/fo/FONode.java b/src/java/org/apache/fop/fo/FONode.java
index 707dae91e..2fae054fe 100644
--- a/src/java/org/apache/fop/fo/FONode.java
+++ b/src/java/org/apache/fop/fo/FONode.java
@@ -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();
}
}
diff --git a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
index f62d7f946..1420d1b98 100644
--- a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
@@ -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;
diff --git a/src/java/org/apache/fop/render/intermediate/IFContext.java b/src/java/org/apache/fop/render/intermediate/IFContext.java
index 681b996e4..62bbbe9c5 100644
--- a/src/java/org/apache/fop/render/intermediate/IFContext.java
+++ b/src/java/org/apache/fop/render/intermediate/IFContext.java
@@ -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;
+ }
+
}
diff --git a/src/java/org/apache/fop/render/intermediate/IFRenderer.java b/src/java/org/apache/fop/render/intermediate/IFRenderer.java
index 771929809..fe3bbf72c 100644
--- a/src/java/org/apache/fop/render/intermediate/IFRenderer.java
+++ b/src/java/org/apache/fop/render/intermediate/IFRenderer.java
@@ -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);
}
diff --git a/src/java/org/apache/fop/render/pdf/PDFEventProducer.java b/src/java/org/apache/fop/render/pdf/PDFEventProducer.java
index 4b8253867..addf21666 100644
--- a/src/java/org/apache/fop/render/pdf/PDFEventProducer.java
+++ b/src/java/org/apache/fop/render/pdf/PDFEventProducer.java
@@ -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);
+
}
diff --git a/src/java/org/apache/fop/render/pdf/PDFEventProducer.xml b/src/java/org/apache/fop/render/pdf/PDFEventProducer.xml
index bf930ea34..b954e61d5 100644
--- a/src/java/org/apache/fop/render/pdf/PDFEventProducer.xml
+++ b/src/java/org/apache/fop/render/pdf/PDFEventProducer.xml
@@ -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>
diff --git a/src/java/org/apache/fop/render/pdf/PDFPainter.java b/src/java/org/apache/fop/render/pdf/PDFPainter.java
index 0160ffc1c..fa1c50318 100644
--- a/src/java/org/apache/fop/render/pdf/PDFPainter.java
+++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java
@@ -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);