aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdrian Cumiskey <acumiskey@apache.org>2008-06-02 14:05:52 +0000
committerAdrian Cumiskey <acumiskey@apache.org>2008-06-02 14:05:52 +0000
commit92f144a66ef5f789019687047756ac870782ef0a (patch)
tree4e0801a4aa22a7c876f1633b22f723e472b7f34f /src
parentdf16894515e5927bc1442225fb0210d2db4c11c9 (diff)
downloadxmlgraphics-fop-92f144a66ef5f789019687047756ac870782ef0a.tar.gz
xmlgraphics-fop-92f144a66ef5f789019687047756ac870782ef0a.zip
Merged revisions 660979,660998,661276,661310,661999,662009,662203 via svnmerge from
https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk ........ r660979 | vhennebert | 2008-05-28 16:24:23 +0100 (Wed, 28 May 2008) | 3 lines Bugzilla 37579: added support for footnotes in lists and table bodies (not header nor footer). This is /not/ to be considered a final fix: similar code is duplicated over several classes (LineLayoutManager, ListItemLayoutManager and to less extent TableStepper). Footnotes should probably be handled another way. ........ r660998 | maxberger | 2008-05-28 17:10:32 +0100 (Wed, 28 May 2008) | 1 line Implemented Font auto-selection word-by-word ........ r661276 | vhennebert | 2008-05-29 10:58:06 +0100 (Thu, 29 May 2008) | 2 lines Set svn:keywords and svn:eol-style properties for files added in revision 660998 ........ r661310 | maxberger | 2008-05-29 13:03:48 +0100 (Thu, 29 May 2008) | 1 line Added docs for my recent commit (word-by-word character selection) ........ r661999 | adelmelle | 2008-05-31 11:56:05 +0100 (Sat, 31 May 2008) | 3 lines Bugzilla 45097: Leading/trailing white-space not removed from nested inline-content when there is no preceding/following text. ........ r662009 | maxberger | 2008-05-31 12:45:55 +0100 (Sat, 31 May 2008) | 1 line Code Cleanups (no functional change) ........ r662203 | maxberger | 2008-06-01 12:57:33 +0100 (Sun, 01 Jun 2008) | 1 line More code Cleanups (no functional changes) ........ git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AFPGOCAResources@662442 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
-rw-r--r--src/documentation/content/xdocs/trunk/fonts.xml50
-rw-r--r--src/java/org/apache/fop/fo/FOText.java2
-rw-r--r--src/java/org/apache/fop/fo/XMLWhiteSpaceHandler.java144
-rw-r--r--src/java/org/apache/fop/fonts/FontSelector.java142
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java32
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java1223
-rw-r--r--src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java30
-rw-r--r--src/java/org/apache/fop/layoutmgr/table/ActiveCell.java25
-rw-r--r--src/java/org/apache/fop/layoutmgr/table/TableStepper.java11
9 files changed, 922 insertions, 737 deletions
diff --git a/src/documentation/content/xdocs/trunk/fonts.xml b/src/documentation/content/xdocs/trunk/fonts.xml
index 30b72ffac..e713fe08a 100644
--- a/src/documentation/content/xdocs/trunk/fonts.xml
+++ b/src/documentation/content/xdocs/trunk/fonts.xml
@@ -22,7 +22,7 @@
<title>Apache FOP: Fonts</title>
<version>$Revision$</version>
<authors>
- <person name="Jeremias Märki" email=""/>
+ <person name="Jeremias M&#xE4;rki" email=""/>
<person name="Tore Engvig" email=""/>
<person name="Adrian Cumiskey" email=""/>
<person name="Max Berger" email=""/>
@@ -96,14 +96,14 @@
<td>yes (used for layout but not for output)</td>
<td>no</td>
</tr>
- <!--tr> NOT AVAILABLE
+<!--tr> NOT AVAILABLE
<td>MIF</td>
<td>n/a (font metrics not needed)</td>
<td>n/a</td>
<td>n/a</td>
<td>n/a</td>
</tr-->
- <!--tr> NOT AVAILABLE
+<!--tr> NOT AVAILABLE
<td>SVG</td>
<td>if available from OS</td>
<td>yes</td>
@@ -163,7 +163,6 @@
PDF or PostScript.
</p>
</section>
-
<section id="custom">
<title>Custom Fonts</title>
<p>
@@ -184,11 +183,14 @@
Basic information about fonts can be found at:
</p>
<ul>
- <li><a href="http://partners.adobe.com/asn/developer/type/ftypes.html">Adobe font types</a></li>
- <li><a href="http://partners.adobe.com/asn/developer/technotes/fonts.html">Adobe Font Technote</a></li>
+ <li>
+ <a href="http://partners.adobe.com/asn/developer/type/ftypes.html">Adobe font types</a>
+ </li>
+ <li>
+ <a href="http://partners.adobe.com/asn/developer/technotes/fonts.html">Adobe Font Technote</a>
+ </li>
</ul>
</section>
-
<section id="basics">
<title>Basic font configuration</title>
<p>
@@ -220,7 +222,6 @@
not possible to easily configure fonts from Java code.
</note>
</section>
-
<section id="advanced">
<title>Advanced font configuration</title>
<p>
@@ -359,7 +360,7 @@
relative to the base directory.
</li>
</ul>
- <!--note>Cocoon users will need to setup the config, see FOPSerializer for more information.</note-->
+<!--note>Cocoon users will need to setup the config, see FOPSerializer for more information.</note-->
</section>
<section id="autodetect">
<title>Auto-Detect and auto-embed feature</title>
@@ -425,14 +426,14 @@
</ul>
</section>
<section id="substitution">
- <title>Substitution</title>
- <p>When a &lt;substitutions/&gt; section is defined in the configuration, FOP will re-map any font-family references found in your FO input to a given substitution font.</p>
- <ul>
- <li>If a &lt;substitution/&gt; is declared, it is mandatory that both a &lt;from/&gt; and &lt;to/&gt; child element is declared with a font-family attribute.</li>
- <li>Both font-weight and font-style are optional attributes, if they are provided then a value of 'normal' is assumed.</li>
- </ul>
- <p>For example you could make all FO font-family references to 'Arial' with weights between 700 and 900 reference the normal 'Arial Black' font.</p>
- <source><![CDATA[
+ <title>Substitution</title>
+ <p>When a &lt;substitutions/&gt; section is defined in the configuration, FOP will re-map any font-family references found in your FO input to a given substitution font.</p>
+ <ul>
+ <li>If a &lt;substitution/&gt; is declared, it is mandatory that both a &lt;from/&gt; and &lt;to/&gt; child element is declared with a font-family attribute.</li>
+ <li>Both font-weight and font-style are optional attributes, if they are provided then a value of 'normal' is assumed.</li>
+ </ul>
+ <p>For example you could make all FO font-family references to 'Arial' with weights between 700 and 900 reference the normal 'Arial Black' font.</p>
+ <source><![CDATA[
<fop version="1.0">
<fonts>
<substitutions>
@@ -448,7 +449,7 @@
</fonts>
</fop>]]></source>
</section>
- <!-- The following section should no longer be required
+<!-- The following section should no longer be required
<section id="embedding-base14">
<title>Explicitly embedding the base 14 fonts</title>
<p>
@@ -474,5 +475,18 @@
[..]]]></source>
</section-->
</section>
+ <section id="selection">
+ <title>Font Selection Strategies</title>
+ <p>
+ There are two font selection strategies: character-by-character or auto. The default is auto.</p>
+ <p>Auto selected the first font from the list which is able to display the most characters in a given word. This means (assume font A has characters for abclmn, font B for lnmxyz, fontlist is A,B):</p>
+ <ul>
+ <li>aaa lll xxx would be displayed in fonts A A B</li>
+ <li>aaaxx would be displayed in font A</li>
+ <li>aaaxxx would be displayed in font A</li>
+ <li>aaaxxxx would be displayed in font B</li>
+ </ul>
+ <p>Character-by-Character is NOT yet supported!</p>
+ </section>
</body>
</document>
diff --git a/src/java/org/apache/fop/fo/FOText.java b/src/java/org/apache/fop/fo/FOText.java
index 8c85bb039..f21386075 100644
--- a/src/java/org/apache/fop/fo/FOText.java
+++ b/src/java/org/apache/fop/fo/FOText.java
@@ -37,7 +37,7 @@ import org.apache.fop.fo.properties.SpaceProperty;
/**
* A text node (PCDATA) in the formatting object tree.
*
- * Unfortunately the BufferManager implementatation holds
+ * Unfortunately the BufferManager implementation holds
* onto references to the character data in this object
* longer than the lifetime of the object itself, causing
* excessive memory consumption and OOM errors.
diff --git a/src/java/org/apache/fop/fo/XMLWhiteSpaceHandler.java b/src/java/org/apache/fop/fo/XMLWhiteSpaceHandler.java
index 557a1778e..d8915b124 100644
--- a/src/java/org/apache/fop/fo/XMLWhiteSpaceHandler.java
+++ b/src/java/org/apache/fop/fo/XMLWhiteSpaceHandler.java
@@ -87,39 +87,49 @@ public class XMLWhiteSpaceHandler {
* @param nextChild the node that will be added to the list
* after firstTextNode
*/
- public void handleWhiteSpace(FObjMixed fo, FONode firstTextNode, FONode nextChild) {
-
+ public void handleWhiteSpace(FObjMixed fo,
+ FONode firstTextNode,
+ FONode nextChild) {
+
Block currentBlock = null;
int foId = fo.getNameId();
- if (foId == Constants.FO_BLOCK) {
- currentBlock = (Block) fo;
- if (nestedBlockStack.isEmpty() || fo != nestedBlockStack.peek()) {
- if (nextChild != null) {
- /* if already in a block, push the current block
- * onto the stack of nested blocks
- */
- nestedBlockStack.push(currentBlock);
+ /* set the current block */
+ switch (foId) {
+ case Constants.FO_BLOCK:
+ currentBlock = (Block) fo;
+ if (nestedBlockStack.empty() || fo != nestedBlockStack.peek()) {
+ if (nextChild != null) {
+ /* if already in a block, push the current block
+ * onto the stack of nested blocks
+ */
+ nestedBlockStack.push(currentBlock);
+ }
+ } else {
+ if (nextChild == null) {
+ nestedBlockStack.pop();
+ }
}
- } else {
- if (nextChild == null) {
- nestedBlockStack.pop();
+ break;
+
+ case Constants.FO_RETRIEVE_MARKER:
+ /* look for the nearest block ancestor, if any */
+ FONode ancestor = fo;
+ do {
+ ancestor = ancestor.getParent();
+ } while (ancestor.getNameId() != Constants.FO_BLOCK
+ && ancestor.getNameId() != Constants.FO_STATIC_CONTENT);
+
+ if (ancestor.getNameId() == Constants.FO_BLOCK) {
+ currentBlock = (Block) ancestor;
+ nestedBlockStack.push(currentBlock);
}
- }
- } else if (foId == Constants.FO_RETRIEVE_MARKER) {
- /* look for the nearest block ancestor, if any */
- FONode ancestor = fo;
- do {
- ancestor = ancestor.getParent();
- } while (ancestor.getNameId() != Constants.FO_BLOCK
- && ancestor.getNameId() != Constants.FO_STATIC_CONTENT);
+ break;
- if (ancestor.getNameId() == Constants.FO_BLOCK) {
- currentBlock = (Block) ancestor;
- nestedBlockStack.push(currentBlock);
- }
- } else if (!nestedBlockStack.isEmpty()) {
- currentBlock = (Block) nestedBlockStack.peek();
+ default:
+ if (!nestedBlockStack.empty()) {
+ currentBlock = (Block) nestedBlockStack.peek();
+ }
}
if (currentBlock != null) {
@@ -132,8 +142,15 @@ public class XMLWhiteSpaceHandler {
whiteSpaceTreatment = Constants.EN_IGNORE_IF_SURROUNDING_LINEFEED;
}
+ endOfBlock = (nextChild == null && fo == currentBlock);
+
if (firstTextNode == null) {
- //nothing to do but initialize related properties
+ //no text means no white-space to handle; return early
+ afterLinefeed = (fo == currentBlock && fo.firstChild == null);
+ nonWhiteSpaceCount = 0;
+ if (endOfBlock) {
+ handlePendingInlines();
+ }
return;
}
@@ -144,13 +161,32 @@ public class XMLWhiteSpaceHandler {
|| currentBlock == null
|| (foId == Constants.FO_RETRIEVE_MARKER
&& fo.getParent() == currentBlock)) {
- afterLinefeed = (
- (firstTextNode == fo.firstChild)
- || (firstTextNode.siblings[0].getNameId()
- == Constants.FO_BLOCK));
+ if (firstTextNode == fo.firstChild) {
+ afterLinefeed = true;
+ } else {
+ int previousChildId = firstTextNode.siblings[0].getNameId();
+ afterLinefeed = (previousChildId == Constants.FO_BLOCK
+ || previousChildId == Constants.FO_TABLE_AND_CAPTION
+ || previousChildId == Constants.FO_TABLE
+ || previousChildId == Constants.FO_LIST_BLOCK
+ || previousChildId == Constants.FO_BLOCK_CONTAINER);
+ }
}
- endOfBlock = (nextChild == null && fo == currentBlock);
+ if (foId == Constants.FO_WRAPPER) {
+ FONode parent = fo.parent;
+ int parentId = parent.getNameId();
+ while (parentId == Constants.FO_WRAPPER) {
+ parent = parent.parent;
+ parentId = parent.getNameId();
+ }
+ if (parentId == Constants.FO_FLOW
+ || parentId == Constants.FO_STATIC_CONTENT
+ || parentId == Constants.FO_BLOCK_CONTAINER
+ || parentId == Constants.FO_TABLE_CELL) {
+ endOfBlock = (nextChild == null);
+ }
+ }
if (nextChild != null) {
int nextChildId = nextChild.getNameId();
@@ -167,26 +203,8 @@ public class XMLWhiteSpaceHandler {
handleWhiteSpace();
if (fo == currentBlock
- && pendingInlines != null
- && !pendingInlines.isEmpty()) {
- /* current FO is a block, and has pending inlines */
- if (endOfBlock || nextChildIsBlockLevel) {
- if (nonWhiteSpaceCount == 0) {
- /* handle white-space for all pending inlines*/
- PendingInline p;
- for (int i = pendingInlines.size(); --i >= 0;) {
- p = (PendingInline)pendingInlines.get(i);
- charIter = (RecursiveCharIterator)p.firstTrailingWhiteSpace;
- handleWhiteSpace();
- pendingInlines.remove(p);
- }
- } else {
- /* there is non-white-space text between the pending
- * inline(s) and the end of the block;
- * clear list of pending inlines */
- pendingInlines.clear();
- }
- }
+ && (endOfBlock || nextChildIsBlockLevel)) {
+ handlePendingInlines();
}
if (nextChild == null) {
@@ -333,6 +351,26 @@ public class XMLWhiteSpaceHandler {
pendingInlines.add(new PendingInline(fo, firstWhiteSpaceInSeq));
}
+ private void handlePendingInlines() {
+ if (!(pendingInlines == null || pendingInlines.isEmpty())) {
+ if (nonWhiteSpaceCount == 0) {
+ /* handle white-space for all pending inlines*/
+ PendingInline p;
+ for (int i = pendingInlines.size(); --i >= 0;) {
+ p = (PendingInline)pendingInlines.get(i);
+ charIter = (RecursiveCharIterator)p.firstTrailingWhiteSpace;
+ handleWhiteSpace();
+ pendingInlines.remove(p);
+ }
+ } else {
+ /* there is non-white-space text between the pending
+ * inline(s) and the end of the block;
+ * clear list of pending inlines */
+ pendingInlines.clear();
+ }
+ }
+ }
+
/**
* Helper class, used during white-space handling to look ahead, and
* see if the next character is a linefeed (or if there will be
diff --git a/src/java/org/apache/fop/fonts/FontSelector.java b/src/java/org/apache/fop/fonts/FontSelector.java
new file mode 100644
index 000000000..ec5ea26bf
--- /dev/null
+++ b/src/java/org/apache/fop/fonts/FontSelector.java
@@ -0,0 +1,142 @@
+/*
+ * 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.fonts;
+
+import org.apache.fop.datatypes.PercentBaseContext;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.FOText;
+import org.apache.fop.fo.flow.Character;
+import org.apache.fop.fo.properties.CommonFont;
+
+/**
+ * Helper class for automatic font selection.
+ * <p>
+ * TODO: Check if this could be merged with another font class, such as
+ * {@link FontManager}.
+ */
+public final class FontSelector {
+ private FontSelector() {
+ // Static since this is an utility class.
+ }
+
+ private static Font selectFontForCharacter(char c, FONode fonode,
+ CommonFont commonFont, PercentBaseContext context) {
+ FontInfo fi = fonode.getFOEventHandler().getFontInfo();
+ FontTriplet[] fontkeys = commonFont.getFontState(fi);
+ for (int i = 0; i < fontkeys.length; i++) {
+ Font font = fi.getFontInstance(fontkeys[i], commonFont.fontSize
+ .getValue(context));
+ if (font.hasChar(c)) {
+ return font;
+ }
+ }
+ return fi.getFontInstance(fontkeys[0], commonFont.fontSize
+ .getValue(context));
+
+ }
+
+ /**
+ * Selects a font which is able to display the given character.
+ *
+ * @param fobj
+ * a Character object containing the character and its
+ * attributes.
+ * @param context
+ * the Percent-based context needed for creating the actual font.
+ * @return a Font object.
+ */
+ public static Font selectFontForCharacter(Character fobj,
+ PercentBaseContext context) {
+ return FontSelector.selectFontForCharacter(fobj.getCharacter(), fobj,
+ fobj.getCommonFont(), context);
+ }
+
+ /**
+ * Selects a font which is able to display the given character.
+ *
+ * @param c
+ * character to find.
+ * @param text
+ * the text object which contains the character
+ * @param context
+ * the Percent-based context needed for creating the actual font.
+ * @return a Font object.
+ */
+ public static Font selectFontForCharacterInText(char c, FOText text,
+ PercentBaseContext context) {
+ return FontSelector.selectFontForCharacter(c, text, text
+ .getCommonFont(), context);
+ }
+
+ /**
+ * Selects a font which is able to display the most of the given characters.
+ *
+ * @param textArray
+ * Text to go through
+ * @param firstIndex
+ * first index within text.
+ * @param breakIndex
+ * last index +1 within text.
+ * @param text
+ * the text object which contains the character
+ * @param context
+ * the Percent-based context needed for creating the actual font.
+ * @return a Font object.
+ */
+ public static Font selectFontForCharactersInText(char[] textArray,
+ int firstIndex, int breakIndex, FOText text,
+ PercentBaseContext context) {
+ final FontInfo fi = text.getFOEventHandler().getFontInfo();
+ final CommonFont commonFont = text.getCommonFont();
+ final FontTriplet[] fontkeys = commonFont.getFontState(fi);
+ final int numFonts = fontkeys.length;
+ final Font[] fonts = new Font[numFonts];
+ final int[] fontCount = new int[numFonts];
+
+ for (int fontnum = 0; fontnum < numFonts; fontnum++) {
+ final Font font = fi.getFontInstance(fontkeys[fontnum],
+ commonFont.fontSize.getValue(context));
+ fonts[fontnum] = font;
+ for (int pos = firstIndex; pos < breakIndex; pos++) {
+ if (font.hasChar(textArray[pos])) {
+ fontCount[fontnum]++;
+ }
+ }
+
+ // quick fall through if all characters can be displayed
+ if (fontCount[fontnum] == (breakIndex - firstIndex)) {
+ return font;
+ }
+ }
+
+ Font font = fonts[0];
+ int max = fontCount[0];
+
+ for (int fontnum = 1; fontnum < numFonts; fontnum++) {
+ final int curCount = fontCount[fontnum];
+ if (curCount > max) {
+ font = fonts[fontnum];
+ max = curCount;
+ }
+ }
+ return font;
+ }
+
+}
diff --git a/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java
index b292d97bf..a6f9be7af 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java
@@ -26,8 +26,7 @@ import org.apache.fop.area.Trait;
import org.apache.fop.fo.flow.Character;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fonts.Font;
-import org.apache.fop.fonts.FontInfo;
-import org.apache.fop.fonts.FontTriplet;
+import org.apache.fop.fonts.FontSelector;
import org.apache.fop.layoutmgr.InlineKnuthSequence;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthGlue;
@@ -62,7 +61,7 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager {
/** {@inheritDoc} */
public void initialize() {
Character fobj = (Character)this.fobj;
- font = this.selectFontForCharacter(fobj);
+ font = FontSelector.selectFontForCharacter(fobj, this);
SpaceVal ls = SpaceVal.makeLetterSpacing(fobj.getLetterSpacing());
letterSpaceIPD = ls.getSpace();
hyphIPD = fobj.getCommonHyphenation().getHyphIPD(font);
@@ -72,33 +71,6 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager {
chArea.setBaselineOffset(font.getAscender());
setCurrentArea(chArea);
}
-
- /**
- * Selects a font which is able to display the given character.
- * <p>
- * Please note: this implements the font-selection-strategy
- * character-by-character.
- * <p>
- * TODO: The same function could apply to other elements as well.
- *
- * @param fobj
- * a Character object containing the character and its
- * attributed.
- * @return a Font object.
- */
- private Font selectFontForCharacter(Character fobj) {
- FontInfo fi = fobj.getFOEventHandler().getFontInfo();
- FontTriplet[] fontkeys = fobj.getCommonFont().getFontState(fi);
- for (int i = 0; i < fontkeys.length; i++) {
- font = fi.getFontInstance(fontkeys[i],
- fobj.getCommonFont().fontSize.getValue(this));
- if (font.hasChar(fobj.getCharacter())) {
- return font;
- }
- }
- return fi.getFontInstance(fontkeys[0],
- fobj.getCommonFont().fontSize.getValue(this));
- }
private org.apache.fop.area.inline.TextArea getCharacterInlineArea(Character node) {
org.apache.fop.area.inline.TextArea text
diff --git a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
index be8a13d50..6ae909cd7 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
@@ -5,9 +5,9 @@
* 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.
@@ -19,7 +19,6 @@
package org.apache.fop.layoutmgr.inline;
-import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
@@ -31,8 +30,7 @@ import org.apache.fop.area.inline.TextArea;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FOText;
import org.apache.fop.fonts.Font;
-import org.apache.fop.fonts.FontInfo;
-import org.apache.fop.fonts.FontTriplet;
+import org.apache.fop.fonts.FontSelector;
import org.apache.fop.layoutmgr.InlineKnuthSequence;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
@@ -62,23 +60,25 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
* Number of word-spaces?
*/
private class AreaInfo {
- private short startIndex;
- private short breakIndex;
- private short wordSpaceCount;
+ private final short startIndex;
+ private final short breakIndex;
+ private final short wordSpaceCount;
private short letterSpaceCount;
- private MinOptMax areaIPD;
- private boolean isHyphenated;
- private boolean isSpace;
+ private final MinOptMax areaIPD;
+ private final boolean isHyphenated;
+ private final boolean isSpace;
private boolean breakOppAfter;
-
- AreaInfo(short startIndex,
- short breakIndex,
- short wordSpaceCount,
- short letterSpaceCount,
- MinOptMax areaIPD,
- boolean isHyphenated,
- boolean isSpace,
- boolean breakOppAfter) {
+ private final Font font;
+
+ AreaInfo(final short startIndex,
+ final short breakIndex,
+ final short wordSpaceCount,
+ final short letterSpaceCount,
+ final MinOptMax areaIPD,
+ final boolean isHyphenated,
+ final boolean isSpace,
+ final boolean breakOppAfter,
+ final Font font) {
this.startIndex = startIndex;
this.breakIndex = breakIndex;
this.wordSpaceCount = wordSpaceCount;
@@ -87,16 +87,18 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
this.isHyphenated = isHyphenated;
this.isSpace = isSpace;
this.breakOppAfter = breakOppAfter;
+ this.font = font;
}
public String toString() {
- return "[ lscnt=" + letterSpaceCount
- + ", wscnt=" + wordSpaceCount
- + ", ipd=" + areaIPD.toString()
- + ", sidx=" + startIndex
- + ", bidx=" + breakIndex
- + ", hyph=" + isHyphenated
- + ", space=" + isSpace
+ return "[ lscnt=" + this.letterSpaceCount
+ + ", wscnt=" + this.wordSpaceCount
+ + ", ipd=" + this.areaIPD.toString()
+ + ", sidx=" + this.startIndex
+ + ", bidx=" + this.breakIndex
+ + ", hyph=" + this.isHyphenated
+ + ", space=" + this.isSpace
+ + ", font=" + this.font
+ "]";
}
@@ -104,11 +106,11 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
// this class stores information about changes in vecAreaInfo
// which are not yet applied
- private class PendingChange {
- public AreaInfo ai;
- public int index;
+ private final class PendingChange {
+ private final AreaInfo ai;
+ private final int index;
- public PendingChange(AreaInfo ai, int index) {
+ private PendingChange(final AreaInfo ai, final int index) {
this.ai = ai;
this.index = index;
}
@@ -117,10 +119,10 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
/**
* logging instance
*/
- private static Log log = LogFactory.getLog(TextLayoutManager.class);
+ private static final Log LOG = LogFactory.getLog(TextLayoutManager.class);
// Hold all possible breaks for the text in this LM's FO.
- private ArrayList vecAreaInfo;
+ private final List vecAreaInfo;
/** Non-space characters on which we can end a line. */
private static final String BREAK_CHARS = "-/";
@@ -128,18 +130,19 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
/** 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;
+ private final FOText foText;
+ private final char[] textArray;
/**
* 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
+ private final MinOptMax[] letterAdjustArray; //size = textArray.length + 1
private static final char NEWLINE = '\n';
- private Font font = null;
+ /** Font used for the space between words. */
+ private Font spaceFont = null;
/** Start index of next TextArea */
private short nextStart = 0;
/** size of a space character (U+0020) glyph in current font */
@@ -150,16 +153,12 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
private int hyphIPD;
/** 1/1 of word-spacing value */
private SpaceVal ws;
- /** 1/2 of word-spacing value */
- private SpaceVal halfWS;
- /** 1/2 of letter-spacing value */
- private SpaceVal halfLS;
private boolean hasChanged = false;
private int returnedIndex = 0;
private short thisStart = 0;
private short tempStart = 0;
- private LinkedList changeList = null;
+ private List changeList = null;
private AlignmentContext alignmentContext = null;
@@ -175,24 +174,24 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
*
* @param node The FOText object to be rendered
*/
- public TextLayoutManager(FOText node) {
+ public TextLayoutManager(final FOText node) {
super();
- foText = node;
+ this.foText = node;
- textArray = new char[node.endIndex - node.startIndex];
- System.arraycopy(node.ca, node.startIndex, textArray, 0,
+ this.textArray = new char[node.endIndex - node.startIndex];
+ System.arraycopy(node.ca, node.startIndex, this.textArray, 0,
node.endIndex - node.startIndex);
- letterAdjustArray = new MinOptMax[textArray.length + 1];
+ this.letterAdjustArray = new MinOptMax[this.textArray.length + 1];
- vecAreaInfo = new java.util.ArrayList();
+ this.vecAreaInfo = new java.util.ArrayList();
}
- private KnuthPenalty makeZeroWidthPenalty(int penaltyValue) {
+ private KnuthPenalty makeZeroWidthPenalty(final int penaltyValue) {
return new KnuthPenalty(
0,
penaltyValue,
false,
- auxiliaryPosition,
+ this.auxiliaryPosition,
true);
}
@@ -200,29 +199,25 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
return new KnuthInlineBox(
0,
null,
- notifyPos(new LeafPosition(this, -1)),
+ this.notifyPos(new LeafPosition(this, -1)),
true);
}
/** {@inheritDoc} */
public void initialize() {
- FontInfo fi = foText.getFOEventHandler().getFontInfo();
- FontTriplet[] fontkeys = foText.getCommonFont().getFontState(fi);
- font = fi.getFontInstance(fontkeys[0], foText.getCommonFont().fontSize.getValue(this));
+
+ this.spaceFont = FontSelector.selectFontForCharacterInText(' ', this.foText, this);
// With CID fonts, space isn't neccesary currentFontState.width(32)
- spaceCharIPD = font.getCharWidth(' ');
+ this.spaceCharIPD = this.spaceFont.getCharWidth(' ');
// Use hyphenationChar property
- hyphIPD = foText.getCommonHyphenation().getHyphIPD(font);
- SpaceVal ls = SpaceVal.makeLetterSpacing(foText.getLetterSpacing());
- halfLS = new SpaceVal(MinOptMax.multiply(ls.getSpace(), 0.5),
- ls.isConditional(), ls.isForcing(), ls.getPrecedence());
+ // TODO: Use hyphen based on actual font used!
+ this.hyphIPD = this.foText.getCommonHyphenation().getHyphIPD(this.spaceFont);
+
+ final SpaceVal ls = SpaceVal.makeLetterSpacing(this.foText.getLetterSpacing());
- ws = SpaceVal.makeWordSpacing(foText.getWordSpacing(), ls, font);
- // Make half-space: <space> on either side of a word-space)
- halfWS = new SpaceVal(MinOptMax.multiply(ws.getSpace(), 0.5),
- ws.isConditional(), ws.isForcing(), ws.getPrecedence());
+ this.ws = SpaceVal.makeWordSpacing(this.foText.getWordSpacing(), ls, this.spaceFont);
// letter space applies only to consecutive non-space characters,
// while word space applies to space characters;
@@ -235,10 +230,11 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
// set letter space and word space dimension;
// the default value "normal" was converted into a MinOptMax value
// in the SpaceVal.makeWordSpacing() method
- letterSpaceIPD = ls.getSpace();
- wordSpaceIPD = MinOptMax.add(new MinOptMax(spaceCharIPD), ws.getSpace());
+ this.letterSpaceIPD = ls.getSpace();
+ this.wordSpaceIPD = MinOptMax.add(new MinOptMax(this.spaceCharIPD), this.ws.getSpace());
- keepTogether = foText.getKeepTogether().getWithinLine().getEnum() == Constants.EN_ALWAYS;
+ this.keepTogether = this.foText.getKeepTogether().getWithinLine()
+ .getEnum() == Constants.EN_ALWAYS;
}
@@ -252,10 +248,10 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
* by this LayoutManager.
* @param context LayoutContext for adjustments
*/
- public void addAreas(PositionIterator posIter, LayoutContext context) {
+ public void addAreas(final PositionIterator posIter, final LayoutContext context) {
// Add word areas
- AreaInfo ai = null;
+ AreaInfo ai;
int wordSpaceCount = 0;
int letterSpaceCount = 0;
int firstAreaInfoIndex = -1;
@@ -265,36 +261,57 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
/* On first area created, add any leading space.
* Calculate word-space stretch value.
*/
+ AreaInfo lastAi = null;
while (posIter.hasNext()) {
- LeafPosition tbpNext = (LeafPosition) posIter.next();
+ final LeafPosition tbpNext = (LeafPosition) posIter.next();
if (tbpNext == null) {
continue; //Ignore elements without Positions
}
if (tbpNext.getLeafPos() != -1) {
- ai = (AreaInfo) vecAreaInfo.get(tbpNext.getLeafPos());
- if (firstAreaInfoIndex == -1) {
+ ai = (AreaInfo) this.vecAreaInfo.get(tbpNext.getLeafPos());
+ if (lastAi == null || ai.font != lastAi.font) {
+ if (lastAi != null) {
+ this.addAreaInfoAreas(lastAi, wordSpaceCount,
+ letterSpaceCount, firstAreaInfoIndex,
+ lastAreaInfoIndex, realWidth, context);
+ }
firstAreaInfoIndex = tbpNext.getLeafPos();
+ wordSpaceCount = 0;
+ letterSpaceCount = 0;
+ realWidth = new MinOptMax(0);
}
wordSpaceCount += ai.wordSpaceCount;
letterSpaceCount += ai.letterSpaceCount;
realWidth.add(ai.areaIPD);
lastAreaInfoIndex = tbpNext.getLeafPos();
+ lastAi = ai;
}
}
- if (ai == null) {
- return;
+ if (lastAi != null) {
+ this.addAreaInfoAreas(lastAi, wordSpaceCount, letterSpaceCount,
+ firstAreaInfoIndex, lastAreaInfoIndex, realWidth, context);
}
- int textLength = ai.breakIndex - ai.startIndex;
+ }
+
+ private void addAreaInfoAreas(final AreaInfo ai, final int wordSpaceCount,
+ int letterSpaceCount, final int firstAreaInfoIndex,
+ final int lastAreaInfoIndex, final MinOptMax realWidth, final LayoutContext context) {
+
+ // TODO: These two statements (if, for) where like this before my recent
+ // changes. However, it seems as if they should use the AreaInfo from
+ // firstAreaInfoIndex.. lastAreaInfoIndex rather than just the last ai.
+ // This needs to be checked.
+ final int textLength = ai.breakIndex - ai.startIndex;
if (ai.letterSpaceCount == textLength && !ai.isHyphenated
&& context.isLastArea()) {
// the line ends at a character like "/" or "-";
// remove the letter space after the last character
- realWidth.add(MinOptMax.multiply(letterSpaceIPD, -1));
+ realWidth.add(MinOptMax.multiply(this.letterSpaceIPD, -1));
letterSpaceCount--;
}
for (int i = ai.startIndex; i < ai.breakIndex; i++) {
- MinOptMax ladj = letterAdjustArray[i + 1];
+ final MinOptMax ladj = this.letterAdjustArray[i + 1];
if (ladj != null && ladj.isElastic()) {
letterSpaceCount++;
}
@@ -302,60 +319,57 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
// add hyphenation character if the last word is hyphenated
if (context.isLastArea() && ai.isHyphenated) {
- realWidth.add(new MinOptMax(hyphIPD));
+ realWidth.add(new MinOptMax(this.hyphIPD));
}
// Calculate adjustments
int difference = 0;
int totalAdjust = 0;
- int wordSpaceDim = wordSpaceIPD.opt;
- int letterSpaceDim = letterSpaceIPD.opt;
- double ipdAdjust = context.getIPDAdjust();
- double dSpaceAdjust = context.getSpaceAdjust(); // not used
+ int wordSpaceDim = this.wordSpaceIPD.opt;
+ int letterSpaceDim = this.letterSpaceIPD.opt;
+ final double ipdAdjust = context.getIPDAdjust();
// calculate total difference between real and available width
if (ipdAdjust > 0.0) {
- difference = (int) ((double) (realWidth.max - realWidth.opt)
+ difference = (int) ((realWidth.max - realWidth.opt)
* ipdAdjust);
} else {
- difference = (int) ((double) (realWidth.opt - realWidth.min)
+ difference = (int) ((realWidth.opt - realWidth.min)
* ipdAdjust);
}
// set letter space adjustment
if (ipdAdjust > 0.0) {
letterSpaceDim
- += (int) ((double) (letterSpaceIPD.max - letterSpaceIPD.opt)
+ += (int) ((this.letterSpaceIPD.max - this.letterSpaceIPD.opt)
* ipdAdjust);
} else {
letterSpaceDim
- += (int) ((double) (letterSpaceIPD.opt - letterSpaceIPD.min)
+ += (int) ((this.letterSpaceIPD.opt - this.letterSpaceIPD.min)
* ipdAdjust);
}
- totalAdjust += (letterSpaceDim - letterSpaceIPD.opt) * letterSpaceCount;
+ totalAdjust += (letterSpaceDim - this.letterSpaceIPD.opt) * letterSpaceCount;
// set word space adjustment
//
if (wordSpaceCount > 0) {
wordSpaceDim += (difference - totalAdjust) / wordSpaceCount;
- } else {
- // there are no word spaces in this area
}
- totalAdjust += (wordSpaceDim - wordSpaceIPD.opt) * wordSpaceCount;
+ totalAdjust += (wordSpaceDim - this.wordSpaceIPD.opt) * wordSpaceCount;
if (totalAdjust != difference) {
// the applied adjustment is greater or smaller than the needed one
- log.trace("TextLM.addAreas: error in word / letter space adjustment = "
- + (totalAdjust - difference));
+ TextLayoutManager.LOG
+ .trace("TextLM.addAreas: error in word / letter space adjustment = "
+ + (totalAdjust - difference));
// set totalAdjust = difference, so that the width of the TextArea
// will counterbalance the error and the other inline areas will be
// placed correctly
totalAdjust = difference;
}
- TextArea t = createTextArea(realWidth, totalAdjust, context,
- wordSpaceIPD.opt - spaceCharIPD,
- firstAreaInfoIndex, lastAreaInfoIndex,
- context.isLastArea());
+ final TextArea t = this.createTextArea(realWidth, totalAdjust, context,
+ this.wordSpaceIPD.opt - this.spaceCharIPD, firstAreaInfoIndex,
+ lastAreaInfoIndex, context.isLastArea(), ai.font);
// wordSpaceDim is computed in relation to wordSpaceIPD.opt
// but the renderer needs to know the adjustment in relation
@@ -370,14 +384,14 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
// + (wordSpaceDim - spaceCharIPD - 2 * letterSpaceAdjust)
// = wordSpaceDim - letterSpaceAdjust
t.setTextLetterSpaceAdjust(letterSpaceDim);
- t.setTextWordSpaceAdjust(wordSpaceDim - spaceCharIPD
+ t.setTextWordSpaceAdjust(wordSpaceDim - this.spaceCharIPD
- 2 * t.getTextLetterSpaceAdjust());
if (context.getIPDAdjust() != 0) {
// add information about space width
- t.setSpaceDifference(wordSpaceIPD.opt - spaceCharIPD
+ t.setSpaceDifference(this.wordSpaceIPD.opt - this.spaceCharIPD
- 2 * t.getTextLetterSpaceAdjust());
}
- parentLM.addChildArea(t);
+ this.parentLM.addChildArea(t);
}
/**
@@ -391,11 +405,12 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
* @param firstIndex the index of the first AreaInfo used for the TextArea
* @param lastIndex the index of the last AreaInfo used for the TextArea
* @param isLastArea is this TextArea the last in a line?
+ * @param font Font to be used in this particular TextArea
* @return the new text area
*/
- protected TextArea createTextArea(MinOptMax width, int adjust,
- LayoutContext context, int spaceDiff,
- int firstIndex, int lastIndex, boolean isLastArea) {
+ protected TextArea createTextArea(final MinOptMax width, final int adjust,
+ final LayoutContext context, final int spaceDiff, final int firstIndex,
+ final int lastIndex, final boolean isLastArea, final Font font) {
TextArea textArea;
if (context.getIPDAdjust() == 0.0) {
// create just a TextArea
@@ -409,11 +424,12 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
}
textArea.setIPD(width.opt + adjust);
textArea.setBPD(font.getAscender() - font.getDescender());
+
textArea.setBaselineOffset(font.getAscender());
- if (textArea.getBPD() == alignmentContext.getHeight()) {
+ if (textArea.getBPD() == this.alignmentContext.getHeight()) {
textArea.setOffset(0);
} else {
- textArea.setOffset(alignmentContext.getOffset());
+ textArea.setOffset(this.alignmentContext.getOffset());
}
// set the text of the TextArea, split into words and spaces
@@ -421,12 +437,12 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
AreaInfo areaInfo;
int len = 0;
for (int i = firstIndex; i <= lastIndex; i++) {
- areaInfo = (AreaInfo) vecAreaInfo.get(i);
+ areaInfo = (AreaInfo) this.vecAreaInfo.get(i);
if (areaInfo.isSpace) {
// areaInfo stores information about spaces
// add the spaces - except zero-width spaces - to the TextArea
for (int j = areaInfo.startIndex; j < areaInfo.breakIndex; j++) {
- char spaceChar = textArray[j];
+ final char spaceChar = this.textArray[j];
if (!CharUtilities.isZeroWidthSpace(spaceChar)) {
textArea.addSpace(spaceChar, 0,
CharUtilities.isAdjustableSpace(spaceChar));
@@ -440,7 +456,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
len = 0;
}
len += areaInfo.breakIndex - areaInfo.startIndex;
- if (i == lastIndex || ((AreaInfo) vecAreaInfo.get(i + 1)).isSpace) {
+ if (i == lastIndex || ((AreaInfo) this.vecAreaInfo.get(i + 1)).isSpace) {
// here ends a new word
// add a word to the TextArea
if (isLastArea
@@ -448,17 +464,19 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
&& areaInfo.isHyphenated) {
len++;
}
- StringBuffer wordChars = new StringBuffer(len);
- int[] letterAdjust = new int[len];
+ final StringBuffer wordChars = new StringBuffer(len);
+ final int[] letterAdjust = new int[len];
int letter = 0;
for (int j = wordStartIndex; j <= i; j++) {
- AreaInfo ai = (AreaInfo) vecAreaInfo.get(j);
+ final AreaInfo ai = (AreaInfo) this.vecAreaInfo.get(j);
int lsCount = ai.letterSpaceCount;
- wordChars.append(textArray, ai.startIndex, ai.breakIndex - ai.startIndex);
+ wordChars.append(this.textArray, ai.startIndex,
+ ai.breakIndex - ai.startIndex);
for (int k = 0; k < ai.breakIndex - ai.startIndex; k++) {
- MinOptMax adj = letterAdjustArray[ai.startIndex + k];
+ final MinOptMax adj = this.letterAdjustArray[ai.startIndex + k];
if (letter > 0) {
- letterAdjust[letter] = (adj != null ? adj.opt : 0);
+ letterAdjust[letter] = adj == null ? 0
+ : adj.opt;
}
if (lsCount > 0) {
letterAdjust[letter] += textArea.getTextLetterSpaceAdjust();
@@ -472,7 +490,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
&& i == lastIndex
&& areaInfo.isHyphenated) {
// add the hyphenation character
- wordChars.append(foText.getCommonHyphenation().getHyphChar(font));
+ wordChars.append(this.foText.getCommonHyphenation().getHyphChar(font));
}
textArea.addWord(wordChars.toString(), 0, letterAdjust);
wordStartIndex = -1;
@@ -480,18 +498,18 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
}
}
TraitSetter.addFontTraits(textArea, font);
- textArea.addTrait(Trait.COLOR, foText.getColor());
+ textArea.addTrait(Trait.COLOR, this.foText.getColor());
- TraitSetter.addTextDecoration(textArea, foText.getTextDecoration());
+ TraitSetter.addTextDecoration(textArea, this.foText.getTextDecoration());
return textArea;
}
- private void addToLetterAdjust(int index, int width) {
- if (letterAdjustArray[index] == null) {
- letterAdjustArray[index] = new MinOptMax(width);
+ private void addToLetterAdjust(final int index, final int width) {
+ if (this.letterAdjustArray[index] == null) {
+ this.letterAdjustArray[index] = new MinOptMax(width);
} else {
- letterAdjustArray[index].add(width);
+ this.letterAdjustArray[index].add(width);
}
}
@@ -507,26 +525,27 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
}
/** {@inheritDoc} */
- public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
- lineStartBAP = context.getLineStartBorderAndPaddingWidth();
- lineEndBAP = context.getLineEndBorderAndPaddingWidth();
- alignmentContext = context.getAlignmentContext();
+ public LinkedList getNextKnuthElements(final LayoutContext context, final int alignment) {
+ this.lineStartBAP = context.getLineStartBorderAndPaddingWidth();
+ this.lineEndBAP = context.getLineEndBorderAndPaddingWidth();
+ this.alignmentContext = context.getAlignmentContext();
- LinkedList returnList = new LinkedList();
+ final LinkedList returnList = new LinkedList();
KnuthSequence sequence = new InlineKnuthSequence();
AreaInfo ai = null;
AreaInfo prevAi = null;
returnList.add(sequence);
- LineBreakStatus lbs = new LineBreakStatus();
- thisStart = nextStart;
+ final LineBreakStatus lbs = new LineBreakStatus();
+ this.thisStart = this.nextStart;
boolean inWord = false;
boolean inWhitespace = false;
char ch = 0;
- while (nextStart < textArray.length) {
- ch = textArray[nextStart];
+ while (this.nextStart < this.textArray.length) {
+ ch = this.textArray[this.nextStart];
boolean breakOpportunity = false;
- byte breakAction = keepTogether ? LineBreakStatus.PROHIBITED_BREAK : lbs.nextChar(ch);
+ final byte breakAction = this.keepTogether ? LineBreakStatus.PROHIBITED_BREAK
+ : lbs.nextChar(ch);
switch (breakAction) {
case LineBreakStatus.COMBINING_PROHIBITED_BREAK:
case LineBreakStatus.PROHIBITED_BREAK:
@@ -539,253 +558,248 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
breakOpportunity = true;
break;
default:
- log.error("Unexpected breakAction: " + breakAction);
+ TextLayoutManager.LOG.error("Unexpected breakAction: " + breakAction);
}
if (inWord) {
- if (breakOpportunity || isSpace(ch) || ch == NEWLINE) {
- //Word boundary found, process widths and kerning
- short lastIndex = nextStart;
- while (lastIndex > 0 && textArray[lastIndex - 1] == CharUtilities.SOFT_HYPHEN) {
- lastIndex--;
- }
- int wordLength = lastIndex - thisStart;
- boolean kerning = font.hasKerning();
- MinOptMax wordIPD = new MinOptMax(0);
- for (int i = thisStart; i < lastIndex; i++) {
- char c = textArray[i];
-
- //character width
- int charWidth = font.getCharWidth(c);
- wordIPD.add(charWidth);
-
- //kerning
- if (kerning) {
- int kern = 0;
- if (i > thisStart) {
- char previous = textArray[i - 1];
- kern = font.getKernValue(previous, c) * font.getFontSize() / 1000;
- } else if (prevAi != null && !prevAi.isSpace && prevAi.breakIndex > 0) {
- char previous = textArray[prevAi.breakIndex - 1];
- kern = font.getKernValue(previous, c) * font.getFontSize() / 1000;
- }
- if (kern != 0) {
- //log.info("Kerning between " + previous + " and " + c + ": " + kern);
- addToLetterAdjust(i, kern);
- wordIPD.add(kern);
- }
- }
- }
- if (kerning && breakOpportunity && !isSpace(ch) && lastIndex > 0 && textArray[lastIndex] == CharUtilities.SOFT_HYPHEN) {
- int kern = font.getKernValue(textArray[lastIndex - 1], ch) * font.getFontSize() / 1000;
- if (kern != 0) {
- addToLetterAdjust(lastIndex, kern);
- }
- }
- int iLetterSpaces = wordLength - 1;
- // if there is a break opportunity and the next one
- // is not a space, it could be used as a line end;
- // add one more letter space, in case other text follows
- if (breakOpportunity && !isSpace(ch)) {
- iLetterSpaces++;
- }
- wordIPD.add(MinOptMax.multiply(letterSpaceIPD, iLetterSpaces));
-
- // create the AreaInfo object
- ai = new AreaInfo(thisStart, lastIndex, (short) 0,
- (short) iLetterSpaces,
- wordIPD, textArray[lastIndex] == CharUtilities.SOFT_HYPHEN, false, breakOpportunity);
- prevAi = ai;
- vecAreaInfo.add(ai);
- tempStart = nextStart;
-
- //add the elements
- addElementsForAWordFragment(sequence, alignment, ai,
- vecAreaInfo.size() - 1, letterSpaceIPD);
- ai = null;
- thisStart = nextStart;
+ if (breakOpportunity || TextLayoutManager.isSpace(ch)
+ || ch == TextLayoutManager.NEWLINE) {
+ // this.textArray[lastIndex] == CharUtilities.SOFT_HYPHEN
+ prevAi = this.processWord(alignment, sequence, prevAi, ch,
+ breakOpportunity, true);
}
} else if (inWhitespace) {
if (ch != CharUtilities.SPACE || breakOpportunity) {
- // End of whitespace
- // create the AreaInfo object
- ai = new AreaInfo(thisStart, nextStart,
- (short) (nextStart - thisStart), (short) 0,
- MinOptMax.multiply(wordSpaceIPD, nextStart - thisStart),
- false, true, breakOpportunity);
- vecAreaInfo.add(ai);
- prevAi = ai;
-
- // create the elements
- addElementsForASpace(sequence, alignment, ai, vecAreaInfo.size() - 1);
- ai = null;
-
- thisStart = nextStart;
+ prevAi = this.processWhitespace(alignment, sequence,
+ breakOpportunity);
}
} else {
if (ai != null) {
- vecAreaInfo.add(ai);
prevAi = ai;
- ai.breakOppAfter = (ch == CharUtilities.SPACE) || breakOpportunity;
- addElementsForASpace(sequence, alignment, ai, vecAreaInfo.size() - 1);
- ai = null;
+ ai = this.processLeftoverAi(alignment, sequence, ai, ch,
+ ch == CharUtilities.SPACE || breakOpportunity);
}
if (breakAction == LineBreakStatus.EXPLICIT_BREAK) {
- if (lineEndBAP != 0) {
- sequence.add(
- new KnuthGlue(lineEndBAP, 0, 0,
- auxiliaryPosition, true));
- }
- sequence.endSequence();
- sequence = new InlineKnuthSequence();
- returnList.add(sequence);
+ sequence = this.processLinebreak(returnList, sequence);
}
}
- if ((ch == CharUtilities.SPACE
- && foText.getWhitespaceTreatment() == Constants.EN_PRESERVE)
+ if (ch == CharUtilities.SPACE
+ && this.foText.getWhitespaceTreatment() == Constants.EN_PRESERVE
|| ch == CharUtilities.NBSPACE) {
// preserved space or non-breaking space:
// create the AreaInfo object
- ai = new AreaInfo(nextStart, (short) (nextStart + 1),
- (short) 1, (short) 0,
- wordSpaceIPD, false, true, breakOpportunity);
- thisStart = (short) (nextStart + 1);
+ ai = new AreaInfo(this.nextStart, (short) (this.nextStart + 1),
+ (short) 1, (short) 0, this.wordSpaceIPD, false, true,
+ breakOpportunity, this.spaceFont);
+ this.thisStart = (short) (this.nextStart + 1);
} else if (CharUtilities.isFixedWidthSpace(ch) || CharUtilities.isZeroWidthSpace(ch)) {
// create the AreaInfo object
- MinOptMax ipd = new MinOptMax(font.getCharWidth(ch));
- ai = new AreaInfo(nextStart, (short) (nextStart + 1),
- (short) 0, (short) 0,
- ipd, false, true, breakOpportunity);
- thisStart = (short) (nextStart + 1);
- } else if (ch == NEWLINE) {
+ final Font font = FontSelector.selectFontForCharacterInText(ch,
+ this.foText, this);
+ final MinOptMax ipd = new MinOptMax(font.getCharWidth(ch));
+ ai = new AreaInfo(this.nextStart, (short) (this.nextStart + 1),
+ (short) 0, (short) 0, ipd, false, true,
+ breakOpportunity, font);
+ this.thisStart = (short) (this.nextStart + 1);
+ } else if (ch == TextLayoutManager.NEWLINE) {
// linefeed; this can happen when linefeed-treatment="preserve"
- thisStart = (short) (nextStart + 1);
+ this.thisStart = (short) (this.nextStart + 1);
}
- inWord = !isSpace(ch) && ch != NEWLINE;
- inWhitespace = ch == CharUtilities.SPACE && foText.getWhitespaceTreatment() != Constants.EN_PRESERVE;
- nextStart++;
+ inWord = !TextLayoutManager.isSpace(ch)
+ && ch != TextLayoutManager.NEWLINE;
+ inWhitespace = ch == CharUtilities.SPACE
+ && this.foText.getWhitespaceTreatment() != Constants.EN_PRESERVE;
+ this.nextStart++;
} // end of while
// Process any last elements
if (inWord) {
- int lastIndex = nextStart;
- if (textArray[nextStart - 1] == CharUtilities.SOFT_HYPHEN) {
- lastIndex--;
- }
- int wordLength = lastIndex - thisStart;
- boolean kerning = font.hasKerning();
- MinOptMax wordIPD = new MinOptMax(0);
- for (int i = thisStart; i < lastIndex; i++) {
- char c = textArray[i];
-
- //character width
- int charWidth = font.getCharWidth(c);
- wordIPD.add(charWidth);
-
- //kerning
- if (kerning) {
- int kern = 0;
- if (i > thisStart) {
- char previous = textArray[i - 1];
- kern = font.getKernValue(previous, c) * font.getFontSize() / 1000;
- } else if (prevAi != null && !prevAi.isSpace) {
- char previous = textArray[prevAi.breakIndex - 1];
- kern = font.getKernValue(previous, c) * font.getFontSize() / 1000;
- }
- if (kern != 0) {
- //log.info("Kerning between " + previous + " and " + c + ": " + kern);
- addToLetterAdjust(i, kern);
- wordIPD.add(kern);
- }
- }
- }
- int iLetterSpaces = wordLength - 1;
- wordIPD.add(MinOptMax.multiply(letterSpaceIPD, iLetterSpaces));
-
- // create the AreaInfo object
- ai = new AreaInfo(thisStart, (short)lastIndex, (short) 0,
- (short) iLetterSpaces,
- wordIPD, false, false, false);
- vecAreaInfo.add(ai);
- tempStart = nextStart;
-
- // create the elements
- addElementsForAWordFragment(sequence, alignment, ai,
- vecAreaInfo.size() - 1, letterSpaceIPD);
- ai = null;
+ this.processWord(alignment, sequence, prevAi, ch, false, false);
} else if (inWhitespace) {
- ai = new AreaInfo(thisStart, (short) (nextStart),
- (short) (nextStart - thisStart), (short) 0,
- MinOptMax.multiply(wordSpaceIPD, nextStart - thisStart),
- false, true, true);
- vecAreaInfo.add(ai);
-
- // create the elements
- addElementsForASpace(sequence, alignment, ai, vecAreaInfo.size() - 1);
- ai = null;
+ this.processWhitespace(alignment, sequence, true);
} else if (ai != null) {
- vecAreaInfo.add(ai);
- ai.breakOppAfter = ch == CharUtilities.ZERO_WIDTH_SPACE;
- addElementsForASpace(sequence, alignment, ai, vecAreaInfo.size() - 1);
- ai = null;
- } else if (ch == NEWLINE) {
- if (lineEndBAP != 0) {
- sequence.add
- (new KnuthGlue(lineEndBAP, 0, 0,
- auxiliaryPosition, true));
- }
- sequence.endSequence();
- sequence = new InlineKnuthSequence();
- returnList.add(sequence);
+ ai = this.processLeftoverAi(alignment, sequence, ai, ch,
+ ch == CharUtilities.ZERO_WIDTH_SPACE);
+ } else if (ch == TextLayoutManager.NEWLINE) {
+ sequence = this.processLinebreak(returnList, sequence);
}
if (((List)returnList.getLast()).size() == 0) {
//Remove an empty sequence because of a trailing newline
returnList.removeLast();
}
- setFinished(true);
- if (returnList.size() > 0) {
- return returnList;
- } else {
+ this.setFinished(true);
+ if (returnList.isEmpty()) {
return null;
+ } else {
+ return returnList;
+ }
+ }
+
+ private KnuthSequence processLinebreak(final LinkedList returnList,
+ KnuthSequence sequence) {
+ if (this.lineEndBAP != 0) {
+ sequence.add(
+ new KnuthGlue(this.lineEndBAP, 0, 0,
+ this.auxiliaryPosition, true));
+ }
+ sequence.endSequence();
+ sequence = new InlineKnuthSequence();
+ returnList.add(sequence);
+ return sequence;
+ }
+
+ private AreaInfo processLeftoverAi(final int alignment,
+ final KnuthSequence sequence, AreaInfo ai, final char ch,
+ final boolean breakOpportunityAfter) {
+ this.vecAreaInfo.add(ai);
+ ai.breakOppAfter = breakOpportunityAfter;
+ this.addElementsForASpace(sequence, alignment, ai, this.vecAreaInfo.size() - 1);
+ ai = null;
+ return ai;
+ }
+
+ private AreaInfo processWhitespace(final int alignment,
+ final KnuthSequence sequence, final boolean breakOpportunity) {
+ AreaInfo ai;
+ AreaInfo prevAi;
+ // End of whitespace
+ // create the AreaInfo object
+ ai = new AreaInfo(this.thisStart, this.nextStart,
+ (short) (this.nextStart - this.thisStart), (short) 0,
+ MinOptMax.multiply(this.wordSpaceIPD, this.nextStart
+ - this.thisStart), false, true,
+ breakOpportunity, this.spaceFont);
+ this.vecAreaInfo.add(ai);
+ prevAi = ai;
+
+ // create the elements
+ this.addElementsForASpace(sequence, alignment, ai, this.vecAreaInfo.size() - 1);
+ ai = null;
+
+ this.thisStart = this.nextStart;
+ return prevAi;
+ }
+
+ private AreaInfo processWord(final int alignment, final KnuthSequence sequence,
+ AreaInfo prevAi, final char ch, final boolean breakOpportunity,
+ final boolean checkEndsWithHyphen) {
+ AreaInfo ai;
+ //Word boundary found, process widths and kerning
+ short lastIndex = this.nextStart;
+ while (lastIndex > 0
+ && this.textArray[lastIndex - 1] == CharUtilities.SOFT_HYPHEN) {
+ lastIndex--;
+ }
+ final boolean endsWithHyphen = checkEndsWithHyphen
+ && this.textArray[lastIndex] == CharUtilities.SOFT_HYPHEN;
+ final Font font = FontSelector
+ .selectFontForCharactersInText(this.textArray,
+ this.thisStart, lastIndex, this.foText, this);
+ final int wordLength = lastIndex - this.thisStart;
+ final boolean kerning = font.hasKerning();
+ final MinOptMax wordIPD = new MinOptMax(0);
+ for (int i = this.thisStart; i < lastIndex; i++) {
+ final char c = this.textArray[i];
+
+ //character width
+ final int charWidth = font.getCharWidth(c);
+ wordIPD.add(charWidth);
+
+ //kerning
+ if (kerning) {
+ int kern = 0;
+ if (i > this.thisStart) {
+ final char previous = this.textArray[i - 1];
+ kern = font.getKernValue(previous, c) * font.getFontSize() / 1000;
+ } else if (prevAi != null && !prevAi.isSpace && prevAi.breakIndex > 0) {
+ final char previous = this.textArray[prevAi.breakIndex - 1];
+ kern = font.getKernValue(previous, c) * font.getFontSize() / 1000;
+ }
+ if (kern != 0) {
+ this.addToLetterAdjust(i, kern);
+ wordIPD.add(kern);
+ }
+ }
+ }
+ if (kerning
+ && breakOpportunity
+ && !TextLayoutManager.isSpace(ch)
+ && lastIndex > 0
+ && endsWithHyphen) {
+ final int kern = font.getKernValue(
+ this.textArray[lastIndex - 1], ch)
+ * font.getFontSize() / 1000;
+ if (kern != 0) {
+ this.addToLetterAdjust(lastIndex, kern);
+ }
+ }
+ int iLetterSpaces = wordLength - 1;
+ // if there is a break opportunity and the next one
+ // is not a space, it could be used as a line end;
+ // add one more letter space, in case other text follows
+ if (breakOpportunity && !TextLayoutManager.isSpace(ch)) {
+ iLetterSpaces++;
}
+ wordIPD.add(MinOptMax.multiply(this.letterSpaceIPD, iLetterSpaces));
+
+ // create the AreaInfo object
+ ai = new AreaInfo(this.thisStart, lastIndex, (short) 0,
+ (short) iLetterSpaces, wordIPD,
+ endsWithHyphen,
+ false, breakOpportunity, font);
+ prevAi = ai;
+ this.vecAreaInfo.add(ai);
+ this.tempStart = this.nextStart;
+
+ //add the elements
+ this.addElementsForAWordFragment(sequence, alignment, ai,
+ this.vecAreaInfo.size() - 1, this.letterSpaceIPD);
+ ai = null;
+ this.thisStart = this.nextStart;
+ return prevAi;
}
/** {@inheritDoc} */
- public List addALetterSpaceTo(List oldList) {
+ public List addALetterSpaceTo(final List oldList) {
// old list contains only a box, or the sequence: box penalty glue box;
// look at the Position stored in the first element in oldList
// which is always a box
ListIterator oldListIterator = oldList.listIterator();
- KnuthElement el = (KnuthElement)oldListIterator.next();
- LeafPosition pos = (LeafPosition) ((KnuthBox) el).getPosition();
- int idx = pos.getLeafPos();
+ final KnuthElement el = (KnuthElement)oldListIterator.next();
+ final LeafPosition pos = (LeafPosition) ((KnuthBox) el).getPosition();
+ final int idx = pos.getLeafPos();
//element could refer to '-1' position, for non-collapsed spaces (?)
if (idx > -1) {
- AreaInfo ai = (AreaInfo) vecAreaInfo.get(idx);
+ final AreaInfo ai = (AreaInfo) this.vecAreaInfo.get(idx);
ai.letterSpaceCount++;
- ai.areaIPD.add(letterSpaceIPD);
- if (BREAK_CHARS.indexOf(textArray[tempStart - 1]) >= 0) {
+ ai.areaIPD.add(this.letterSpaceIPD);
+ if (TextLayoutManager.BREAK_CHARS.indexOf(this.textArray[this.tempStart - 1]) >= 0) {
// the last character could be used as a line break
// append new elements to oldList
oldListIterator = oldList.listIterator(oldList.size());
oldListIterator.add(new KnuthPenalty(0, KnuthPenalty.FLAGGED_PENALTY, true,
- auxiliaryPosition, false));
- oldListIterator.add(new KnuthGlue(letterSpaceIPD.opt,
- letterSpaceIPD.max - letterSpaceIPD.opt,
- letterSpaceIPD.opt - letterSpaceIPD.min,
- auxiliaryPosition, false));
- } else if (letterSpaceIPD.min == letterSpaceIPD.max) {
+ this.auxiliaryPosition, false));
+ oldListIterator.add(new KnuthGlue(this.letterSpaceIPD.opt,
+ this.letterSpaceIPD.max - this.letterSpaceIPD.opt,
+ this.letterSpaceIPD.opt - this.letterSpaceIPD.min,
+ this.auxiliaryPosition, false));
+ } else if (this.letterSpaceIPD.min == this.letterSpaceIPD.max) {
// constant letter space: replace the box
- oldListIterator.set(new KnuthInlineBox(ai.areaIPD.opt, alignmentContext, pos, false));
+ oldListIterator.set(new KnuthInlineBox(ai.areaIPD.opt,
+ this.alignmentContext, pos, false));
} else {
// adjustable letter space: replace the glue
oldListIterator.next(); // this would return the penalty element
oldListIterator.next(); // this would return the glue element
- oldListIterator.set(new KnuthGlue(ai.letterSpaceCount * letterSpaceIPD.opt,
- ai.letterSpaceCount * (letterSpaceIPD.max - letterSpaceIPD.opt),
- ai.letterSpaceCount * (letterSpaceIPD.opt - letterSpaceIPD.min),
- auxiliaryPosition, true));
+ oldListIterator
+ .set(new KnuthGlue(
+ ai.letterSpaceCount * this.letterSpaceIPD.opt,
+ ai.letterSpaceCount
+ * (this.letterSpaceIPD.max - this.letterSpaceIPD.opt),
+ ai.letterSpaceCount
+ * (this.letterSpaceIPD.opt - this.letterSpaceIPD.min),
+ this.auxiliaryPosition, true));
}
}
return oldList;
@@ -798,10 +812,10 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
*
* @param oldList the elements representing the word space
*/
- public void removeWordSpace(List oldList) {
+ public void removeWordSpace(final List oldList) {
// find the element storing the Position whose value
// points to the AreaInfo object
- ListIterator oldListIterator = oldList.listIterator();
+ final ListIterator oldListIterator = oldList.listIterator();
if (((KnuthElement) ((LinkedList) oldList).getFirst()).isPenalty()) {
// non breaking space: oldList starts with a penalty
oldListIterator.next();
@@ -812,30 +826,31 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
oldListIterator.next();
oldListIterator.next();
}
- int leafValue = ((LeafPosition) ((KnuthElement) oldListIterator.next()).getPosition()).getLeafPos();
+ final int leafValue = ((LeafPosition) ((KnuthElement) oldListIterator
+ .next()).getPosition()).getLeafPos();
// only the last word space can be a trailing space!
- if (leafValue == vecAreaInfo.size() - 1) {
- vecAreaInfo.remove(leafValue);
+ if (leafValue == this.vecAreaInfo.size() - 1) {
+ this.vecAreaInfo.remove(leafValue);
} else {
- log.error("trying to remove a non-trailing word space");
+ TextLayoutManager.LOG.error("trying to remove a non-trailing word space");
}
}
/** {@inheritDoc} */
- public void hyphenate(Position pos, HyphContext hc) {
- AreaInfo ai
- = (AreaInfo) vecAreaInfo.get(((LeafPosition) pos).getLeafPos());
+ public void hyphenate(final Position pos, final HyphContext hc) {
+ final AreaInfo ai
+ = (AreaInfo) this.vecAreaInfo.get(((LeafPosition) pos).getLeafPos());
int startIndex = ai.startIndex;
int stopIndex;
boolean nothingChanged = true;
+ final Font font = ai.font;
while (startIndex < ai.breakIndex) {
- MinOptMax newIPD = new MinOptMax(0);
+ final MinOptMax newIPD = new MinOptMax(0);
boolean hyphenFollows;
- if (hc.hasMoreHyphPoints()
- && (stopIndex = startIndex + hc.getNextHyphPoint())
- <= ai.breakIndex) {
+ stopIndex = startIndex + hc.getNextHyphPoint();
+ if (hc.hasMoreHyphPoints() && stopIndex <= ai.breakIndex) {
// stopIndex is the index of the first character
// after a hyphenation point
hyphenFollows = true;
@@ -850,12 +865,12 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
//log.info("Word: " + new String(textArray, startIndex, stopIndex - startIndex));
for (int i = startIndex; i < stopIndex; i++) {
- char c = textArray[i];
+ final char c = this.textArray[i];
newIPD.add(new MinOptMax(font.getCharWidth(c)));
//if (i > startIndex) {
if (i < stopIndex) {
MinOptMax la = this.letterAdjustArray[i + 1];
- if ((i == stopIndex - 1) && hyphenFollows) {
+ if (i == stopIndex - 1 && hyphenFollows) {
//the letter adjust here needs to be handled further down during
//element generation because it depends on hyph/no-hyph condition
la = null;
@@ -866,115 +881,113 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
}
}
// add letter spaces
- boolean isWordEnd
+ final boolean isWordEnd
= stopIndex == ai.breakIndex
- && ai.letterSpaceCount < (ai.breakIndex - ai.startIndex);
- newIPD.add(MinOptMax.multiply(letterSpaceIPD,
+ && ai.letterSpaceCount < ai.breakIndex - ai.startIndex;
+ newIPD.add(MinOptMax.multiply(this.letterSpaceIPD,
(isWordEnd
- ? (stopIndex - startIndex - 1)
- : (stopIndex - startIndex))));
+ ? stopIndex - startIndex - 1
+ : stopIndex - startIndex)));
if (!(nothingChanged
&& stopIndex == ai.breakIndex
&& !hyphenFollows)) {
// the new AreaInfo object is not equal to the old one
- if (changeList == null) {
- changeList = new LinkedList();
+ if (this.changeList == null) {
+ this.changeList = new LinkedList();
}
- changeList.add
- (new PendingChange
- (new AreaInfo((short) startIndex, (short) stopIndex,
- (short) 0,
- (short) (isWordEnd
- ? (stopIndex - startIndex - 1)
- : (stopIndex - startIndex)),
- newIPD, hyphenFollows, false, false),
- ((LeafPosition) pos).getLeafPos()));
+ this.changeList.add(new PendingChange(new AreaInfo(
+ (short) startIndex, (short) stopIndex, (short) 0,
+ (short) (isWordEnd ? stopIndex - startIndex - 1
+ : stopIndex - startIndex), newIPD,
+ hyphenFollows, false, false, font),
+ ((LeafPosition) pos).getLeafPos()));
nothingChanged = false;
}
startIndex = stopIndex;
}
- hasChanged = !nothingChanged;
+ this.hasChanged = !nothingChanged;
}
/** {@inheritDoc} */
- public boolean applyChanges(List oldList) {
- setFinished(false);
+ public boolean applyChanges(final List oldList) {
+ this.setFinished(false);
- if (changeList != null && !changeList.isEmpty()) {
+ if (this.changeList != null && !this.changeList.isEmpty()) {
int areaInfosAdded = 0;
int areaInfosRemoved = 0;
int oldIndex = -1, changeIndex;
PendingChange currChange;
- ListIterator changeListIterator = changeList.listIterator();
+ final ListIterator changeListIterator = this.changeList.listIterator();
while (changeListIterator.hasNext()) {
currChange = (PendingChange) changeListIterator.next();
- if (currChange.index != oldIndex) {
- areaInfosRemoved++;
+ if (currChange.index == oldIndex) {
areaInfosAdded++;
- oldIndex = currChange.index;
changeIndex = currChange.index + areaInfosAdded - areaInfosRemoved;
- vecAreaInfo.remove(changeIndex);
} else {
+ areaInfosRemoved++;
areaInfosAdded++;
+ oldIndex = currChange.index;
changeIndex = currChange.index + areaInfosAdded - areaInfosRemoved;
+ this.vecAreaInfo.remove(changeIndex);
}
- vecAreaInfo.add(changeIndex, currChange.ai);
+ this.vecAreaInfo.add(changeIndex, currChange.ai);
}
- changeList.clear();
+ this.changeList.clear();
}
- returnedIndex = 0;
- return hasChanged;
+ this.returnedIndex = 0;
+ return this.hasChanged;
}
/** {@inheritDoc} */
- public LinkedList getChangedKnuthElements(List oldList,
- int alignment) {
- if (isFinished()) {
+ public LinkedList getChangedKnuthElements(final List oldList,
+ final int alignment) {
+ if (this.isFinished()) {
return null;
}
- LinkedList returnList = new LinkedList();
+ final LinkedList returnList = new LinkedList();
- while (returnedIndex < vecAreaInfo.size()) {
- AreaInfo ai = (AreaInfo) vecAreaInfo.get(returnedIndex);
+ while (this.returnedIndex < this.vecAreaInfo.size()) {
+ final AreaInfo ai = (AreaInfo) this.vecAreaInfo.get(this.returnedIndex);
if (ai.wordSpaceCount == 0) {
// ai refers either to a word or a word fragment
- addElementsForAWordFragment(returnList, alignment, ai, returnedIndex, letterSpaceIPD);
+ this.addElementsForAWordFragment(returnList, alignment, ai,
+ this.returnedIndex, this.letterSpaceIPD);
} else {
// ai refers to a space
- addElementsForASpace(returnList, alignment, ai, returnedIndex);
+ this.addElementsForASpace(returnList, alignment, ai, this.returnedIndex);
}
- returnedIndex++;
+ this.returnedIndex++;
} // end of while
- setFinished(true);
+ this.setFinished(true);
//ElementListObserver.observe(returnList, "text-changed", null);
return returnList;
}
/** {@inheritDoc} */
- public void getWordChars(StringBuffer sbChars, Position pos) {
- int leafValue = ((LeafPosition) pos).getLeafPos();
+ public void getWordChars(final StringBuffer sbChars, final Position pos) {
+ final int leafValue = ((LeafPosition) pos).getLeafPos();
if (leafValue != -1) {
- AreaInfo ai = (AreaInfo) vecAreaInfo.get(leafValue);
- sbChars.append(textArray, ai.startIndex, ai.breakIndex - ai.startIndex);
+ final AreaInfo ai = (AreaInfo) this.vecAreaInfo.get(leafValue);
+ sbChars.append(this.textArray, ai.startIndex, ai.breakIndex - ai.startIndex);
}
}
- private void addElementsForASpace(List baseList,
- int alignment,
- AreaInfo ai,
- int leafValue) {
- LeafPosition mainPosition = new LeafPosition(this, leafValue);
+ private void addElementsForASpace(final List baseList,
+ final int alignment,
+ final AreaInfo ai,
+ final int leafValue) {
+ final LeafPosition mainPosition = new LeafPosition(this, leafValue);
if (!ai.breakOppAfter) {
// a non-breaking space
- if (alignment == EN_JUSTIFY) {
+ if (alignment == Constants.EN_JUSTIFY) {
// the space can stretch and shrink, and must be preserved
// when starting a line
- baseList.add(makeAuxiliaryZeroWidthBox());
- baseList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
+ baseList.add(this.makeAuxiliaryZeroWidthBox());
+ baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
baseList.add(new KnuthGlue(ai.areaIPD.opt, ai.areaIPD.max - ai.areaIPD.opt,
ai.areaIPD.opt - ai.areaIPD.min, mainPosition, false));
} else {
@@ -984,195 +997,133 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
mainPosition, true));
}
} else {
- if (textArray[ai.startIndex] != CharUtilities.SPACE
- || foText.getWhitespaceTreatment() == Constants.EN_PRESERVE) {
+ if (this.textArray[ai.startIndex] != CharUtilities.SPACE
+ || this.foText.getWhitespaceTreatment() == Constants.EN_PRESERVE) {
// a breaking space that needs to be preserved
- switch (alignment) {
- case EN_CENTER:
- // centered text:
- // if the second element is chosen as a line break these elements
- // add a constant amount of stretch at the end of a line and at the
- // beginning of the next one, otherwise they don't add any stretch
- baseList.add(new KnuthGlue(lineEndBAP,
- 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- auxiliaryPosition, false));
- baseList.add(makeZeroWidthPenalty(0));
- baseList.add(new KnuthGlue(
- - (lineStartBAP + lineEndBAP), -6
- * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- auxiliaryPosition, false));
- baseList.add(makeAuxiliaryZeroWidthBox());
- baseList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
- baseList.add(new KnuthGlue(ai.areaIPD.opt + lineStartBAP,
- 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- mainPosition, false));
- break;
-
- case EN_START: // fall through
- case EN_END:
- // left- or right-aligned text:
- // if the second element is chosen as a line break these elements
- // add a constant amount of stretch at the end of a line, otherwise
- // they don't add any stretch
- baseList.add(new KnuthGlue(lineEndBAP,
- 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- auxiliaryPosition, false));
- baseList.add(makeZeroWidthPenalty(0));
- baseList.add(new KnuthGlue(
- - (lineStartBAP + lineEndBAP), -3
- * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- auxiliaryPosition, false));
- baseList.add(makeAuxiliaryZeroWidthBox());
- baseList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
- baseList.add(new KnuthGlue(ai.areaIPD.opt + lineStartBAP, 0, 0,
- mainPosition, false));
- break;
-
- case EN_JUSTIFY:
- // justified text:
- // the stretch and shrink depends on the space width
- baseList.add(new KnuthGlue(lineEndBAP, 0, 0,
- auxiliaryPosition, false));
- baseList.add(makeZeroWidthPenalty(0));
- baseList.add(new KnuthGlue(
- - (lineStartBAP + lineEndBAP), ai.areaIPD.max
- - ai.areaIPD.opt, ai.areaIPD.opt - ai.areaIPD.min,
- auxiliaryPosition, false));
- baseList.add(makeAuxiliaryZeroWidthBox());
- baseList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
- baseList.add(new KnuthGlue(lineStartBAP + ai.areaIPD.opt, 0, 0,
- mainPosition, false));
- break;
-
- default:
- // last line justified, the other lines unjustified:
- // use only the space stretch
- baseList.add(new KnuthGlue(lineEndBAP, 0, 0,
- auxiliaryPosition, false));
- baseList.add(makeZeroWidthPenalty(0));
- baseList.add(new KnuthGlue(
- - (lineStartBAP + lineEndBAP), ai.areaIPD.max
- - ai.areaIPD.opt, 0,
- auxiliaryPosition, false));
- baseList.add(makeAuxiliaryZeroWidthBox());
- baseList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
- baseList.add(new KnuthGlue(lineStartBAP + ai.areaIPD.opt, 0, 0,
- mainPosition, false));
- }
+ this
+ .addElementsForBreakingSpace(baseList, alignment, ai,
+ this.auxiliaryPosition, 0, mainPosition,
+ ai.areaIPD.opt, true);
} else {
// a (possible block) of breaking spaces
- switch (alignment) {
- case EN_CENTER:
- // centered text:
- // if the second element is chosen as a line break these elements
- // add a constant amount of stretch at the end of a line and at the
- // beginning of the next one, otherwise they don't add any stretch
- baseList.add(new KnuthGlue(lineEndBAP,
- 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- auxiliaryPosition, false));
- baseList.add(makeZeroWidthPenalty(0));
- baseList.add(new KnuthGlue(ai.areaIPD.opt
- - (lineStartBAP + lineEndBAP), -6
- * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- mainPosition, false));
- baseList.add(makeAuxiliaryZeroWidthBox());
- baseList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
- baseList.add(new KnuthGlue(lineStartBAP,
- 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- auxiliaryPosition, false));
- break;
+ this
+ .addElementsForBreakingSpace(baseList, alignment, ai,
+ mainPosition, ai.areaIPD.opt,
+ this.auxiliaryPosition, 0, false);
+ }
+ }
+ }
- case EN_START: // fall through
- case EN_END:
- // left- or right-aligned text:
- // if the second element is chosen as a line break these elements
- // add a constant amount of stretch at the end of a line, otherwise
- // they don't add any stretch
- if (lineStartBAP != 0 || lineEndBAP != 0) {
- baseList.add(new KnuthGlue(lineEndBAP,
- 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- auxiliaryPosition, false));
- baseList.add(makeZeroWidthPenalty(0));
- baseList.add(new KnuthGlue(ai.areaIPD.opt
- - (lineStartBAP + lineEndBAP), -3
+ private void addElementsForBreakingSpace(final List baseList,
+ final int alignment, final AreaInfo ai, final Position pos2,
+ final int p2WidthOffset, final Position pos3,
+ final int p3WidthOffset, final boolean skipZeroCheck) {
+ switch (alignment) {
+ case EN_CENTER:
+ // centered text:
+ // if the second element is chosen as a line break these elements
+ // add a constant amount of stretch at the end of a line and at the
+ // beginning of the next one, otherwise they don't add any stretch
+ baseList.add(new KnuthGlue(this.lineEndBAP,
+ 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+ this.auxiliaryPosition, false));
+ baseList.add(this.makeZeroWidthPenalty(0));
+ baseList.add(new KnuthGlue(p2WidthOffset
+ - (this.lineStartBAP + this.lineEndBAP), -6
+ * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0, pos2, false));
+ baseList.add(this.makeAuxiliaryZeroWidthBox());
+ baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
+ baseList.add(new KnuthGlue(this.lineStartBAP + p3WidthOffset,
+ 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0, pos3, false));
+ break;
+
+ case EN_START: // fall through
+ case EN_END:
+ // left- or right-aligned text:
+ // if the second element is chosen as a line break these elements
+ // add a constant amount of stretch at the end of a line, otherwise
+ // they don't add any stretch
+ if (skipZeroCheck || this.lineStartBAP != 0 || this.lineEndBAP != 0) {
+ baseList.add(new KnuthGlue(this.lineEndBAP,
+ 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+ this.auxiliaryPosition, false));
+ baseList.add(this.makeZeroWidthPenalty(0));
+ baseList
+ .add(new KnuthGlue(p2WidthOffset
+ - (this.lineStartBAP + this.lineEndBAP), -3
* LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- mainPosition, false));
- baseList.add(makeAuxiliaryZeroWidthBox());
- baseList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
- baseList.add(new KnuthGlue(lineStartBAP, 0, 0,
- auxiliaryPosition, false));
- } else {
- baseList.add(new KnuthGlue(0,
- 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- auxiliaryPosition, false));
- baseList.add(makeZeroWidthPenalty(0));
- baseList.add(new KnuthGlue(ai.areaIPD.opt, -3
+ pos2, false));
+ baseList.add(this.makeAuxiliaryZeroWidthBox());
+ baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
+ baseList.add(new KnuthGlue(this.lineStartBAP + p3WidthOffset,
+ 0, 0, pos3, false));
+ } else {
+ baseList.add(new KnuthGlue(0,
+ 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+ this.auxiliaryPosition, false));
+ baseList.add(this.makeZeroWidthPenalty(0));
+ baseList
+ .add(new KnuthGlue(ai.areaIPD.opt, -3
* LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- mainPosition, false));
- }
- break;
+ pos2, false));
+ }
+ break;
- case EN_JUSTIFY:
- // justified text:
- // the stretch and shrink depends on the space width
- if (lineStartBAP != 0 || lineEndBAP != 0) {
- baseList.add(new KnuthGlue(lineEndBAP, 0, 0,
- auxiliaryPosition, false));
- baseList.add(makeZeroWidthPenalty(0));
- baseList.add(new KnuthGlue(
- ai.areaIPD.opt - (lineStartBAP + lineEndBAP),
- ai.areaIPD.max - ai.areaIPD.opt,
- ai.areaIPD.opt - ai.areaIPD.min,
- mainPosition, false));
- baseList.add(makeAuxiliaryZeroWidthBox());
- baseList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
- baseList.add(new KnuthGlue(lineStartBAP, 0, 0,
- auxiliaryPosition, false));
- } else {
- baseList.add(new KnuthGlue(ai.areaIPD.opt,
- ai.areaIPD.max - ai.areaIPD.opt,
- ai.areaIPD.opt - ai.areaIPD.min,
- mainPosition, false));
- }
- break;
+ case EN_JUSTIFY:
+ // justified text:
+ // the stretch and shrink depends on the space width
+ if (skipZeroCheck || this.lineStartBAP != 0 || this.lineEndBAP != 0) {
+ baseList.add(new KnuthGlue(this.lineEndBAP, 0, 0,
+ this.auxiliaryPosition, false));
+ baseList.add(this.makeZeroWidthPenalty(0));
+ baseList.add(new KnuthGlue(p2WidthOffset
+ - (this.lineStartBAP + this.lineEndBAP), ai.areaIPD.max
+ - ai.areaIPD.opt, ai.areaIPD.opt - ai.areaIPD.min,
+ pos2, false));
+ baseList.add(this.makeAuxiliaryZeroWidthBox());
+ baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
+ baseList.add(new KnuthGlue(this.lineStartBAP + p3WidthOffset,
+ 0, 0, pos3, false));
+ } else {
+ baseList.add(new KnuthGlue(ai.areaIPD.opt, ai.areaIPD.max
+ - ai.areaIPD.opt, ai.areaIPD.opt - ai.areaIPD.min,
+ pos2, false));
+ }
+ break;
- default:
- // last line justified, the other lines unjustified:
- // use only the space stretch
- if (lineStartBAP != 0 || lineEndBAP != 0) {
- baseList.add(new KnuthGlue(lineEndBAP, 0, 0,
- auxiliaryPosition, false));
- baseList.add(makeZeroWidthPenalty(0));
- baseList.add(new KnuthGlue(
- ai.areaIPD.opt - (lineStartBAP + lineEndBAP),
- ai.areaIPD.max - ai.areaIPD.opt,
- 0, mainPosition, false));
- baseList.add(makeAuxiliaryZeroWidthBox());
- baseList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
- baseList.add(new KnuthGlue(lineStartBAP, 0, 0,
- auxiliaryPosition, false));
- } else {
- baseList.add(new KnuthGlue(ai.areaIPD.opt,
- ai.areaIPD.max - ai.areaIPD.opt, 0,
- mainPosition, false));
- }
- }
+ default:
+ // last line justified, the other lines unjustified:
+ // use only the space stretch
+ if (skipZeroCheck || this.lineStartBAP != 0 || this.lineEndBAP != 0) {
+ baseList.add(new KnuthGlue(this.lineEndBAP, 0, 0,
+ this.auxiliaryPosition, false));
+ baseList.add(this.makeZeroWidthPenalty(0));
+ baseList.add(new KnuthGlue(p2WidthOffset
+ - (this.lineStartBAP + this.lineEndBAP), ai.areaIPD.max
+ - ai.areaIPD.opt, 0, pos2, false));
+ baseList.add(this.makeAuxiliaryZeroWidthBox());
+ baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
+ baseList.add(new KnuthGlue(this.lineStartBAP + p3WidthOffset,
+ 0, 0, pos3, false));
+ } else {
+ baseList.add(new KnuthGlue(ai.areaIPD.opt, ai.areaIPD.max
+ - ai.areaIPD.opt, 0, pos2, false));
}
}
}
- private void addElementsForAWordFragment(List baseList,
- int alignment,
- AreaInfo ai,
- int leafValue,
- MinOptMax letterSpaceWidth) {
+ private void addElementsForAWordFragment(final List baseList,
+ final int alignment,
+ final AreaInfo ai,
+ final int leafValue,
+ final MinOptMax letterSpaceWidth) {
- LeafPosition mainPosition = new LeafPosition(this, leafValue);
+ final LeafPosition mainPosition = new LeafPosition(this, leafValue);
// if the last character of the word fragment is '-' or '/',
// the fragment could end a line; in this case, it loses one
// of its letter spaces;
- boolean suppressibleLetterSpace = ai.breakOppAfter && !ai.isHyphenated;
+ final boolean suppressibleLetterSpace = ai.breakOppAfter && !ai.isHyphenated;
if (letterSpaceWidth.min == letterSpaceWidth.max) {
// constant letter spacing
@@ -1180,138 +1131,152 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
suppressibleLetterSpace
? ai.areaIPD.opt - letterSpaceWidth.opt
: ai.areaIPD.opt,
- alignmentContext,
- notifyPos(mainPosition), false));
+ this.alignmentContext,
+ this.notifyPos(mainPosition), false));
} else {
// adjustable letter spacing
- int unsuppressibleLetterSpaces
+ final int unsuppressibleLetterSpaces
= suppressibleLetterSpace ? ai.letterSpaceCount - 1 : ai.letterSpaceCount;
baseList.add
(new KnuthInlineBox(ai.areaIPD.opt
- ai.letterSpaceCount * letterSpaceWidth.opt,
- alignmentContext,
- notifyPos(mainPosition), false));
- baseList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
+ this.alignmentContext,
+ this.notifyPos(mainPosition), false));
+ baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
baseList.add
(new KnuthGlue(unsuppressibleLetterSpaces * letterSpaceWidth.opt,
unsuppressibleLetterSpaces * (letterSpaceWidth.max - letterSpaceWidth.opt),
unsuppressibleLetterSpaces * (letterSpaceWidth.opt - letterSpaceWidth.min),
- auxiliaryPosition, true));
- baseList.add(makeAuxiliaryZeroWidthBox());
+ this.auxiliaryPosition, true));
+ baseList.add(this.makeAuxiliaryZeroWidthBox());
}
// 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.isHyphenated) {
MinOptMax widthIfNoBreakOccurs = null;
- if (ai.breakIndex < textArray.length) {
+ if (ai.breakIndex < this.textArray.length) {
//Add in kerning in no-break condition
- widthIfNoBreakOccurs = letterAdjustArray[ai.breakIndex];
+ widthIfNoBreakOccurs = this.letterAdjustArray[ai.breakIndex];
}
//if (ai.breakIndex)
// the word fragment ends at the end of a syllable:
// if a break occurs the content width increases,
// otherwise nothing happens
- addElementsForAHyphen(baseList, alignment, hyphIPD, widthIfNoBreakOccurs, ai.breakOppAfter && ai.isHyphenated);
+ this.addElementsForAHyphen(baseList, alignment, this.hyphIPD,
+ widthIfNoBreakOccurs, ai.breakOppAfter && ai.isHyphenated);
} else if (suppressibleLetterSpace) {
// the word fragment ends with a character that acts as a hyphen
// if a break occurs the width does not increase,
// otherwise there is one more letter space
- addElementsForAHyphen(baseList, alignment, 0, letterSpaceWidth, true);
+ this.addElementsForAHyphen(baseList, alignment, 0, letterSpaceWidth, true);
}
}
// static final int SOFT_HYPHEN_PENALTY = KnuthPenalty.FLAGGED_PENALTY / 10;
- static final int SOFT_HYPHEN_PENALTY = 1;
+ private static final int SOFT_HYPHEN_PENALTY = 1;
- private void addElementsForAHyphen(List baseList,
- int alignment,
- int widthIfBreakOccurs,
+ private void addElementsForAHyphen(final List baseList,
+ final int alignment,
+ final int widthIfBreakOccurs,
MinOptMax widthIfNoBreakOccurs,
- boolean unflagged) {
+ final boolean unflagged) {
if (widthIfNoBreakOccurs == null) {
- widthIfNoBreakOccurs = ZERO_MINOPTMAX;
+ widthIfNoBreakOccurs = TextLayoutManager.ZERO_MINOPTMAX;
}
switch (alignment) {
case EN_CENTER :
// centered text:
- baseList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
- baseList.add(new KnuthGlue(lineEndBAP, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- auxiliaryPosition, true));
- baseList.add(new KnuthPenalty(hyphIPD,
- unflagged ? SOFT_HYPHEN_PENALTY : KnuthPenalty.FLAGGED_PENALTY, !unflagged,
- auxiliaryPosition, false));
- baseList.add(new KnuthGlue(-(lineEndBAP + lineStartBAP),
- -6 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- auxiliaryPosition, false));
- baseList.add(makeAuxiliaryZeroWidthBox());
- baseList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
- baseList.add(new KnuthGlue(lineStartBAP, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- auxiliaryPosition, true));
+ baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
+ baseList.add(new KnuthGlue(this.lineEndBAP,
+ 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+ this.auxiliaryPosition, true));
+ baseList.add(new KnuthPenalty(this.hyphIPD,
+ unflagged ? TextLayoutManager.SOFT_HYPHEN_PENALTY
+ : KnuthPenalty.FLAGGED_PENALTY, !unflagged,
+ this.auxiliaryPosition, false));
+ baseList.add(new KnuthGlue(-(this.lineEndBAP + this.lineStartBAP),
+ -6 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+ this.auxiliaryPosition, false));
+ baseList.add(this.makeAuxiliaryZeroWidthBox());
+ baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
+ baseList.add(new KnuthGlue(this.lineStartBAP,
+ 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+ this.auxiliaryPosition, true));
break;
case EN_START : // fall through
case EN_END :
// left- or right-aligned text:
- if (lineStartBAP != 0 || lineEndBAP != 0) {
- baseList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
- baseList.add(new KnuthGlue(lineEndBAP, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- auxiliaryPosition, false));
+ if (this.lineStartBAP != 0 || this.lineEndBAP != 0) {
+ baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
+ baseList.add(new KnuthGlue(this.lineEndBAP,
+ 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+ this.auxiliaryPosition, false));
baseList.add(new KnuthPenalty(widthIfBreakOccurs,
- unflagged ? SOFT_HYPHEN_PENALTY : KnuthPenalty.FLAGGED_PENALTY, !unflagged,
- auxiliaryPosition, false));
- baseList.add(new KnuthGlue(widthIfNoBreakOccurs.opt - (lineStartBAP + lineEndBAP),
- -3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- auxiliaryPosition, false));
- baseList.add(makeAuxiliaryZeroWidthBox());
- baseList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
- baseList.add(new KnuthGlue(lineStartBAP, 0, 0,
- auxiliaryPosition, false));
+ unflagged ? TextLayoutManager.SOFT_HYPHEN_PENALTY
+ : KnuthPenalty.FLAGGED_PENALTY, !unflagged,
+ this.auxiliaryPosition, false));
+ baseList.add(new KnuthGlue(widthIfNoBreakOccurs.opt
+ - (this.lineStartBAP + this.lineEndBAP), -3
+ * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+ this.auxiliaryPosition, false));
+ baseList.add(this.makeAuxiliaryZeroWidthBox());
+ baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
+ baseList.add(new KnuthGlue(this.lineStartBAP, 0, 0,
+ this.auxiliaryPosition, false));
} else {
- baseList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
+ baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
baseList.add(new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- auxiliaryPosition, false));
+ this.auxiliaryPosition, false));
baseList.add(new KnuthPenalty(widthIfBreakOccurs,
- unflagged ? SOFT_HYPHEN_PENALTY : KnuthPenalty.FLAGGED_PENALTY, !unflagged,
- auxiliaryPosition, false));
+ unflagged ? TextLayoutManager.SOFT_HYPHEN_PENALTY
+ : KnuthPenalty.FLAGGED_PENALTY, !unflagged,
+ this.auxiliaryPosition, false));
baseList.add(new KnuthGlue(widthIfNoBreakOccurs.opt,
-3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
- auxiliaryPosition, false));
+ this.auxiliaryPosition, false));
}
break;
default:
// justified text, or last line justified:
// just a flagged penalty
- if (lineStartBAP != 0 || lineEndBAP != 0) {
- baseList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
- baseList.add(new KnuthGlue(lineEndBAP, 0, 0,
- auxiliaryPosition, false));
+ if (this.lineStartBAP != 0 || this.lineEndBAP != 0) {
+ baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
+ baseList.add(new KnuthGlue(this.lineEndBAP, 0, 0,
+ this.auxiliaryPosition, false));
baseList.add(new KnuthPenalty(widthIfBreakOccurs,
- unflagged ? SOFT_HYPHEN_PENALTY : KnuthPenalty.FLAGGED_PENALTY, !unflagged,
- auxiliaryPosition, false));
+ unflagged ? TextLayoutManager.SOFT_HYPHEN_PENALTY
+ : KnuthPenalty.FLAGGED_PENALTY, !unflagged,
+ this.auxiliaryPosition, false));
// extra elements representing a letter space that is suppressed
// if a break occurs
if (widthIfNoBreakOccurs.min != 0
|| widthIfNoBreakOccurs.max != 0) {
- baseList.add(new KnuthGlue(widthIfNoBreakOccurs.opt - (lineStartBAP + lineEndBAP),
- widthIfNoBreakOccurs.max - widthIfNoBreakOccurs.opt,
- widthIfNoBreakOccurs.opt - widthIfNoBreakOccurs.min,
- auxiliaryPosition, false));
+ baseList
+ .add(new KnuthGlue(widthIfNoBreakOccurs.opt
+ - (this.lineStartBAP + this.lineEndBAP),
+ widthIfNoBreakOccurs.max
+ - widthIfNoBreakOccurs.opt,
+ widthIfNoBreakOccurs.opt
+ - widthIfNoBreakOccurs.min,
+ this.auxiliaryPosition, false));
} else {
- baseList.add(new KnuthGlue(-(lineStartBAP + lineEndBAP), 0, 0,
- auxiliaryPosition, false));
+ baseList.add(new KnuthGlue(-(this.lineStartBAP + this.lineEndBAP), 0, 0,
+ this.auxiliaryPosition, false));
}
- baseList.add(makeAuxiliaryZeroWidthBox());
- baseList.add(makeZeroWidthPenalty(KnuthPenalty.INFINITE));
- baseList.add(new KnuthGlue(lineStartBAP, 0, 0,
- auxiliaryPosition, false));
+ baseList.add(this.makeAuxiliaryZeroWidthBox());
+ baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
+ baseList.add(new KnuthGlue(this.lineStartBAP, 0, 0,
+ this.auxiliaryPosition, false));
} else {
baseList.add(new KnuthPenalty(widthIfBreakOccurs,
- unflagged ? SOFT_HYPHEN_PENALTY : KnuthPenalty.FLAGGED_PENALTY, !unflagged,
- auxiliaryPosition, false));
+ unflagged ? TextLayoutManager.SOFT_HYPHEN_PENALTY
+ : KnuthPenalty.FLAGGED_PENALTY, !unflagged,
+ this.auxiliaryPosition, false));
// extra elements representing a letter space that is suppressed
// if a break occurs
if (widthIfNoBreakOccurs.min != 0
@@ -1319,11 +1284,11 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
baseList.add(new KnuthGlue(widthIfNoBreakOccurs.opt,
widthIfNoBreakOccurs.max - widthIfNoBreakOccurs.opt,
widthIfNoBreakOccurs.opt - widthIfNoBreakOccurs.min,
- auxiliaryPosition, false));
+ this.auxiliaryPosition, false));
}
}
}
-
+
}
}
diff --git a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
index 6a3a38db1..9d08415ff 100644
--- a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
@@ -26,7 +26,6 @@ import java.util.ListIterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.fo.flow.ListItem;
@@ -39,12 +38,14 @@ import org.apache.fop.layoutmgr.ConditionalElementListener;
import org.apache.fop.layoutmgr.ElementListObserver;
import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.KeepUtil;
+import org.apache.fop.layoutmgr.KnuthBlockBox;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthPenalty;
import org.apache.fop.layoutmgr.KnuthPossPosIter;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.LayoutManager;
+import org.apache.fop.layoutmgr.ListElement;
import org.apache.fop.layoutmgr.NonLeafPosition;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
@@ -279,8 +280,7 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager
int keepWithNextActive = BlockLevelLayoutManager.KEEP_AUTO;
LinkedList returnList = new LinkedList();
- while ((step = getNextStep(elementLists, start, end, partialHeights))
- > 0) {
+ while ((step = getNextStep(elementLists, start, end, partialHeights)) > 0) {
if (end[0] + 1 == elementLists[0].size()) {
keepWithNextActive = Math.max(keepWithNextActive, keepWithNextPendingOnLabel);
@@ -312,11 +312,33 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager
int boxHeight = step - addedBoxHeight - penaltyHeight;
penaltyHeight += additionalPenaltyHeight; //Add AFTER calculating boxHeight!
+ // collect footnote information
+ // TODO this should really not be done like this. ListItemLM should remain as
+ // footnote-agnostic as possible
+ LinkedList footnoteList = null;
+ ListElement el;
+ for (int i = 0; i < elementLists.length; i++) {
+ for (int j = start[i]; j <= end[i]; j++) {
+ el = (ListElement) elementLists[i].get(j);
+ if (el instanceof KnuthBlockBox && ((KnuthBlockBox) el).hasAnchors()) {
+ if (footnoteList == null) {
+ footnoteList = new LinkedList();
+ }
+ footnoteList.addAll(((KnuthBlockBox) el).getFootnoteBodyLMs());
+ }
+ }
+ }
+
// add the new elements
addedBoxHeight += boxHeight;
ListItemPosition stepPosition = new ListItemPosition(this,
start[0], end[0], start[1], end[1]);
- returnList.add(new KnuthBox(boxHeight, stepPosition, false));
+ if (footnoteList == null) {
+ returnList.add(new KnuthBox(boxHeight, stepPosition, false));
+ } else {
+ returnList.add(new KnuthBlockBox(boxHeight, footnoteList, stepPosition, false));
+ }
+
if (addedBoxHeight < totalHeight) {
int strength = BlockLevelLayoutManager.KEEP_AUTO;
strength = Math.max(strength, keepWithNextActive);
diff --git a/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java b/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java
index feb4b67ac..4012b0c00 100644
--- a/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java
+++ b/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java
@@ -19,12 +19,12 @@
package org.apache.fop.layoutmgr.table;
+import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.flow.table.ConditionalBorder;
import org.apache.fop.fo.flow.table.EffRow;
@@ -32,6 +32,7 @@ import org.apache.fop.fo.flow.table.PrimaryGridUnit;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.ElementListUtils;
+import org.apache.fop.layoutmgr.KnuthBlockBox;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthPenalty;
@@ -101,6 +102,8 @@ class ActiveCell {
private int penaltyLength;
/** Value of the penalty ending this step, 0 if the step does not end on a penalty. */
private int penaltyValue;
+ /** List of footnotes for this step. */
+ private List footnoteList;
/**
* One of {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN},
* {@link Constants#EN_PAGE}, {@link Constants#EN_EVEN_PAGE},
@@ -130,6 +133,7 @@ class ActiveCell {
this.totalLength = other.totalLength;
this.penaltyLength = other.penaltyLength;
this.penaltyValue = other.penaltyValue;
+ this.footnoteList = other.footnoteList;
this.condBeforeContentLength = other.condBeforeContentLength;
this.breakClass = other.breakClass;
}
@@ -293,6 +297,7 @@ class ActiveCell {
afterNextStep.penaltyValue = 0;
afterNextStep.condBeforeContentLength = 0;
afterNextStep.breakClass = Constants.EN_AUTO;
+ afterNextStep.footnoteList = null;
boolean breakFound = false;
boolean prevIsBox = false;
boolean boxFound = false;
@@ -322,6 +327,12 @@ class ActiveCell {
}
prevIsBox = false;
} else {
+ if (el instanceof KnuthBlockBox && ((KnuthBlockBox) el).hasAnchors()) {
+ if (afterNextStep.footnoteList == null) {
+ afterNextStep.footnoteList = new LinkedList();
+ }
+ afterNextStep.footnoteList.addAll(((KnuthBlockBox) el).getFootnoteBodyLMs());
+ }
prevIsBox = true;
boxFound = true;
afterNextStep.contentLength += el.getW();
@@ -543,6 +554,18 @@ class ActiveCell {
}
}
+ /**
+ * Adds the footnotes (if any) that are part of the next step, if this cell
+ * contributes content to the next step.
+ *
+ * @param footnoteList the list to which this cell must add its footnotes
+ */
+ void addFootnotes(List footnoteList) {
+ if (includedInLastStep() && nextStep.footnoteList != null) {
+ footnoteList.addAll(nextStep.footnoteList);
+ }
+ }
+
int getKeepWithNextStrength() {
return keepWithNextStrength;
}
diff --git a/src/java/org/apache/fop/layoutmgr/table/TableStepper.java b/src/java/org/apache/fop/layoutmgr/table/TableStepper.java
index f514844ac..7c963338f 100644
--- a/src/java/org/apache/fop/layoutmgr/table/TableStepper.java
+++ b/src/java/org/apache/fop/layoutmgr/table/TableStepper.java
@@ -33,6 +33,7 @@ import org.apache.fop.fo.flow.table.PrimaryGridUnit;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.BreakElement;
import org.apache.fop.layoutmgr.KeepUtil;
+import org.apache.fop.layoutmgr.KnuthBlockBox;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthGlue;
@@ -199,12 +200,14 @@ public class TableStepper {
}
}
+ LinkedList footnoteList = new LinkedList();
//Put all involved grid units into a list
List cellParts = new java.util.ArrayList(columnCount);
for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
ActiveCell activeCell = (ActiveCell) iter.next();
CellPart part = activeCell.createCellPart();
cellParts.add(part);
+ activeCell.addFootnotes(footnoteList);
}
//Create elements for step
@@ -217,7 +220,13 @@ public class TableStepper {
tcpos.setFlag(TableContentPosition.FIRST_IN_ROWGROUP, true);
}
lastTCPos = tcpos;
- returnList.add(new KnuthBox(boxLen, tcpos, false));
+
+ // TODO TableStepper should remain as footnote-agnostic as possible
+ if (footnoteList.isEmpty()) {
+ returnList.add(new KnuthBox(boxLen, tcpos, false));
+ } else {
+ returnList.add(new KnuthBlockBox(boxLen, footnoteList, tcpos, false));
+ }
int effPenaltyLen = Math.max(0, penaltyOrGlueLen);
TableHFPenaltyPosition penaltyPos = new TableHFPenaltyPosition(getTableLM());