diff options
-rw-r--r-- | src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java | 52 | ||||
-rw-r--r-- | status.xml | 16 | ||||
-rw-r--r-- | test/layoutengine/hyphenation-testcases/block_hyphenation_kerning.xml | 60 |
3 files changed, 117 insertions, 11 deletions
diff --git a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java index 1582ea30d..159ece158 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java @@ -106,12 +106,17 @@ public class TextLayoutManager extends LeafNodeLayoutManager { /** Non-space characters on which we can end a line. */ private static final String BREAK_CHARS = "-/"; + /** Used to reduce instantiation of MinOptMax with zero length. Do not modify! */ + private static final MinOptMax ZERO_MINOPTMAX = new MinOptMax(0); + private FOText foText; private char[] textArray; - /** Contains an array of widths to adjust for kerning and letter spacing */ + /** + * Contains an array of widths to adjust for kerning. The first entry can + * be used to influence the start position of the first letter. The entry i+1 defines the + * cursor advancement after the character i. A null entry means no special advancement. + */ private MinOptMax[] letterAdjustArray; //size = textArray.length + 1 - /** The sum of all entries in the letterAdjustArray */ - private MinOptMax totalLetterAdjust = new MinOptMax(0); private static final char NEWLINE = '\n'; @@ -310,8 +315,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager { iLScount--; } - for (int i = ai.iStartIndex + 1; i < ai.iBreakIndex + 1; i++) { - MinOptMax ladj = letterAdjustArray[i]; + for (int i = ai.iStartIndex; i < ai.iBreakIndex; i++) { + MinOptMax ladj = letterAdjustArray[i + 1]; if (ladj != null && ladj.isElastic()) { iLScount++; } @@ -466,8 +471,10 @@ public class TextLayoutManager extends LeafNodeLayoutManager { int[] letterAdjust = new int[wordChars.length()]; int lsCount = areaInfo.iLScount; for (int letter = 0; letter < len; letter++) { - MinOptMax adj = letterAdjustArray[letter + wordStartIndex + 1]; - letterAdjust[letter] = (adj != null ? adj.opt : 0); + MinOptMax adj = letterAdjustArray[letter + wordStartIndex]; + if (letter > 0) { + letterAdjust[letter] = (adj != null ? adj.opt : 0); + } if (lsCount > 0) { letterAdjust[letter] += textArea.getTextLetterSpaceAdjust(); lsCount--; @@ -492,7 +499,6 @@ public class TextLayoutManager extends LeafNodeLayoutManager { } else { letterAdjustArray[index].add(width); } - totalLetterAdjust.add(width); } private void addToLetterAdjust(int index, MinOptMax width) { @@ -501,7 +507,6 @@ public class TextLayoutManager extends LeafNodeLayoutManager { } else { letterAdjustArray[index].add(width); } - totalLetterAdjust.add(width); } /** @@ -625,7 +630,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager { char previous = textArray[i - 1]; kern = font.getKernValue(previous, c) * font.getFontSize() / 1000; if (kern != 0) { - addToLetterAdjust(i + 1, kern); + //log.info("Kerning between " + previous + " and " + c + ": " + kern); + addToLetterAdjust(i, kern); } wordIPD.add(kern); } @@ -761,9 +767,22 @@ public class TextLayoutManager extends LeafNodeLayoutManager { hc.updateOffset(iStopIndex - iStartIndex); + //log.info("Word: " + new String(textArray, iStartIndex, iStopIndex - iStartIndex)); for (int i = iStartIndex; i < iStopIndex; i++) { char c = textArray[i]; newIPD.add(new MinOptMax(font.getCharWidth(c))); + //if (i > iStartIndex) { + if (i < iStopIndex) { + MinOptMax la = this.letterAdjustArray[i + 1]; + if ((i == iStopIndex - 1) && bHyphenFollows) { + //the letter adjust here needs to be handled further down during + //element generation because it depends on hyph/no-hyph condition + la = null; + } + if (la != null) { + newIPD.add(la); + } + } } // add letter spaces boolean bIsWordEnd @@ -854,6 +873,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { iReturnedIndex++; } // end of while setFinished(true); + //ElementListObserver.observe(returnList, "text-changed", null); return returnList; } @@ -1152,10 +1172,17 @@ public class TextLayoutManager extends LeafNodeLayoutManager { // extra-elements if the word fragment is the end of a syllable, // or it ends with a character that can be used as a line break if (ai.bHyphenated) { + MinOptMax widthIfNoBreakOccurs = null; + if (ai.iBreakIndex < textArray.length) { + //Add in kerning in no-break condition + widthIfNoBreakOccurs = letterAdjustArray[ai.iBreakIndex]; + } + //if (ai.iBreakIndex) + // the word fragment ends at the end of a syllable: // if a break occurs the content width increases, // otherwise nothing happens - wordElements.addAll(createElementsForAHyphen(alignment, hyphIPD, new MinOptMax(0))); + wordElements.addAll(createElementsForAHyphen(alignment, hyphIPD, widthIfNoBreakOccurs)); } else if (bSuppressibleLetterSpace) { // the word fragment ends with a character that acts as a hyphen // if a break occurs the width does not increase, @@ -1167,6 +1194,9 @@ public class TextLayoutManager extends LeafNodeLayoutManager { private LinkedList createElementsForAHyphen(int alignment, int widthIfBreakOccurs, MinOptMax widthIfNoBreakOccurs) { + if (widthIfNoBreakOccurs == null) { + widthIfNoBreakOccurs = ZERO_MINOPTMAX; + } LinkedList hyphenElements = new LinkedList(); switch (alignment) { diff --git a/status.xml b/status.xml index 7848f22f5..765a0fcc4 100644 --- a/status.xml +++ b/status.xml @@ -27,6 +27,22 @@ <changes> <release version="FOP Trunk"> + <action context="Code" dev="JM" type="fix"> + Bugfix: The combination of hyphenation and kerning resulted in slightly ragged + right ends for right-aligned and justified text. + </action> + <action context="Code" dev="JM" type="fix"> + Bugfix: NullPointerException in AreaAdditionUtil in a table-cell spanning + multiple pages and with a marker. + </action> + <action context="Code" dev="JM" type="fix" fixes-bug="39533"> + Bugfix: NullPointerException in RTF output when a table does not contain + table-columns. + </action> + <action context="Code" dev="JM" type="fix" fixes-bug="39607" due-to="Julien Aymé"> + Bugfix: NullPointerException in RTF library when there are no borders on + the parent table. + </action> <action context="Code" dev="JM" type="add"> Automatic support for all fonts available to the Java2D subsystem for all Java2D-descendant renderers (TIFF, PNG, print, AWT). diff --git a/test/layoutengine/hyphenation-testcases/block_hyphenation_kerning.xml b/test/layoutengine/hyphenation-testcases/block_hyphenation_kerning.xml new file mode 100644 index 000000000..5ee6c9b68 --- /dev/null +++ b/test/layoutengine/hyphenation-testcases/block_hyphenation_kerning.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2006 The Apache Software Foundation + + Licensed 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$ --> +<testcase> + <info> + <p> + Checks hyphenation in combination with kerning. + </p> + </info> + <cfg> + <base14kerning>true</base14kerning> + </cfg> + <fo> + <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" language="en" hyphenate="true"> + <fo:layout-master-set> + <fo:simple-page-master master-name="simple" page-height="5in" page-width="5in"> + <fo:region-body/> + </fo:simple-page-master> + </fo:layout-master-set> + <fo:page-sequence master-reference="simple"> + <fo:flow flow-name="xsl-region-body"> + <fo:block font-size="20pt" line-height="1.0" text-align="justify" text-align-last="justify" background-color="lightgray" start-indent="10pt" end-indent="10pt" border="solid 1pt"> + hyphenation regression advantage foundation vandalism AVAVAVA vandavanda + hyphenation regression advantage foundation vandalism AVAVAVA vandavanda + hyphenation regression + </fo:block> + </fo:flow> + </fo:page-sequence> + </fo:root> + </fo> + <checks> + <eval expected="1" xpath="count(//pageViewport)"/> + + <eval expected="17230" xpath="//flow/block[1]/lineArea[1]/text[1]/@twsadjust"/> + <eval expected="-1339" xpath="//flow/block[1]/lineArea[2]/text[1]/@twsadjust"/> + <eval expected="2393" xpath="//flow/block[1]/lineArea[3]/text[1]/@twsadjust"/> + <eval expected="5900" xpath="//flow/block[1]/lineArea[4]/text[1]/@twsadjust"/> + <eval expected="9900" xpath="//flow/block[1]/lineArea[5]/text[1]/@twsadjust"/> + + <!-- In no-break condition there's a -400 kerning between a and v. It musn't occur if "vandavanda" is hyphenated. --> + <eval expected="vanda-" xpath="//flow/block[1]/lineArea[2]/text[1]/word[4]"/> + <eval expected="0 -500 0 0 0 0" xpath="//flow/block[1]/lineArea[2]/text[1]/word[4]/@letter-adjust"/> + <eval expected="vanda" xpath="//flow/block[1]/lineArea[3]/text[1]/word[1]"/> + <eval expected="0 -500 0 0 0" xpath="//flow/block[1]/lineArea[3]/text[1]/word[1]/@letter-adjust"/> + </checks> +</testcase> |