diff options
Diffstat (limited to 'src/java/org/apache/fop')
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); |