diff options
author | Vincent Hennebert <vhennebert@apache.org> | 2012-10-08 17:47:48 +0000 |
---|---|---|
committer | Vincent Hennebert <vhennebert@apache.org> | 2012-10-08 17:47:48 +0000 |
commit | d9d2ec28c23c9dc69dd87c1060ea506ad08beca8 (patch) | |
tree | cb1a215d26b61bd6f6581a2962d9384f2149df12 /src | |
parent | d261730a4f7be752ae12a5ec52e6bad8ee4fa5c1 (diff) | |
download | xmlgraphics-fop-d9d2ec28c23c9dc69dd87c1060ea506ad08beca8.tar.gz xmlgraphics-fop-d9d2ec28c23c9dc69dd87c1060ea506ad08beca8.zip |
Bugzilla #53980: PDF accessibility: Store language information coming from fo:block or fo:character in the structure tree.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1395692 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
10 files changed, 137 insertions, 103 deletions
diff --git a/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java b/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java index 09a814ef5..6a763a6f6 100644 --- a/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java +++ b/src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java @@ -22,7 +22,8 @@ package org.apache.fop.accessibility.fo; import java.util.Locale; import java.util.Stack; -import org.xml.sax.SAXException; +import javax.xml.XMLConstants; + import org.xml.sax.helpers.AttributesImpl; import org.apache.fop.accessibility.StructureTreeElement; @@ -59,8 +60,11 @@ import org.apache.fop.fo.flow.table.TableRow; import org.apache.fop.fo.pagination.Flow; import org.apache.fop.fo.pagination.LayoutMasterSet; import org.apache.fop.fo.pagination.PageSequence; +import org.apache.fop.fo.pagination.Root; import org.apache.fop.fo.pagination.StaticContent; import org.apache.fop.fo.properties.CommonAccessibilityHolder; +import org.apache.fop.fo.properties.CommonHyphenation; +import org.apache.fop.util.LanguageTags; import org.apache.fop.util.XMLUtil; /** @@ -76,16 +80,20 @@ class StructureTreeEventTrigger extends FOEventHandler { private final Stack<Boolean> inTableHeader = new Stack<Boolean>(); + private final Stack<Locale> locales = new Stack<Locale>(); + public StructureTreeEventTrigger(StructureTreeEventHandler structureTreeEventHandler) { this.structureTreeEventHandler = structureTreeEventHandler; } @Override - public void startDocument() throws SAXException { + public void startRoot(Root root) { + locales.push(root.getLocale()); } @Override - public void endDocument() throws SAXException { + public void endRoot(Root root) { + locales.pop(); } @Override @@ -93,13 +101,11 @@ class StructureTreeEventTrigger extends FOEventHandler { if (layoutMasterSet == null) { layoutMasterSet = pageSeq.getRoot().getLayoutMasterSet(); } - Locale locale = null; - if (pageSeq.getLanguage() != null) { - if (pageSeq.getCountry() != null) { - locale = new Locale(pageSeq.getLanguage(), pageSeq.getCountry()); - } else { - locale = new Locale(pageSeq.getLanguage()); - } + Locale locale = pageSeq.getLocale(); + if (locale != null) { + locales.push(locale); + } else { + locales.push(locales.peek()); } String role = pageSeq.getCommonAccessibility().getRole(); structureTreeEventHandler.startPageSequence(locale, role); @@ -108,6 +114,7 @@ class StructureTreeEventTrigger extends FOEventHandler { @Override public void endPageSequence(PageSequence pageSeq) { structureTreeEventHandler.endPageSequence(); + locales.pop(); } @Override @@ -171,12 +178,28 @@ class StructureTreeEventTrigger extends FOEventHandler { @Override public void startBlock(Block bl) { - startElement(bl); + CommonHyphenation hyphProperties = bl.getCommonHyphenation(); + AttributesImpl attributes = createLangAttribute(hyphProperties); + startElement(bl, attributes); + } + + private AttributesImpl createLangAttribute(CommonHyphenation hyphProperties) { + Locale locale = hyphProperties.getLocale(); + AttributesImpl attributes = new AttributesImpl(); + if (locale == null || locale.equals(locales.peek())) { + locales.push(locales.peek()); + } else { + locales.push(locale); + addAttribute(attributes, XMLConstants.XML_NS_URI, "lang", "xml", + LanguageTags.toLanguageTag(locale)); + } + return attributes; } @Override public void endBlock(Block bl) { endElement(bl); + locales.pop(); } @Override @@ -393,8 +416,10 @@ class StructureTreeEventTrigger extends FOEventHandler { @Override public void character(Character c) { - startElementWithID(c); + AttributesImpl attributes = createLangAttribute(c.getCommonHyphenation()); + startElementWithID(c, attributes); endElement(c); + locales.pop(); } @Override @@ -409,7 +434,10 @@ class StructureTreeEventTrigger extends FOEventHandler { } private void startElementWithID(FONode node) { - AttributesImpl attributes = new AttributesImpl(); + startElementWithID(node, new AttributesImpl()); + } + + private void startElementWithID(FONode node, AttributesImpl attributes) { String localName = node.getLocalName(); if (node instanceof CommonAccessibilityHolder) { addRole((CommonAccessibilityHolder) node, attributes); diff --git a/src/java/org/apache/fop/area/AreaTreeParser.java b/src/java/org/apache/fop/area/AreaTreeParser.java index e965d15fc..a606f9727 100644 --- a/src/java/org/apache/fop/area/AreaTreeParser.java +++ b/src/java/org/apache/fop/area/AreaTreeParser.java @@ -84,6 +84,7 @@ import org.apache.fop.util.ContentHandlerFactory; import org.apache.fop.util.ContentHandlerFactoryRegistry; import org.apache.fop.util.ConversionUtils; import org.apache.fop.util.DefaultErrorListener; +import org.apache.fop.util.LanguageTags; import org.apache.fop.util.XMLConstants; import org.apache.fop.util.XMLUtil; @@ -394,10 +395,10 @@ public class AreaTreeParser { public void startElement(Attributes attributes) { PageSequence pageSequence = new PageSequence(null); - String lang = attributes.getValue("language"); - pageSequence.setLanguage(lang); - String country = attributes.getValue("country"); - pageSequence.setCountry(country); + String lang = attributes.getValue(javax.xml.XMLConstants.XML_NS_URI, "lang"); + if (lang != null) { + pageSequence.setLocale(LanguageTags.toLocale(lang)); + } transferForeignObjects(attributes, pageSequence); areaStack.push(pageSequence); } diff --git a/src/java/org/apache/fop/area/PageSequence.java b/src/java/org/apache/fop/area/PageSequence.java index 1f0411b00..124476602 100644 --- a/src/java/org/apache/fop/area/PageSequence.java +++ b/src/java/org/apache/fop/area/PageSequence.java @@ -20,6 +20,7 @@ package org.apache.fop.area; import java.util.List; +import java.util.Locale; /** * Represents a page sequence in the area tree. @@ -28,8 +29,8 @@ public class PageSequence extends AreaTreeObject { private List<PageViewport> pages = new java.util.ArrayList<PageViewport>(); private LineArea title; - private String language; - private String country; + + private Locale locale; /** * Main constructor @@ -88,43 +89,21 @@ public class PageSequence extends AreaTreeObject { } /** - * Returns the language of the page-sequence. - * @return the language (the value of the language property, "none" is mapped to null) - */ - public String getLanguage() { - return this.language; - } - - /** - * Sets the language that applies to this page-sequence. - * @param language the language to set ("none" is mapped to null) - */ - public void setLanguage(String language) { - if ("none".equals(language)) { - this.language = null; - } else { - this.language = language; - } - } - - /** - * Returns the country of the page-sequence. - * @return the country (the value of the country property, "none" is mapped to null) + * Sets the locale that applies to this page-sequence. + * + * @param locale the locale to set */ - public String getCountry() { - return this.country; + public void setLocale(Locale locale) { + this.locale = locale; } /** - * Sets the country that applies to this page-sequence. - * @param country the country to set ("none" is mapped to null) + * Returns the locale of this page-sequence. + * + * @return the locale, {@code null} if not set */ - public void setCountry(String country) { - if ("none".equals(country)) { - this.country = null; - } else { - this.country = country; - } + public Locale getLocale() { + return locale; } } diff --git a/src/java/org/apache/fop/fo/pagination/PageSequence.java b/src/java/org/apache/fop/fo/pagination/PageSequence.java index 63114b507..6039dafeb 100644 --- a/src/java/org/apache/fop/fo/pagination/PageSequence.java +++ b/src/java/org/apache/fop/fo/pagination/PageSequence.java @@ -19,6 +19,7 @@ package org.apache.fop.fo.pagination; +import java.util.Locale; import java.util.Map; import java.util.Stack; @@ -30,6 +31,7 @@ import org.apache.fop.datatypes.Numeric; import org.apache.fop.fo.FONode; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.ValidationException; +import org.apache.fop.fo.properties.CommonHyphenation; import org.apache.fop.traits.Direction; import org.apache.fop.traits.WritingMode; import org.apache.fop.traits.WritingModeTraits; @@ -41,13 +43,11 @@ import org.apache.fop.traits.WritingModeTraitsGetter; */ public class PageSequence extends AbstractPageSequence implements WritingModeTraitsGetter { - // The value of FO traits (refined properties) that apply to fo:page-sequence. - private String country; - private String language; private String masterReference; private Numeric referenceOrientation; private WritingModeTraits writingModeTraits; - // End of trait values + + private Locale locale; // There doesn't seem to be anything in the spec requiring flows // to be in the order given, only that they map to the regions @@ -90,8 +90,9 @@ public class PageSequence extends AbstractPageSequence implements WritingModeTra /** {@inheritDoc} */ public void bind(PropertyList pList) throws FOPException { super.bind(pList); - country = pList.get(PR_COUNTRY).getString(); - language = pList.get(PR_LANGUAGE).getString(); + String country = pList.get(PR_COUNTRY).getString(); + String language = pList.get(PR_LANGUAGE).getString(); + locale = CommonHyphenation.toLocale(language, country); masterReference = pList.get(PR_MASTER_REFERENCE).getString(); referenceOrientation = pList.get(PR_REFERENCE_ORIENTATION).getNumeric(); writingModeTraits = new WritingModeTraits @@ -320,20 +321,8 @@ public class PageSequence extends AbstractPageSequence implements WritingModeTra return FO_PAGE_SEQUENCE; } - /** - * Get the value of the <code>country</code> trait. - * @return the country trait value - */ - public String getCountry() { - return this.country; - } - - /** - * Get the value of the <code>language</code> trait. - * @return the language trait value - */ - public String getLanguage() { - return this.language; + public Locale getLocale() { + return locale; } /** diff --git a/src/java/org/apache/fop/fo/pagination/Root.java b/src/java/org/apache/fop/fo/pagination/Root.java index 1a2ce718b..6db8d6db1 100644 --- a/src/java/org/apache/fop/fo/pagination/Root.java +++ b/src/java/org/apache/fop/fo/pagination/Root.java @@ -36,6 +36,7 @@ import org.apache.fop.fo.extensions.destination.Destination; import org.apache.fop.fo.pagination.bookmarks.BookmarkTree; import org.apache.fop.fo.properties.CommonAccessibility; import org.apache.fop.fo.properties.CommonAccessibilityHolder; +import org.apache.fop.fo.properties.CommonHyphenation; /** * Class modeling the <a href="http://www.w3.org/TR/xsl/#fo_root"> @@ -92,17 +93,7 @@ public class Root extends FObj implements CommonAccessibilityHolder { mediaUsage = pList.get(PR_MEDIA_USAGE).getEnum(); String language = pList.get(PR_LANGUAGE).getString(); String country = pList.get(PR_COUNTRY).getString(); - if (isLocalePropertySet(language)) { - if (isLocalePropertySet(country)) { - locale = new Locale(language, country); - } else { - locale = new Locale(language); - } - } - } - - private boolean isLocalePropertySet(String property) { - return property != null && !property.equals("none"); + locale = CommonHyphenation.toLocale(language, country); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/fo/properties/CommonHyphenation.java b/src/java/org/apache/fop/fo/properties/CommonHyphenation.java index 8394a4b18..d5f4c538b 100644 --- a/src/java/org/apache/fop/fo/properties/CommonHyphenation.java +++ b/src/java/org/apache/fop/fo/properties/CommonHyphenation.java @@ -19,6 +19,8 @@ package org.apache.fop.fo.properties; +import java.util.Locale; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -185,6 +187,41 @@ public final class CommonHyphenation { return font.getCharWidth(hyphChar); } + /** + * Creates and returns a {@link Locale} representation of the language and country. + * + * @return the language (and the country if set) represented as a locale, {@code null} + * if the language has not been set (i.e., has been left to its initial value of + * "none") + */ + public Locale getLocale() { + return toLocale(language.getString(), country.getString()); + } + + /** + * Creates and returns a {@link Locale} representation of the given language, and the + * given country if set. The country is considered to be set if not {@code null} and + * not set to "none". + * + * @return the language and country represented as a locale, {@code null} if the + * language is null or "none" (case insensitive) + */ + public static Locale toLocale(String language, String country) { + Locale locale = null; + if (isDefined(language)) { + if (isDefined(country)) { + locale = new Locale(language, country); + } else { + locale = new Locale(language); + } + } + return locale; + } + + private static boolean isDefined(String property) { + return !(property == null || property.equalsIgnoreCase("none")); + } + /** {@inheritDoc} */ public boolean equals(Object obj) { if (obj == this) { diff --git a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java index 43f231cf3..577f172eb 100644 --- a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java @@ -99,8 +99,7 @@ public class PageSequenceLayoutManager extends AbstractPageSequenceLayoutManager org.apache.fop.area.PageSequence pageSequenceAreaObject = new org.apache.fop.area.PageSequence(title); transferExtensions(pageSequenceAreaObject); - pageSequenceAreaObject.setLanguage(getPageSequence().getLanguage()); - pageSequenceAreaObject.setCountry(getPageSequence().getCountry()); + pageSequenceAreaObject.setLocale(getPageSequence().getLocale()); areaTreeModel.startPageSequence(pageSequenceAreaObject); if (log.isDebugEnabled()) { log.debug("Starting layout"); diff --git a/src/java/org/apache/fop/render/intermediate/IFRenderer.java b/src/java/org/apache/fop/render/intermediate/IFRenderer.java index 57f13ac07..771929809 100644 --- a/src/java/org/apache/fop/render/intermediate/IFRenderer.java +++ b/src/java/org/apache/fop/render/intermediate/IFRenderer.java @@ -520,7 +520,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { this.inPageSequence = true; } establishForeignAttributes(pageSequence.getForeignAttributes()); - documentHandler.getContext().setLanguage(toLocale(pageSequence)); + documentHandler.getContext().setLanguage(pageSequence.getLocale()); documentHandler.startPageSequence(null); resetForeignAttributes(); processExtensionAttachments(pageSequence); @@ -529,17 +529,6 @@ public class IFRenderer extends AbstractPathOrientedRenderer { } } - 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); diff --git a/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java b/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java index 031224ffb..08aad08f6 100644 --- a/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java +++ b/src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java @@ -23,6 +23,8 @@ import java.util.LinkedList; import java.util.Locale; import java.util.Map; +import javax.xml.XMLConstants; + import org.xml.sax.Attributes; import org.xml.sax.helpers.AttributesImpl; @@ -42,6 +44,7 @@ import org.apache.fop.pdf.StandardStructureTypes.Grouping; import org.apache.fop.pdf.StandardStructureTypes.Table; import org.apache.fop.pdf.StructureHierarchyMember; import org.apache.fop.pdf.StructureType; +import org.apache.fop.util.LanguageTags; import org.apache.fop.util.XMLUtil; class PDFStructureTreeBuilder implements StructureTreeEventHandler { @@ -62,10 +65,10 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler { addBuilder("static-content", regionBuilder); addBuilder("flow", regionBuilder); // Block-level Formatting Objects - addBuilder("block", StandardStructureTypes.Paragraphlike.P); + addBuilder("block", new LanguageHolderBuilder(StandardStructureTypes.Paragraphlike.P)); addBuilder("block-container", StandardStructureTypes.Grouping.DIV); // Inline-level Formatting Objects - addBuilder("character", StandardStructureTypes.InlineLevelStructure.SPAN); + addBuilder("character", new LanguageHolderBuilder(StandardStructureTypes.InlineLevelStructure.SPAN)); addBuilder("external-graphic", new ImageBuilder()); addBuilder("instream-foreign-object", new ImageBuilder()); addBuilder("inline", StandardStructureTypes.InlineLevelStructure.SPAN); @@ -192,6 +195,23 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler { } + private static class LanguageHolderBuilder extends DefaultStructureElementBuilder { + + LanguageHolderBuilder(StructureType structureType) { + super(structureType); + } + + @Override + protected void setAttributes(PDFStructElem structElem, Attributes attributes) { + String xmlLang = attributes.getValue(XMLConstants.XML_NS_URI, "lang"); + if (xmlLang != null) { + Locale locale = LanguageTags.toLocale(xmlLang); + structElem.setLanguage(locale); + } + } + + } + private static class ImageBuilder extends DefaultStructureElementBuilder { ImageBuilder() { diff --git a/src/java/org/apache/fop/render/xml/XMLRenderer.java b/src/java/org/apache/fop/render/xml/XMLRenderer.java index cf3cbe5a2..4a920d18d 100644 --- a/src/java/org/apache/fop/render/xml/XMLRenderer.java +++ b/src/java/org/apache/fop/render/xml/XMLRenderer.java @@ -27,8 +27,10 @@ import java.io.IOException; import java.io.OutputStream; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Map; +import javax.xml.XMLConstants; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; @@ -86,6 +88,7 @@ import org.apache.fop.render.Renderer; import org.apache.fop.render.RendererContext; import org.apache.fop.render.XMLHandler; import org.apache.fop.util.ColorUtil; +import org.apache.fop.util.LanguageTags; import org.apache.fop.util.XMLUtil; /** @@ -450,11 +453,9 @@ public class XMLRenderer extends AbstractXMLRenderer { endPageSequence(); // move this before handleDocumentExtensionAttachments() ? startedSequence = true; atts.clear(); - if (pageSequence.getLanguage() != null) { - addAttribute("language", pageSequence.getLanguage()); - } - if (pageSequence.getCountry() != null) { - addAttribute("country", pageSequence.getCountry()); + Locale locale = pageSequence.getLocale(); + if (locale != null) { + addAttribute(new QName(XMLConstants.XML_NS_URI, "xml:lang"), LanguageTags.toLanguageTag(locale)); } transferForeignObjects(pageSequence); startElement("pageSequence", atts); |