diff options
35 files changed, 167 insertions, 26 deletions
diff --git a/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd b/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd index 5e58c8208..d6f0c694c 100644 --- a/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd +++ b/src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd @@ -68,6 +68,7 @@ <xs:attribute name="word-spacing" type="mf:lengthType"/> <xs:attribute name="dx" type="mf:lengthListType"/> <xs:attribute name="dp" type="mf:dpListType"/> + <xs:attribute name="hyphenated" type="xs:boolean"/> </xs:extension> </xs:simpleContent> </xs:complexType> diff --git a/src/java/org/apache/fop/area/inline/TextArea.java b/src/java/org/apache/fop/area/inline/TextArea.java index 1d27827f7..66854f7f2 100644 --- a/src/java/org/apache/fop/area/inline/TextArea.java +++ b/src/java/org/apache/fop/area/inline/TextArea.java @@ -30,6 +30,8 @@ public class TextArea extends AbstractTextArea { private static final long serialVersionUID = 7315900267242540809L; + private boolean isHyphenated; + /** * Create a text inline area */ @@ -117,6 +119,20 @@ public class TextArea extends AbstractTextArea { } /** + * Records that the last word in this text area is hyphenated. + */ + public void setHyphenated() { + this.isHyphenated = true; + } + + /** + * Returns {@code true} if the last word in this area is hyphenated. + */ + public boolean isHyphenated() { + return isHyphenated; + } + + /** * Get the whole text string. * Renderers whose space adjustment handling is not affected * by multi-byte characters can use this method to render the diff --git a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java index c2f69cf98..573019bf6 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java @@ -624,6 +624,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { wordChars.append(foText.getCommonHyphenation().getHyphChar(font)); // [TBD] expand bidi word levels, letter space adjusts, gpos adjusts // [TBD] [GA] problematic in bidi context... what is level of hyphen? + textArea.setHyphenated(); } /** diff --git a/src/java/org/apache/fop/render/intermediate/IFContext.java b/src/java/org/apache/fop/render/intermediate/IFContext.java index 62bbbe9c5..fda0cff3b 100644 --- a/src/java/org/apache/fop/render/intermediate/IFContext.java +++ b/src/java/org/apache/fop/render/intermediate/IFContext.java @@ -53,6 +53,8 @@ public class IFContext { private String location; + private boolean hyphenated; + /** * Main constructor. * @param ua the user agent @@ -200,4 +202,18 @@ public class IFContext { return location; } + /** + * Records that the last text in the currently processed text area is hyphenated. + */ + public void setHyphenated(boolean hyphenated) { + this.hyphenated = hyphenated; + } + + /** + * Returns {@code true} if the last text in the currently processed text area is hyphenated. + */ + public boolean isHyphenated() { + return hyphenated; + } + } diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java index 24b7a924c..5753dad01 100644 --- a/src/java/org/apache/fop/render/intermediate/IFParser.java +++ b/src/java/org/apache/fop/render/intermediate/IFParser.java @@ -633,7 +633,12 @@ public class IFParser implements IFConstants { dp = IFUtil.convertDXToDP ( dx ); } establishStructureTreeElement(lastAttributes); + boolean isHyphenated = Boolean.valueOf(lastAttributes.getValue("hyphenated")); + if (isHyphenated) { + documentHandler.getContext().setHyphenated(isHyphenated); + } painter.drawText(x, y, letterSpacing, wordSpacing, dp, content.toString()); + documentHandler.getContext().setHyphenated(false); resetStructureTreeElement(); } diff --git a/src/java/org/apache/fop/render/intermediate/IFRenderer.java b/src/java/org/apache/fop/render/intermediate/IFRenderer.java index 592a57ebe..d1e2217c7 100644 --- a/src/java/org/apache/fop/render/intermediate/IFRenderer.java +++ b/src/java/org/apache/fop/render/intermediate/IFRenderer.java @@ -1032,10 +1032,12 @@ public class IFRenderer extends AbstractPathOrientedRenderer { textUtil.flush(); textUtil.setStartPosition(rx, bl); textUtil.setSpacing(text.getTextLetterSpaceAdjust(), text.getTextWordSpaceAdjust()); + documentHandler.getContext().setHyphenated(text.isHyphenated()); super.renderText(text); textUtil.flush(); renderTextDecoration(tf, size, text, bl, rx); + documentHandler.getContext().setHyphenated(false); resetStructurePointer(); } diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java index 24239e5f4..f8882f1e0 100644 --- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java +++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java @@ -678,6 +678,9 @@ implements IFConstants, IFPainter, IFDocumentNavigationHandler { } } addStructureReference(atts); + if (getContext().isHyphenated()) { + addAttribute(atts, "hyphenated", "true"); + } handler.startElement(EL_TEXT, atts); char[] chars = text.toCharArray(); handler.characters(chars, 0, chars.length); diff --git a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java index 7a6e4e3d2..f20339078 100644 --- a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java +++ b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java @@ -32,6 +32,7 @@ import org.apache.fop.pdf.PDFNumber; import org.apache.fop.pdf.PDFPaintingState; import org.apache.fop.pdf.PDFResourceContext; import org.apache.fop.pdf.PDFStream; +import org.apache.fop.pdf.PDFText; import org.apache.fop.pdf.PDFTextUtil; import org.apache.fop.pdf.PDFXObject; @@ -171,17 +172,36 @@ public class PDFContentGenerator { } /** - * Begins a new marked content sequence (BDC or BMC). If the parameter structElemType is null, - * the sequenceNum is ignored and instead of a BDC with the MCID as parameter, an "Artifact" - * and a BMC command is generated. - * @param structElemType Structure Element Type - * @param mcid Sequence number + * Begins a new marked content sequence (BDC or BMC). If {@code structElemType} is + * null, a BMC operator with an "Artifact" tag is generated. Otherwise, a BDC operator + * with {@code structElemType} as a tag is generated, and the given mcid stored in its + * property list. + * + * @param structElemType the type of the associated structure element + * @param mcid the marked content identifier */ protected void beginMarkedContentSequence(String structElemType, int mcid) { + beginMarkedContentSequence(structElemType, mcid, null); + } + + /** + * Begins a new marked content sequence (BDC or BMC). If {@code structElemType} is + * null, a BMC operator with an "Artifact" tag is generated. Otherwise, a BDC operator + * with {@code structElemType} as a tag is generated, and the given mcid and actual + * text are stored in its property list. + * + * @param structElemType the type of the associated structure element + * @param mcid the marked content identifier + * @param actualText the replacement text for the marked content + */ + protected void beginMarkedContentSequence(String structElemType, int mcid, String actualText) { assert !this.inMarkedContentSequence; assert !this.inArtifactMode; if (structElemType != null) { - currentStream.add(structElemType + " <</MCID " + String.valueOf(mcid) + ">>\n" + String actualTextProperty = actualText == null ? "" + : " /ActualText " + PDFText.escapeText(actualText); + currentStream.add(structElemType + " <</MCID " + String.valueOf(mcid) + + actualTextProperty + ">>\n" + "BDC\n"); } else { currentStream.add("/Artifact\nBMC\n"); @@ -230,21 +250,6 @@ public class PDFContentGenerator { currentState.restore(); } - /** - * Separates 2 text elements, ending the current marked content sequence and - * starting a new one. - * - * @param structElemType structure element type - * @param mcid sequence number - * @see #beginMarkedContentSequence(String, int) - */ - protected void separateTextElements(String structElemType, int mcid) { - textutil.endTextObject(); - endMarkedContentSequence(); - beginMarkedContentSequence(structElemType, mcid); - textutil.beginTextObject(); - } - /** Indicates the beginning of a text object. */ protected void beginTextObject() { if (!textutil.isInTextObject()) { @@ -261,8 +266,21 @@ public class PDFContentGenerator { * @see #beginMarkedContentSequence(String, int) */ protected void beginTextObject(String structElemType, int mcid) { + beginTextObject(structElemType, mcid, null); + } + + /** + * Indicates the beginning of a marked-content text object. + * + * @param structElemType structure element type + * @param mcid sequence number + * @param actualText the replacement text for the marked content + * @see #beginTextObject() + * @see #beginMarkedContentSequence(String, int, String)) + */ + protected void beginTextObject(String structElemType, int mcid, String actualText) { if (!textutil.isInTextObject()) { - beginMarkedContentSequence(structElemType, mcid); + beginMarkedContentSequence(structElemType, mcid, actualText); textutil.beginTextObject(); } } diff --git a/src/java/org/apache/fop/render/pdf/PDFPainter.java b/src/java/org/apache/fop/render/pdf/PDFPainter.java index 7b636fddd..d71c6aff4 100644 --- a/src/java/org/apache/fop/render/pdf/PDFPainter.java +++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java @@ -343,11 +343,10 @@ public class PDFPainter extends AbstractIFPainter<PDFDocumentHandler> { PDFStructElem structElem = (PDFStructElem) getContext().getStructureTreeElement(); languageAvailabilityChecker.checkLanguageAvailability(text); MarkedContentInfo mci = logicalStructureHandler.addTextContentItem(structElem); - if (generator.getTextUtil().isInTextObject()) { - generator.separateTextElements(mci.tag, mci.mcid); - } + String actualText = getContext().isHyphenated() ? text.substring(0, text.length() - 1) : null; + generator.endTextObject(); generator.updateColor(state.getTextColor(), true, null); - generator.beginTextObject(mci.tag, mci.mcid); + generator.beginTextObject(mci.tag, mci.mcid, actualText); } else { generator.updateColor(state.getTextColor(), true, null); generator.beginTextObject(); diff --git a/status.xml b/status.xml index d4a2e63bd..bcf8c2475 100644 --- a/status.xml +++ b/status.xml @@ -59,6 +59,9 @@ 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="54081"> + PDF accessibility: properly tag hyphenated words. + </action> <action context="Code" dev="CB" type="fix" fixes-bug="48955" due-to="Peter Hancock"> Allow AFP font codepage names to be less than 8 chars </action> diff --git a/test/intermediate/hyphenation.xml b/test/intermediate/hyphenation.xml new file mode 100644 index 000000000..307f45680 --- /dev/null +++ b/test/intermediate/hyphenation.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" standalone="no"?> +<!-- + 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. +--> +<testcase> + <info> + <p> + This test checks that lines ending with a hyphenated word are properly marked as such. + </p> + </info> + <fo> + <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xml:lang="en-US"> + <fo:layout-master-set> + <fo:simple-page-master master-name="page" + page-height="170pt" page-width="220pt" margin="10pt"> + <fo:region-body display-align="center"/> + </fo:simple-page-master> + </fo:layout-master-set> + <fo:page-sequence master-reference="page" hyphenate="true"> + <fo:flow flow-name="xsl-region-body" text-align="justify"> + <fo:block-container width="140pt" start-indent="30pt"> + <fo:block start-indent="0">Hyphenated text. Hyphenated text. Hyphenated text. Hyphenated + text. Hyphenated text.</fo:block> + </fo:block-container> + <fo:block-container width="140pt" space-before="10pt" start-indent="30pt"> + <fo:block start-indent="0">Hyphenated text with ‘special’ character. Hyphenated text + with ‘special’ character.</fo:block> + </fo:block-container> + </fo:flow> + </fo:page-sequence> + </fo:root> + </fo> + <if-checks xmlns:if="http://xmlgraphics.apache.org/fop/intermediate"> + <eval expected="true" xpath="/descendant::if:text[1]/@hyphenated"/> + <eval expected="" xpath="/descendant::if:text[2]/@hyphenated"/> + <eval expected="true" xpath="/descendant::if:text[3]/@hyphenated"/> + <eval expected="" xpath="/descendant::if:text[4]/@hyphenated"/> + <eval expected="true" xpath="/descendant::if:text[5]/@hyphenated"/> + <eval expected="true" xpath="/descendant::if:text[6]/@hyphenated"/> + <eval expected="true" xpath="/descendant::if:text[7]/@hyphenated"/> + <eval expected="" xpath="/descendant::if:text[8]/@hyphenated"/> + </if-checks> +</testcase> diff --git a/test/pdf/accessibility/hyphenation.fo b/test/pdf/accessibility/hyphenation.fo new file mode 100644 index 000000000..28a3b76df --- /dev/null +++ b/test/pdf/accessibility/hyphenation.fo @@ -0,0 +1,21 @@ +<?xml version="1.0"?> +<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xml:lang="en-US"> + <fo:layout-master-set> + <fo:simple-page-master master-name="page" + page-height="170pt" page-width="220pt" margin="10pt"> + <fo:region-body display-align="center"/> + </fo:simple-page-master> + </fo:layout-master-set> + <fo:page-sequence master-reference="page" hyphenate="true"> + <fo:flow flow-name="xsl-region-body" text-align="justify"> + <fo:block-container width="140pt" start-indent="30pt"> + <fo:block start-indent="0">Hyphenated text. Hyphenated text. Hyphenated text. Hyphenated + text. Hyphenated text.</fo:block> + </fo:block-container> + <fo:block-container width="140pt" space-before="10pt" start-indent="30pt"> + <fo:block start-indent="0">Hyphenated text with ‘special’ character. Hyphenated text with + ‘special’ character.</fo:block> + </fo:block-container> + </fo:flow> + </fo:page-sequence> +</fo:root> diff --git a/test/pdf/accessibility/pdf/background-image_jpg_repeat.pdf b/test/pdf/accessibility/pdf/background-image_jpg_repeat.pdf Binary files differindex bf3cdccad..65f04cdef 100644 --- a/test/pdf/accessibility/pdf/background-image_jpg_repeat.pdf +++ b/test/pdf/accessibility/pdf/background-image_jpg_repeat.pdf diff --git a/test/pdf/accessibility/pdf/background-image_jpg_single.pdf b/test/pdf/accessibility/pdf/background-image_jpg_single.pdf Binary files differindex 4d40ebc7a..6803ba999 100644 --- a/test/pdf/accessibility/pdf/background-image_jpg_single.pdf +++ b/test/pdf/accessibility/pdf/background-image_jpg_single.pdf diff --git a/test/pdf/accessibility/pdf/background-image_png_repeat.pdf b/test/pdf/accessibility/pdf/background-image_png_repeat.pdf Binary files differindex 7847bcedd..d42d935aa 100644 --- a/test/pdf/accessibility/pdf/background-image_png_repeat.pdf +++ b/test/pdf/accessibility/pdf/background-image_png_repeat.pdf diff --git a/test/pdf/accessibility/pdf/background-image_png_single.pdf b/test/pdf/accessibility/pdf/background-image_png_single.pdf Binary files differindex 9458b54f8..ba39a2b31 100644 --- a/test/pdf/accessibility/pdf/background-image_png_single.pdf +++ b/test/pdf/accessibility/pdf/background-image_png_single.pdf diff --git a/test/pdf/accessibility/pdf/background-image_svg_repeat.pdf b/test/pdf/accessibility/pdf/background-image_svg_repeat.pdf Binary files differindex 0921d734f..1de4c98a1 100644 --- a/test/pdf/accessibility/pdf/background-image_svg_repeat.pdf +++ b/test/pdf/accessibility/pdf/background-image_svg_repeat.pdf diff --git a/test/pdf/accessibility/pdf/background-image_svg_single.pdf b/test/pdf/accessibility/pdf/background-image_svg_single.pdf Binary files differindex 9c8af4fb6..b89ea182a 100644 --- a/test/pdf/accessibility/pdf/background-image_svg_single.pdf +++ b/test/pdf/accessibility/pdf/background-image_svg_single.pdf diff --git a/test/pdf/accessibility/pdf/complete.pdf b/test/pdf/accessibility/pdf/complete.pdf Binary files differindex a9bb3df77..9b4df8c40 100644 --- a/test/pdf/accessibility/pdf/complete.pdf +++ b/test/pdf/accessibility/pdf/complete.pdf diff --git a/test/pdf/accessibility/pdf/hyphenation.pdf b/test/pdf/accessibility/pdf/hyphenation.pdf Binary files differnew file mode 100644 index 000000000..d8552f63a --- /dev/null +++ b/test/pdf/accessibility/pdf/hyphenation.pdf diff --git a/test/pdf/accessibility/pdf/image_jpg.pdf b/test/pdf/accessibility/pdf/image_jpg.pdf Binary files differindex 21bae3826..e35768d8a 100644 --- a/test/pdf/accessibility/pdf/image_jpg.pdf +++ b/test/pdf/accessibility/pdf/image_jpg.pdf diff --git a/test/pdf/accessibility/pdf/image_png.pdf b/test/pdf/accessibility/pdf/image_png.pdf Binary files differindex 5bd99a623..a33d2ed3f 100644 --- a/test/pdf/accessibility/pdf/image_png.pdf +++ b/test/pdf/accessibility/pdf/image_png.pdf diff --git a/test/pdf/accessibility/pdf/image_svg.pdf b/test/pdf/accessibility/pdf/image_svg.pdf Binary files differindex cc0a3ebba..1184ddef9 100644 --- a/test/pdf/accessibility/pdf/image_svg.pdf +++ b/test/pdf/accessibility/pdf/image_svg.pdf diff --git a/test/pdf/accessibility/pdf/image_wmf.pdf b/test/pdf/accessibility/pdf/image_wmf.pdf Binary files differindex 368afe60d..43c15d9ea 100644 --- a/test/pdf/accessibility/pdf/image_wmf.pdf +++ b/test/pdf/accessibility/pdf/image_wmf.pdf diff --git a/test/pdf/accessibility/pdf/language.pdf b/test/pdf/accessibility/pdf/language.pdf Binary files differindex ee4cd0b2d..48a5f9f52 100644 --- a/test/pdf/accessibility/pdf/language.pdf +++ b/test/pdf/accessibility/pdf/language.pdf diff --git a/test/pdf/accessibility/pdf/leader.pdf b/test/pdf/accessibility/pdf/leader.pdf Binary files differindex 4b91dfe8e..e277699e5 100644 --- a/test/pdf/accessibility/pdf/leader.pdf +++ b/test/pdf/accessibility/pdf/leader.pdf diff --git a/test/pdf/accessibility/pdf/links.pdf b/test/pdf/accessibility/pdf/links.pdf Binary files differindex d2ff84ea4..896620bfb 100644 --- a/test/pdf/accessibility/pdf/links.pdf +++ b/test/pdf/accessibility/pdf/links.pdf diff --git a/test/pdf/accessibility/pdf/role.pdf b/test/pdf/accessibility/pdf/role.pdf Binary files differindex 8fb665b79..6e26032ff 100644 --- a/test/pdf/accessibility/pdf/role.pdf +++ b/test/pdf/accessibility/pdf/role.pdf diff --git a/test/pdf/accessibility/pdf/role_non-standard.pdf b/test/pdf/accessibility/pdf/role_non-standard.pdf Binary files differindex 9effef793..edf7541df 100644 --- a/test/pdf/accessibility/pdf/role_non-standard.pdf +++ b/test/pdf/accessibility/pdf/role_non-standard.pdf diff --git a/test/pdf/accessibility/pdf/side-regions.pdf b/test/pdf/accessibility/pdf/side-regions.pdf Binary files differindex 1bd64e115..22364c2c8 100644 --- a/test/pdf/accessibility/pdf/side-regions.pdf +++ b/test/pdf/accessibility/pdf/side-regions.pdf diff --git a/test/pdf/accessibility/pdf/table_row-col-span.pdf b/test/pdf/accessibility/pdf/table_row-col-span.pdf Binary files differindex 603717d2e..eec14fa3d 100644 --- a/test/pdf/accessibility/pdf/table_row-col-span.pdf +++ b/test/pdf/accessibility/pdf/table_row-col-span.pdf diff --git a/test/pdf/accessibility/pdf/text_1.pdf b/test/pdf/accessibility/pdf/text_1.pdf Binary files differindex bacd7a9d0..f3daa44b0 100644 --- a/test/pdf/accessibility/pdf/text_1.pdf +++ b/test/pdf/accessibility/pdf/text_1.pdf diff --git a/test/pdf/accessibility/pdf/text_2.pdf b/test/pdf/accessibility/pdf/text_2.pdf Binary files differindex 4411b302f..5a2abcf2f 100644 --- a/test/pdf/accessibility/pdf/text_2.pdf +++ b/test/pdf/accessibility/pdf/text_2.pdf diff --git a/test/pdf/accessibility/pdf/text_font-embedding.pdf b/test/pdf/accessibility/pdf/text_font-embedding.pdf Binary files differindex 47ca60bdb..e7f75b5a3 100644 --- a/test/pdf/accessibility/pdf/text_font-embedding.pdf +++ b/test/pdf/accessibility/pdf/text_font-embedding.pdf diff --git a/test/pdf/accessibility/pdf/th_scope.pdf b/test/pdf/accessibility/pdf/th_scope.pdf Binary files differindex 27159520b..9d19548d7 100644 --- a/test/pdf/accessibility/pdf/th_scope.pdf +++ b/test/pdf/accessibility/pdf/th_scope.pdf |