From d9d2ec28c23c9dc69dd87c1060ea506ad08beca8 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Mon, 8 Oct 2012 17:47:48 +0000 Subject: [PATCH] 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 --- .../fo/StructureTreeEventTrigger.java | 54 ++++++++++++---- .../org/apache/fop/area/AreaTreeParser.java | 9 +-- .../org/apache/fop/area/PageSequence.java | 47 ++++---------- .../fop/fo/pagination/PageSequence.java | 29 +++------ .../org/apache/fop/fo/pagination/Root.java | 13 +--- .../fop/fo/properties/CommonHyphenation.java | 37 +++++++++++ .../layoutmgr/PageSequenceLayoutManager.java | 3 +- .../fop/render/intermediate/IFRenderer.java | 13 +--- .../render/pdf/PDFStructureTreeBuilder.java | 24 +++++++- .../apache/fop/render/xml/XMLRenderer.java | 11 ++-- status.xml | 4 ++ .../fo/FO2StructureTreeConverterTestCase.java | 5 ++ .../fop/accessibility/fo/fo2StructureTree.xsl | 13 +++- .../apache/fop/accessibility/fo/language.fo | 30 +++++++++ .../properties/CommonHyphenationTestCase.java | 58 ++++++++++++++++++ .../block_hyphenation_kerning.xml | 3 +- .../page-sequence_language.xml | 12 ++-- test/pdf/accessibility/language.fo | 30 +++++++++ test/pdf/accessibility/pdf/complete.pdf | Bin 94698 -> 94714 bytes test/pdf/accessibility/pdf/language.pdf | Bin 0 -> 8739 bytes test/pdf/accessibility/pdf/side-regions.pdf | Bin 26963 -> 26943 bytes .../accessibility/pdf/table_row-col-span.pdf | Bin 18844 -> 18824 bytes test/pdf/accessibility/pdf/text_2.pdf | Bin 10247 -> 10263 bytes test/pdf/accessibility/pdf/th_scope.pdf | Bin 15495 -> 15475 bytes 24 files changed, 281 insertions(+), 114 deletions(-) create mode 100644 test/java/org/apache/fop/accessibility/fo/language.fo create mode 100644 test/java/org/apache/fop/fo/properties/CommonHyphenationTestCase.java create mode 100644 test/pdf/accessibility/language.fo create mode 100644 test/pdf/accessibility/pdf/language.pdf 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 inTableHeader = new Stack(); + private final Stack locales = new Stack(); + 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 pages = new java.util.ArrayList(); 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 country trait. - * @return the country trait value - */ - public String getCountry() { - return this.country; - } - - /** - * Get the value of the language 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 @@ -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); diff --git a/status.xml b/status.xml index 76b25a9eb..78cf4efc2 100644 --- a/status.xml +++ b/status.xml @@ -62,6 +62,10 @@ documents. Example: the fix of marks layering will be such a case when it's done. --> + + PDF accessibility: Store language information coming from fo:block or fo:character in the + structure tree. + Support for retrieve-table-markers diff --git a/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java b/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java index 87b970576..a86b5b2b2 100644 --- a/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java +++ b/test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java @@ -96,6 +96,11 @@ public class FO2StructureTreeConverterTestCase { testConverter("table-header_scope.fo"); } + @Test + public void testLanguage() throws Exception { + testConverter("language.fo"); + } + private static InputStream getResource(String name) { return FO2StructureTreeConverterTestCase.class.getResourceAsStream(name); } diff --git a/test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl b/test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl index 90d74a7c4..a9de38db1 100644 --- a/test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl +++ b/test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl @@ -150,11 +150,22 @@ - + + + + + + - + + + + + diff --git a/test/java/org/apache/fop/accessibility/fo/language.fo b/test/java/org/apache/fop/accessibility/fo/language.fo new file mode 100644 index 000000000..8dfb2694a --- /dev/null +++ b/test/java/org/apache/fop/accessibility/fo/language.fo @@ -0,0 +1,30 @@ + + + + + + + + + + This block of text is written in the default language of the page sequence, which is + British English. + Ce text est + écrit dans une autre langue, en l’occurence le français de France. + However, this block of French text encloses a block of American + English. + The structure element corresponding to this block should have no language + set as it is the same as on the parent block. + Maintenant on revient au français. + And now we are back to the English language, with a + rench + character. + + + diff --git a/test/java/org/apache/fop/fo/properties/CommonHyphenationTestCase.java b/test/java/org/apache/fop/fo/properties/CommonHyphenationTestCase.java new file mode 100644 index 000000000..029146413 --- /dev/null +++ b/test/java/org/apache/fop/fo/properties/CommonHyphenationTestCase.java @@ -0,0 +1,58 @@ +/* + * 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.fo.properties; + +import java.util.Locale; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class CommonHyphenationTestCase { + + private final String lang = "en"; + + @Test + public void testToLocaleNull() { + Locale locale = CommonHyphenation.toLocale(null, null); + assertNull(locale); + locale = CommonHyphenation.toLocale("none", null); + assertNull(locale); + locale = CommonHyphenation.toLocale("NoNe", "US"); + assertNull(locale); + } + + @Test + public void testToLocaleWithJustLanguage() { + Locale locale = new Locale(lang); + assertEquals(locale, CommonHyphenation.toLocale(lang, null)); + assertEquals(locale, CommonHyphenation.toLocale(lang, "none")); + assertEquals(locale, CommonHyphenation.toLocale(lang, "NONE")); + } + + @Test + public void testToLocaleWithLanguageAndCountry() { + Locale locale = new Locale(lang, "US"); + assertEquals(locale, CommonHyphenation.toLocale(lang, "US")); + assertEquals(locale, CommonHyphenation.toLocale(lang, "us")); + } + +} diff --git a/test/layoutengine/hyphenation-testcases/block_hyphenation_kerning.xml b/test/layoutengine/hyphenation-testcases/block_hyphenation_kerning.xml index 084f1e685..9f94969cb 100644 --- a/test/layoutengine/hyphenation-testcases/block_hyphenation_kerning.xml +++ b/test/layoutengine/hyphenation-testcases/block_hyphenation_kerning.xml @@ -45,8 +45,7 @@ - - + diff --git a/test/layoutengine/standard-testcases/page-sequence_language.xml b/test/layoutengine/standard-testcases/page-sequence_language.xml index f2fa610bc..4ff0fe3b3 100644 --- a/test/layoutengine/standard-testcases/page-sequence_language.xml +++ b/test/layoutengine/standard-testcases/page-sequence_language.xml @@ -53,17 +53,13 @@ - - + - - + - - + - - + diff --git a/test/pdf/accessibility/language.fo b/test/pdf/accessibility/language.fo new file mode 100644 index 000000000..8dfb2694a --- /dev/null +++ b/test/pdf/accessibility/language.fo @@ -0,0 +1,30 @@ + + + + + + + + + + This block of text is written in the default language of the page sequence, which is + British English. + Ce text est + écrit dans une autre langue, en l’occurence le français de France. + However, this block of French text encloses a block of American + English. + The structure element corresponding to this block should have no language + set as it is the same as on the parent block. + Maintenant on revient au français. + And now we are back to the English language, with a + rench + character. + + + diff --git a/test/pdf/accessibility/pdf/complete.pdf b/test/pdf/accessibility/pdf/complete.pdf index a9bb3df778058759fb011eff424d053dbd2a3386..38d9bc4997db94a662b1e068e788d9c4e2d16c49 100644 GIT binary patch delta 680 zcmaiwy-EW?6or{U5QY%*1Tqi;Dg^KR?%XH=cavZtMpVScBE?2TSRtkmn+SHP1dDC+ z2#Vn13-}PW>BJ|na*Y9HMsS#7_&9gYx#w+K{FoMRuPFzx+)5$E!#FILIn==(aNCd~ zzmKowb>gtQYUSKPHsgUYcX}g!4u;u=s-q~A8c}SMh`z~3`-jB#`X;p9rUxy`( z&K{UsOOK)DX+I`A1ue3tm>e#Q0(3;yqERkGj@o0w2#-nW2C*p74PsFt%w|VFi7jgF z8yop8{H+T_;2B%t&!X3gMVuSY{~P6HA%J!_LEy@520{E$sj$9ITH^#nP}Xe$L0bap zI3bM!53-kpJQvP3O*`N`QXzh|4NQ2V{7}TS25$-&}Nff V410s&h%Q&D>b4-N%vQAtp;{c>Mg{U zEH6F0)RvjYZW{Gt4_%Jx#i-62Yx&zQo6qlhY_9m&VH>jx5DEA?A`^V_Ah2WuMkdNn zQ?_1Frg%!(_RP>IPvjhF=QBb}0h8JUOramdk+Ob}(!%P=?C>YCqez9u2ET>Bbrvx& zb`Z`|(266P8c+WlmSquu@;4zsr>HIchtqNfAoUzBs z5!ob)jnXkBM!Ama#<4b0LI@obOE7J*@~>o%3$e6$c%BN33~#sj$zZ=fIP0eeoKU0U K&E{&a%Rd3Ka*^Ty diff --git a/test/pdf/accessibility/pdf/language.pdf b/test/pdf/accessibility/pdf/language.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ee4cd0b2d78badae2a57e6f24440e613d6828ab6 GIT binary patch literal 8739 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 delta 1299 zcmah|y>1gh5Z2M*!g3ddhAW6fib(U#?(ELQ2r0H~nka4%y$dS}h4ToPIu+8DR6GK* zgha(VgfbnEz!R{TALE@!Ty^?x?%Vl(_RC%K^{#n$GazL^qC!93PKQI%6UJ-EY1C8b z=6*PCDy)Atx~`zjhtcOWI$y3Y+vn@+_3GqeaWOmIym|Hh@Hoeoem?EG9c*7XLfK(K z`X|dpll!;JaVJuJhYD&QXrk=qQc4cXVh$^M9cI85>vqdREmJ*cl!C*+wI~>iJH!Iq z(iUZpuPZ*m1fDQOPnf+6rg4vO%V$*cF_HdKyc5iXSoCj`+C@eIwS`O}*UK=8)asZL z>PVQf)e$qP{EoQ$=U|JD5JZj;WNyJyYqua+oMHs*3oiaMBGncaEIA7yuB?pY%F6ID z70i{DOVh2Z?T5LxatX>QDZcJ2DMGkdQ}dOdoj8u^k6Yc}tI9cgLUn~>wg(8!-4YJu z`w>EYa}J4vsLMSl^`BPbCTza1zCD_r%?Z=_Y{E(=Q^-WK6#o5XU*}UU3A{TD&4DEX0|encba44(`r7(xuQ=&?15e3NeV-JWH`sUMq;- zz?hHYN3n5V;wA6)AMmQjFthWY-~4y)TR-{KPriI?m?(3Wpy~Ycayn(YPx%Sw0|^J3 zE`CoBCsnN9+j&!kE`IF%*}eF=_wMdJ&MghU_I2A_esJWJAST)$&yOdm|2{wH#I;Hw z*H{;kTc{5wFQ-Fo%nq@X31T_P5bH*2$z8ZgEQCTWaG(|-kCQ>HfQ6XQIIr|4ViK>X zV^Wxe$!=*JwVsYC$>nsT;h6GP8)6u7j3JjOvdI8bHz*P|Pmg%xqJ z;dE@bG>Hx?DH{PYoOMggz@OP=ypu~b><$zHC0J8n0}3G+oEJoEV{%aK0DmyrQaA_< z=6GNMCiNy`+P*{pec_Wbnh{prbzhGS%J_V-uE>*g;ax_0~k delta 1897 zcmah~J#Q015S2?@SeEDz5-t*n6cIB!GdsHuLJIa-K|*oE4}bzufSjJ@C=oPB*HF;# z6Tm+wKZS<%g~;c9k+|wKnveJ1yxslWjec~aZ=c5GLD@Np{`#_*Ovq1zzG9zqnu~6) zCugH7)*Vf+s?hf5^w0h2%Qu^Mv&WmO&D+z<^<{Ii{eJZE;fbUf?Y`M&Htv5oa(0MG z?9R^DquhNxpSQ|dB~aE>7g08?n^TU0c}^Mnr2^>?80C~@7i$M-DQDv-``$?>g$w6Za@&^kC2zLNOWNa86YaJB~$#HPLt?eGH#;p*RNm04xRjdmzL;{E` zci34B7bKB(8t-$!!eM2ix1QZ99+Qh*3rYN3M(gd(r697tNBF&B}~8i&^72 eK5rtI3x2V9HhcQNlw{pfy>aqz{1eN*vQ0UW0yT2pP_-SfklX+g_W_9m5IgX>wMOXXkwEU1oF{@ zHqRBfCcxv9n3t}gkyfPZ7Nog2Uy()2*jT{;1QhZVxWEhpO9M+w3^5}!)5$Yc{g^C` zCcjiIWwtP|oSdj;#bjx*d9E5GqqCufnX!|FiL0rzql>GPo1vqLrG>evnTeU9k-3GL anUS4>4Iw3yAF9i8ni+Dbs=E5SaRC5C^E@m7 delta 241 zcmbOp&>k?Mfy=wMOXXkwEU1oF{@ zHqRBfCNQ~2Nn`VB#VgEOhUN+eAfS+^zy)R)SQ=OuV~81c?bmHuY<&VPY+`j{BUlOd1U`b?JJ|UI zK87#gC21}<0k>K{X7>BdeEa(JyL^An5I|9x1U}!=aENdYdV^Xp6#~uAa5Cs=_3`MT zCp90V?}O&$Y`K5xF^AR3@AGVZK~@5z#aJKdVnFqy78OU|FF+?^G$FQ{I-_~9?*+7V z3Sre-b!kz(HIAZv69P0Qgb+;~T0o*Lz}6oCi7g?y4Ph6MoCPG=0qA!Ch8=*RQj-}e z+espmnJz|~EvSj9oy~YK@g|b0`&k&wTA97cj-9Nt>u!bxO?2$-#O(c6Z+$YkXn*4E st<8 delta 886 zcmaiyyGjF55Qa(V3hNejf^1>HfRVYKTM`0h*{wp-*o%b-7MoT9VdTs$B4Jf^TdX_-cw3$hnzYXVpw`FTg`8$YN7 zZMy))8KoIvrCAWIIsKnwUFXTI-&Rdp^j;eW=i4R(tV{?gs5;VsL_2^he*h%bgd|(S zCLoChB(n$5?g4ar0DT22GxA1v5)8GwV?dQHBdC}dt@2