]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Do text align before the line is rendered, not when the line is closed.
authorJoerg Pietschmann <pietsch@apache.org>
Sun, 2 Mar 2003 16:55:18 +0000 (16:55 +0000)
committerJoerg Pietschmann <pietsch@apache.org>
Sun, 2 Mar 2003 16:55:18 +0000 (16:55 +0000)
Moved page number resolving to just before text align. Removed page
number resolving from renderers.
Also, fix leader expansion in case page number resolving has eaten up
too much space for the page number, resolving in a possible area overflow.
Leaders may now be shortened down to leader-length.minimum if necessary.
PR: 1130, 17194

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/fop-0_20_2-maintain@196009 13f79535-47bb-0310-9956-ffa450edef68

16 files changed:
CHANGES
src/org/apache/fop/layout/FontState.java
src/org/apache/fop/layout/LineArea.java
src/org/apache/fop/layout/inline/InlineArea.java
src/org/apache/fop/layout/inline/PageNumberInlineArea.java
src/org/apache/fop/layout/inline/WordArea.java
src/org/apache/fop/render/AbstractRenderer.java
src/org/apache/fop/render/PrintRenderer.java
src/org/apache/fop/render/Renderer.java
src/org/apache/fop/render/awt/AWTRenderer.java
src/org/apache/fop/render/pcl/PCLRenderer.java
src/org/apache/fop/render/pdf/PDFRenderer.java
src/org/apache/fop/render/ps/PSRenderer.java
src/org/apache/fop/render/svg/SVGRenderer.java
src/org/apache/fop/render/txt/TXTRenderer.java
src/org/apache/fop/render/xml/XMLRenderer.java

diff --git a/CHANGES b/CHANGES
index 2ad552aa3d01bc1d7c14638e77bfe668b7b195cb..52fd9e6eccac515225eb4bdcc94df3634ce3d51b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,7 @@
 ==============================================================================
 Done since 0.20.4 release
+- Fixed text alingment for lines containing forward pointing page number
+  citations. This should greatly improve TOC layout. (J.Pietschmann)
 - Fixed repeatedly laid out small caps text (for example in static
   content or due ot keeps). (J.Pietschmann)
 - Fixed marker handling thouroughly. All retrieving boundaries and
index 55fd26a5890ebfaa9a45180e84aa5bb37c81d2b2..08c14957652790f1475f37d7609a3062b4a8a53c 100644 (file)
@@ -215,14 +215,118 @@ public class FontState {
         }
 
         // Use default CodePointMapping
-    char d = CodePointMapping.getMapping("WinAnsiEncoding").mapChar(c);
-    if (d != 0) {
-        c = d;
-    } else {
-        c = '#';
+        char d = CodePointMapping.getMapping("WinAnsiEncoding").mapChar(c);
+        if (d != 0) {
+            c = d;
+        } else {
+            c = '#';
+        }
+        return c;
     }
 
-        return c;
+    private int enWidth=-1;
+    private int emWidth=-1;
+
+    private final int getEmWidth() {
+        if (emWidth<0) {
+            char mappedChar = mapChar('m');
+            // The mapping returns '#' for unmapped characters in
+            // standard fonts.  What happens for other fonts?
+            if (mappedChar == '#') {
+                emWidth = 500 * getFontSize();
+            } else {
+                emWidth = width(mappedChar);
+            }
+        }
+        return emWidth;
+    }
+
+    private final int getEnWidth() {
+        if (enWidth<0) {
+            char mappedChar = mapChar('n');
+            // The mapping returns '#' for unmapped characters in
+            // standard fonts.  What happens for other fonts?
+            if (mappedChar != '#') {
+                // Should do something to discover non-proportional fonts.
+                enWidth = (getEmWidth()*9)/10;
+            } else {
+                enWidth = width(mappedChar);
+            }
+        }
+        return enWidth;
+    }
+
+    /**
+     * Helper method for getting the width of a unicode char
+     * from the current fontstate.
+     * This also performs some guessing on widths on various
+     * versions of space that might not exists in the font.
+     */
+    public int getCharWidth(char c) {
+        if ((c == '\n') || (c == '\r') || (c == '\t')) {
+            return getCharWidth(' ');
+        } else {
+            char mappedChar = mapChar(c);
+            if (mappedChar == '#' || mappedChar == 0) {
+                // Estimate the width of spaces not represented in
+                // the font
+                if (c == '#') {
+                    return width(mappedChar);
+                } else if (c == ' ') {
+                    return getEmWidth();
+                } else if (c == '\u00A0') {
+                    return getCharWidth(' ');
+                } else if (c == '\u2000') {
+                    return getEnWidth();
+                } else if (c == '\u2001') {
+                    return getEmWidth();
+                } else if (c == '\u2002') {
+                    return getEnWidth();
+                } else if (c == '\u2003') {
+                    return getEmWidth();
+                } else if (c == '\u2004') {
+                    return getEmWidth() / 3;
+                } else if (c == '\u2005') {
+                    return getEmWidth() / 4;
+                } else if (c == '\u2006') {
+                    return getEmWidth() / 6;
+                } else if (c == '\u2007') {
+                    return getCharWidth(' ');
+                } else if (c == '\u2008') {
+                    return getCharWidth('.');
+                } else if (c == '\u2009') {
+                    return getEmWidth() / 5;
+                } else if (c == '\u200A') {
+                    return getEmWidth() / 10;
+                } else if (c == '\u200B') {
+                    return 1;
+                } else if (c == '\u202F') {
+                    return getCharWidth(' ') / 2;
+                } else if (c == '\u3000') {
+                    return getCharWidth(' ') * 2;
+                } else {
+                    return width(mappedChar);
+                }
+            } else {
+                return width(mappedChar);
+            }
+        }
+    }
+
+    /**
+     * Calculates the word width.
+     */
+    public int getWordWidth(String word) {
+        if (word == null)
+            return 0;
+        int wordLength = word.length();
+        int width = 0;
+        char[] characters = new char[wordLength];
+        word.getChars(0, wordLength, characters, 0);
+        for (int i = 0; i < wordLength; i++) {
+            width += getCharWidth(characters[i]);
+        }
+        return width;
     }
 
 }
index cc901e0330b3cccd75bc391aecb1171b082e79e1..7b47b4d31acdaf7390b28b49bf3a9c0bbd6bc29d 100644 (file)
  */ 
 package org.apache.fop.layout;
 
+// Java
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+import java.awt.Rectangle;
+
 // FOP
-import org.apache.fop.render.Renderer;
-import org.apache.fop.messaging.MessageHandler;
-import org.apache.fop.layout.inline.*;
-import org.apache.fop.fo.properties.WrapOption;
-import org.apache.fop.fo.properties.WhiteSpaceCollapse;
-import org.apache.fop.fo.properties.TextAlign;
-import org.apache.fop.fo.properties.LeaderPattern;
+import org.apache.fop.datatypes.IDReferences;
 import org.apache.fop.fo.properties.Hyphenate;
 import org.apache.fop.fo.properties.LeaderAlignment;
+import org.apache.fop.fo.properties.LeaderPattern;
+import org.apache.fop.fo.properties.TextAlign;
 import org.apache.fop.fo.properties.VerticalAlign;
+import org.apache.fop.fo.properties.WhiteSpaceCollapse;
+import org.apache.fop.fo.properties.WrapOption;
 import org.apache.fop.layout.hyphenation.Hyphenation;
 import org.apache.fop.layout.hyphenation.Hyphenator;
-
-// Java
-import java.util.ArrayList;
-import java.util.StringTokenizer;
-import java.awt.Rectangle;
+import org.apache.fop.layout.inline.*;
+import org.apache.fop.messaging.MessageHandler;
+import org.apache.fop.render.Renderer;
 
 public class LineArea extends Area {
 
@@ -81,24 +82,27 @@ public class LineArea extends Area {
     protected int endIndent;
 
     private int placementOffset;
+    private int textAlign;
 
     private FontState currentFontState;    // not the nominal, which is
     // in this.fontState
     private float red, green, blue;
     private int wrapOption;
     private int whiteSpaceCollapse;
-    int vAlign;
+    private int vAlign;
 
     /* hyphenation */
-    HyphenationProps hyphProps;
+    private HyphenationProps hyphProps;
 
     /*
      * the width of text that has definitely made it into the line
      * area
      */
-    protected int finalWidth = 0;
+    private int finalWidth = 0;
 
-    /* the position to shift a link rectangle in order to compensate for links embedded within a word */
+    /* the position to shift a link rectangle in order to compensate
+     * for links embedded within a word
+     */
     protected int embeddedLinkStart = 0;
 
     /* the width of the current word so far */
@@ -111,33 +115,31 @@ public class LineArea extends Area {
     protected static final int MULTIBYTECHAR = 3;
 
     /* the character type of the previous character */
-    protected int prev = NOTHING;
-
-    /* the position in data[] of the start of the current word */
-    // protected int wordStart;
-
-    /* the length (in characters) of the current word */
-    // protected int wordLength = 0;
+    private int prev = NOTHING;
 
     /* width of spaces before current word */
-    protected int spaceWidth = 0;
+    private  int spaceWidth = 0;
 
     /*
      * the inline areas that have not yet been added to the line
      * because subsequent characters to come (in a different addText)
      * may be part of the same word
      */
-    protected ArrayList pendingAreas = new ArrayList();
+    private ArrayList pendingAreas = new ArrayList();
 
     /* the width of the pendingAreas */
-    /* public for problem check in AbstractRenderer */
-    public int pendingWidth = 0;
+    private int pendingWidth = 0;
 
     /* text-decoration of the previous text */
     protected boolean prevUlState = false;
     protected boolean prevOlState = false;
     protected boolean prevLTState = false;
 
+    // Whether the line has already be aligned text and expanded
+    // leaders.
+    private boolean aligned = false;
+    private boolean hasPageNumbers = false;
+
     public class Leader {
         int leaderPattern;
         int leaderLengthMinimum;
@@ -177,24 +179,27 @@ public class LineArea extends Area {
             this.placementOffset=placementOffset;
             this.position = position;
         }
-        void expand(int leaderLength) {
+        void expand() {
             char dot = '.';
-            int dotWidth =  getCharWidth(dot);
+            int dotWidth =  currentFontState.getCharWidth(dot);
             char space = ' ';
-            int spaceWidth = getCharWidth(space);
+            int spaceWidth = currentFontState.getCharWidth(space);
             int idx=children.indexOf(this);
             children.remove(this);
             switch (leaderPattern) {
             case LeaderPattern.SPACE:
-                InlineSpace spaceArea = new InlineSpace(leaderLength,false);
+                InlineSpace spaceArea = new InlineSpace(leaderLengthOptimum
+                                                        , false);
                 children.add(idx,spaceArea);
                 break;
             case LeaderPattern.RULE:
-                LeaderArea leaderArea = new LeaderArea(this.fontState, this.red, this.green,
-                                                       this.blue, "", leaderLength,
-                                                       this.leaderPattern,
-                                                       this.ruleThickness, this.ruleStyle);
-                leaderArea.setYOffset(this.placementOffset);
+                LeaderArea leaderArea = new LeaderArea(fontState, red, green,
+                                                       blue, "",
+                                                       leaderLengthOptimum,
+                                                       leaderPattern,
+                                                       ruleThickness,
+                                                       ruleStyle);
+                leaderArea.setYOffset(placementOffset);
                 children.add(idx,leaderArea);
                 break;
             case LeaderPattern.DOTS:
@@ -229,19 +234,19 @@ public class LineArea extends Area {
                             // shorten leaderLength, otherwise - in
                             // case of leaderLength=remaining length -
                             // it will cut off the end of leaderlength
-                            leaderLength -= spaceBeforeLeader;
+                            leaderLengthOptimum -= spaceBeforeLeader;
                         }
                     }
-                    int factor = (int)Math.floor(leaderLength / dotWidth);
+                    int factor = (int)Math.floor(leaderLengthOptimum / dotWidth);
                     char[] leaderChars = new char[factor];
                     for (int i = 0; i < factor; i++) {
                         leaderChars[i] = dot;
                     }
                     WordArea leaderPatternArea =
-                        new WordArea(currentFontState,
-                                     this.red, this.green, this.blue,
-                                     new String(leaderChars), leaderLength);
-                    leaderPatternArea.setYOffset(this.placementOffset);
+                        new WordArea(currentFontState, red, green, blue,
+                                     new String(leaderChars),
+                                     leaderLengthOptimum);
+                    leaderPatternArea.setYOffset(placementOffset);
                     children.add(idx, leaderPatternArea);
                 } else {
                     // if leader-alignment is used, calculate space to
@@ -263,33 +268,34 @@ public class LineArea extends Area {
                             // shorten leaderLength, otherwise - in
                             // case of leaderLength=remaining length -
                             // it will cut off the end of leaderlength
-                            leaderLength -= spaceBeforeLeader;
+                            leaderLengthOptimum -= spaceBeforeLeader;
                         }
                     }
                     // calculate the space to insert between the dots
                     // and create a inline area with this width
                     int dotsFactor =
-                        (int)Math.floor(((double)leaderLength)
-                                        / ((double)this.leaderPatternWidth));
+                        (int)Math.floor(((double)leaderLengthOptimum)
+                                        / ((double)leaderPatternWidth));
                     // add combination of dot + space to fill leader
                     // is there a way to do this in a more effective way?
                     for (int i = 0; i < dotsFactor; i++) {
                         InlineSpace spaceBetweenDots =
-                            new InlineSpace(this.leaderPatternWidth - dotWidth, false);
+                            new InlineSpace(leaderPatternWidth - dotWidth,
+                                            false);
                         WordArea leaderPatternArea =
                             new WordArea(this.fontState,
                                          this.red, this.green, this.blue,
                                          new String("."), dotWidth);
-                        leaderPatternArea.setYOffset(this.placementOffset);
+                        leaderPatternArea.setYOffset(placementOffset);
                         children.add(idx,leaderPatternArea);
                         idx++;
                         children.add(idx,spaceBetweenDots);
                         idx++;
                     }
                     // append at the end some space to fill up to leader length
-                    children.add(idx,new InlineSpace(leaderLength
+                    children.add(idx,new InlineSpace(leaderLengthOptimum
                                                      - dotsFactor
-                                                     * this.leaderPatternWidth));
+                                                     * leaderPatternWidth));
                     idx++;
                 }
                 break;
@@ -355,6 +361,153 @@ public class LineArea extends Area {
     }
 
     public void render(Renderer renderer) {
+        if (pendingWidth > 0) {
+            MessageHandler.error("Areas pending, text probably lost in line"
+                                 + getLineText());
+        }
+        if (hasPageNumbers) {
+            IDReferences idReferences = renderer.getIDReferences();
+            for (int i = 0; i < children.size(); i++) {
+                Object o = children.get(i);
+                if ( o instanceof PageNumberInlineArea) {
+                    PageNumberInlineArea pia = (PageNumberInlineArea)o;
+                    FontState piaFontState = pia.getFontState();
+                    finalWidth-=piaFontState.getWordWidth(pia.getText());
+                    pia.resolve(idReferences);
+                    finalWidth+=piaFontState.getWordWidth(pia.getText());
+                }
+            }
+        }
+        if (!aligned) {
+            int padding = 0;
+            switch (textAlign) {
+            case TextAlign.START:      // left
+                padding = this.getContentWidth() - finalWidth;
+                endIndent += padding;
+                for (int i = 0; i < children.size(); i++) {
+                    Object o = children.get(i);
+                    if (o instanceof LineArea.Leader) {
+                        LineArea.Leader leader = (LineArea.Leader)o;
+                        leader.expand();
+                    }
+                }
+                break;
+            case TextAlign.END:        // right
+                padding = this.getContentWidth() - finalWidth;
+                startIndent += padding;
+                for (int i = 0; i < children.size(); i++) {
+                    Object o = children.get(i);
+                    if (o instanceof LineArea.Leader) {
+                        LineArea.Leader leader = (LineArea.Leader)o;
+                        leader.expand();
+                    }
+                }
+                break;
+            case TextAlign.CENTER:     // center
+                padding = (this.getContentWidth() - finalWidth) / 2;
+                startIndent += padding;
+                endIndent += padding;
+                for (int i = 0; i < children.size(); i++) {
+                    Object o = children.get(i);
+                    if (o instanceof LineArea.Leader) {
+                        LineArea.Leader leader = (LineArea.Leader)o;
+                        leader.expand();
+                    }
+                }
+                break;
+            case TextAlign.JUSTIFY:    // justify
+                // first pass - count the spaces
+                int leaderCount = 0;
+                int spaceCount = 0;
+                for (int i = 0; i < children.size(); i++ ) {
+                    Object o = children.get(i);
+                    if (o instanceof InlineSpace) {
+                        InlineSpace space = (InlineSpace)o;
+                        if (space.getResizeable()) {
+                            spaceCount++;
+                        }
+                    } else if(o instanceof LineArea.Leader) {
+                        leaderCount++;
+                    }
+                }
+                padding = (this.getContentWidth() - finalWidth);
+                if (padding!=0) {
+                    if (leaderCount>0) {
+                        int offset=0;
+                        for (int i = 0; i < children.size(); i++) {
+                            Object o = children.get(i);
+                            if (o instanceof LineArea.Leader) {
+                                LineArea.Leader leader = (LineArea.Leader)o;
+                                int leaderExpansionMaximum=
+                                    leader.leaderLengthMaximum - leader.leaderLengthOptimum;
+                                int leaderExpansionMinimum=
+                                    leader.leaderLengthMinimum - leader.leaderLengthOptimum;
+                                if (leaderExpansionMaximum < padding) {
+                                    leader.leaderLengthOptimum =
+                                        leader.leaderLengthMaximum;
+                                    leader.expand();
+                                    padding-=leaderExpansionMaximum;
+                                    offset+=leaderExpansionMaximum;
+                                } else if (padding < leaderExpansionMinimum) {
+                                    leader.leaderLengthOptimum =
+                                        leader.leaderLengthMinimum;
+                                    leader.expand();
+                                    padding-=leaderExpansionMinimum;
+                                    offset+=leaderExpansionMinimum;
+                                } else {
+                                    leader.leaderLengthOptimum += padding;
+                                    leader.expand();
+                                    padding=0;
+                                    offset+=padding;
+                                }
+                            } else if (o instanceof InlineArea) {
+                                ((InlineArea)o).setXOffset(((InlineArea)o).getXOffset() + offset);
+                            }
+                        }
+                    }
+                    if (padding != 0) {
+                        if (spaceCount > 0) {
+                            if (padding > 0) {
+                                // The line is actually short of
+                                // padding mod spaceCount
+                                // millipoints. Should implement
+                                // Bresenham-like algorithm for
+                                // compensating, but it's not worth
+                                // yet.
+                                // If there are ref-area aligned leaders,
+                                // they will be no longer aligned.
+                                padding = padding/spaceCount;
+                                spaceCount = 0;
+                                // second pass - add additional space
+                                for (int i = 0; i < children.size(); i++) {
+                                    Object o = children.get(i);
+                                    if (o instanceof InlineSpace) {
+                                        InlineSpace space = (InlineSpace)o;
+                                        if (space.getResizeable()) {
+                                            space.setSize(space.getSize() + padding);
+                                            spaceCount++;
+                                        }
+                                    } else if (o instanceof InlineArea) {
+                                        ((InlineArea)o).setXOffset(((InlineArea)o).getXOffset() + i * padding);
+                                    }
+                                }
+                            } else {
+                                MessageHandler.log("Area overflow in line "
+                                                   + getLineText());
+                            }
+                        } else {
+                            // no spaces
+                            MessageHandler.log("No spaces to justify text in line "
+                                               + getLineText());
+                        }
+                    }
+                }
+                break;
+            default: 
+                MessageHandler.errorln("bad align: "+textAlign);
+            break;
+            }
+        }
         renderer.renderLineArea(this);
     }
 
@@ -368,7 +521,7 @@ public class LineArea extends Area {
         // Space must be allocated for the page number, so currently we
         // give it 3 spaces
 
-        int width = 3*getCharWidth(' ');
+        int width = 3*currentFontState.getCharWidth(' ');
 
 
         PageNumberInlineArea pia
@@ -380,6 +533,7 @@ public class LineArea extends Area {
         pendingAreas.add(pia);
         pendingWidth += width;
         prev = TEXT;
+        hasPageNumbers = true;
 
         return -1;
     }
@@ -402,7 +556,7 @@ public class LineArea extends Area {
         int wordLength = 0;
         int wordWidth = 0;
         // With CID fonts, space isn't neccesary currentFontState.width(32)
-        int whitespaceWidth = getCharWidth(' ');
+        int whitespaceWidth = currentFontState.getCharWidth(' ');
 
         boolean isText = false;
         boolean isMultiByteChar = false;
@@ -414,7 +568,7 @@ public class LineArea extends Area {
             char c = data[i];
             if (!(isSpace(c) || (c == '\n') || (c == '\r') || (c == '\t')
                   || (c == '\u2028'))) {
-                charWidth = getCharWidth(c);
+                charWidth = currentFontState.getCharWidth(c);
                 isText = true;
                 isMultiByteChar = (c > 127);
                 // Add support for zero-width spaces
@@ -424,7 +578,7 @@ public class LineArea extends Area {
                 if ((c == '\n') || (c == '\r') || (c == '\t'))
                     charWidth = whitespaceWidth;
                 else
-                    charWidth = getCharWidth(c);
+                    charWidth = currentFontState.getCharWidth(c);
 
                 isText = false;
                 isMultiByteChar = false;
@@ -435,7 +589,7 @@ public class LineArea extends Area {
 
                     if (this.whiteSpaceCollapse == WhiteSpaceCollapse.FALSE) {
                         if (isSpace(c)) {
-                            spaceWidth += getCharWidth(c);
+                            spaceWidth += currentFontState.getCharWidth(c);
                         } else if (c == '\n' || c == '\u2028') {
                             // force line break
                             if (spaceWidth > 0) {
@@ -533,7 +687,7 @@ public class LineArea extends Area {
                     embeddedLinkStart =
                         0;    // reset embeddedLinkStart since a space was encountered
 
-                    spaceWidth = getCharWidth(c);
+                    spaceWidth = currentFontState.getCharWidth(c);
 
                     /*
                      * here is the place for white-space-treatment value 'ignore':
@@ -563,7 +717,7 @@ public class LineArea extends Area {
                     if (this.whiteSpaceCollapse == WhiteSpaceCollapse.FALSE) {
                         if (isSpace(c)) {
                             prev = WHITESPACE;
-                            spaceWidth = getCharWidth(c);
+                            spaceWidth = currentFontState.getCharWidth(c);
                         } else if (c == '\n') {
                             // force line break
                             // textdecoration not used because spaceWidth is 0
@@ -594,7 +748,9 @@ public class LineArea extends Area {
                     if ((finalWidth + spaceWidth + wordWidth)
                         > this.getContentWidth()) {
                         if (overrun)
-                            MessageHandler.log("area contents overflows area");
+                            MessageHandler.log("area contents overflows area "
+                                               + "in line "
+                                               + getLineText());
                         if (this.wrapOption == WrapOption.WRAP) {
                             return i;
                         }
@@ -706,7 +862,9 @@ public class LineArea extends Area {
                                 (wordStart == start) &&
                                 (finalWidth == 0)) {
 
-                                MessageHandler.log("area contents overflows area");
+                                MessageHandler.log("area contents overflows"
+                                                   + " area in line "
+                                                   + getLineText());
                                 addSpacedWord(new String(data, wordStart, wordLength - 1),
                                               ls,
                                               embeddedLinkStart,
@@ -764,7 +922,8 @@ public class LineArea extends Area {
         }
 
         if (overrun)
-            MessageHandler.log("area contents overflows area");
+            MessageHandler.log("area contents overflows area in line "
+                               + getLineText());
         return -1;
     }
 
@@ -822,111 +981,12 @@ public class LineArea extends Area {
     }
 
     /**
-     * aligns line area
-     *
+     * Store text alignment.
+     * The line is aligned immediately before rendering, after
+     * page numbers have been resolved.
      */
     public void align(int type) {
-        int padding = 0;
-
-        switch (type) {
-        case TextAlign.START:      // left
-            padding = this.getContentWidth() - finalWidth;
-            endIndent += padding;
-            for (int i = 0; i < children.size(); i++) {
-                Object o = children.get(i);
-                if (o instanceof LineArea.Leader) {
-                    LineArea.Leader leader = (LineArea.Leader)o;
-                    leader.expand(leader.leaderLengthOptimum);
-                }
-            }
-            break;
-        case TextAlign.END:        // right
-            padding = this.getContentWidth() - finalWidth;
-            startIndent += padding;
-            for (int i = 0; i < children.size(); i++) {
-                Object o = children.get(i);
-                if (o instanceof LineArea.Leader) {
-                    LineArea.Leader leader = (LineArea.Leader)o;
-                    leader.expand(leader.leaderLengthOptimum);
-                }
-            }
-            break;
-        case TextAlign.CENTER:     // center
-            padding = (this.getContentWidth() - finalWidth) / 2;
-            startIndent += padding;
-            endIndent += padding;
-            for (int i = 0; i < children.size(); i++) {
-                Object o = children.get(i);
-                if (o instanceof LineArea.Leader) {
-                    LineArea.Leader leader = (LineArea.Leader)o;
-                    leader.expand(leader.leaderLengthOptimum);
-                }
-            }
-            break;
-        case TextAlign.JUSTIFY:    // justify
-            // first pass - count the spaces
-            int leaderCount = 0;
-            int spaceCount = 0;
-            for (int i = 0; i < children.size(); i++ ) {
-                Object o = children.get(i);
-                if (o instanceof InlineSpace) {
-                    InlineSpace space = (InlineSpace)o;
-                    if (space.getResizeable()) {
-                        spaceCount++;
-                    }
-                } else if(o instanceof LineArea.Leader) {
-                    leaderCount++;
-                }
-            }
-            padding = (this.getContentWidth() - finalWidth);
-            if (padding>0) {
-                if (leaderCount>0) {
-                    int offset=0;
-                    for (int i = 0; i < children.size(); i++) {
-                        Object o = children.get(i);
-                        if (o instanceof LineArea.Leader) {
-                            LineArea.Leader leader = (LineArea.Leader)o;
-                            int leaderExpansionMaximum=
-                                leader.leaderLengthMaximum - leader.leaderLengthOptimum;
-                            if (leaderExpansionMaximum < padding) {
-                                leader.expand(leader.leaderLengthMaximum);
-                                padding-=leaderExpansionMaximum;
-                                offset+=leaderExpansionMaximum;
-                            } else {
-                                leader.expand(leader.leaderLengthOptimum + padding);
-                                padding=0;
-                                offset+=padding;
-                            }
-                        } else if (o instanceof InlineArea) {
-                            ((InlineArea)o).setXOffset(((InlineArea)o).getXOffset() + offset);
-                        }
-                    }
-                }
-                if (spaceCount > 0 && padding > 0) {
-                    padding = padding/spaceCount;
-                } else {               // no spaces
-                    padding = 0;
-                }
-                spaceCount = 0;
-                // second pass - add additional space
-                for (int i = 0; i < children.size(); i++) {
-                    Object o = children.get(i);
-                    if (o instanceof InlineSpace) {
-                        InlineSpace space = (InlineSpace)o;
-                        if (space.getResizeable()) {
-                            space.setSize(space.getSize() + padding);
-                            spaceCount++;
-                        }
-                    } else if (o instanceof InlineArea) {
-                        ((InlineArea)o).setXOffset(((InlineArea)o).getXOffset() + i * padding);
-                    }
-                }
-            }
-            break;
-        default: 
-            MessageHandler.errorln("bad align: "+type);
-            break;
-        }
+        textAlign = type;
     }
 
     /**
@@ -936,9 +996,9 @@ public class LineArea extends Area {
         int superHeight = -this.placementOffset;
         int maxHeight = this.allocationHeight;
         for (int i = 0; i < children.size(); i++ ) {
-            Box b = (Box)children.get(i);
-            if (b instanceof InlineArea) {
-                InlineArea ia = (InlineArea)b;
+            Object o = children.get(i);
+            if (o instanceof InlineArea) {
+                InlineArea ia = (InlineArea)o;
                 if (ia instanceof WordArea) {
                     ia.setYOffset(placementOffset);
                 }
@@ -953,7 +1013,7 @@ public class LineArea extends Area {
                     int fh = fontState.getAscender();
                     ia.setYOffset((int)(placementOffset + (2 * fh / 3.0)));
                 }
-            } else {}
+            }
         }
         // adjust the height of this line to the
         // resulting alignment height.
@@ -1018,7 +1078,7 @@ public class LineArea extends Area {
      * and wraps it in an InlineArea which is returned
      */
     private InlineArea buildSimpleLeader(char c, int leaderLength) {
-        int width = getCharWidth(c);
+        int width = currentFontState.getCharWidth(c);
         if (width == 0) {
             MessageHandler.errorln("char " + c
                                    + " has width 0. Using width 100 instead.");
@@ -1075,7 +1135,9 @@ public class LineArea extends Area {
                              TextState textState) {
         // check whether the language property has been set
         if (this.hyphProps.language.equalsIgnoreCase("none")) {
-            MessageHandler.errorln("if property 'hyphenate' is used, a language must be specified");
+            MessageHandler.errorln("if property 'hyphenate' is used, a "
+                                   + "language must be specified in line "
+                                   + getLineText());
             return wordStart;
         }
 
@@ -1100,7 +1162,8 @@ public class LineArea extends Area {
         String wordToHyphenate;
 
         // width of hyphenation character
-        int hyphCharWidth = getCharWidth(this.hyphProps.hyphenationChar);
+        int hyphCharWidth = currentFontState
+            .getCharWidth(this.hyphProps.hyphenationChar);
         remainingWidth -= hyphCharWidth;
 
         // handles ' or " at the beginning of the word
@@ -1115,7 +1178,7 @@ public class LineArea extends Area {
         // if the extracted word is smaller than the remaining width
         // we have a non letter character inside the word. at the moment
         // we will only handle hard hyphens and slashes
-        if (getWordWidth(wordToHyphenate) < remainingWidth) {
+        if (currentFontState.getWordWidth(wordToHyphenate) < remainingWidth) {
             inwordPunctuation =
                 characters[wordStart + remainingString.length()
                            + wordToHyphenate.length()];
@@ -1127,8 +1190,8 @@ public class LineArea extends Area {
                                        wordStart + remainingString.length()
                                        + wordToHyphenate.length() + 1);
                 remainingWidth -=
-                    (getWordWidth(wordToHyphenate)
-                     + getCharWidth(inwordPunctuation));
+                    (currentFontState.getWordWidth(wordToHyphenate)
+                     + currentFontState.getCharWidth(inwordPunctuation));
             }
         }
 
@@ -1172,24 +1235,6 @@ public class LineArea extends Area {
         return wordStart;
     }
 
-
-    /**
-     * Calculates the wordWidth using the actual fontstate
-     */
-    private int getWordWidth(String word) {
-        if (word == null)
-            return 0;
-        int wordLength = word.length();
-        int width = 0;
-        char[] characters = new char[wordLength];
-        word.getChars(0, wordLength, characters, 0);
-
-        for (int i = 0; i < wordLength; i++) {
-            width += getCharWidth(characters[i]);
-        }
-        return width;
-    }
-
     public int getRemainingWidth() {
         return this.getContentWidth() + startIndent - this.getCurrentXPosition();
     }
@@ -1220,7 +1265,7 @@ public class LineArea extends Area {
     public int addCharacter(char data, LinkSet ls, boolean ul) {
         WordArea ia = null;
         int remainingWidth = this.getRemainingWidth();
-        int width = getCharWidth(data);
+        int width = currentFontState.getCharWidth(data);
         // if it doesn't fit, return
         if (width > remainingWidth) {
             return org.apache.fop.fo.flow.Character.DOESNOT_FIT;
@@ -1294,7 +1339,7 @@ public class LineArea extends Area {
         pendingWidth = 0;
         pendingAreas = new ArrayList();
         String word = (wordBuf != null) ? wordBuf.toString() : "";
-        int wordWidth = this.getWordWidth(word);
+        int wordWidth = currentFontState.getWordWidth(word);
         WordArea hia = new WordArea(currentFontState,
                                     this.red, this.green, this.blue,
                                     word, wordWidth);
@@ -1333,7 +1378,7 @@ public class LineArea extends Area {
 
         for (int i = 0; i < numberOfHyphenationPoints; i++) {
             wordBegin = hyph.getPreHyphenText(i);
-            if (this.getWordWidth(wordBegin) > remainingWidth) {
+            if (currentFontState.getWordWidth(wordBegin) > remainingWidth) {
                 break;
             }
             index = i;
@@ -1358,87 +1403,6 @@ public class LineArea extends Area {
         return ret;
     }
 
-    private final int getEmWidth() {
-        char mappedChar = currentFontState.mapChar('m');
-        // the mapping returns '#' for unmapped characters in standard fonts
-        // what happens for other fonts?
-        if (mappedChar == '#') {
-            return 500 * currentFontState.getFontSize();
-        } else {
-            return currentFontState.width(mappedChar);
-        }
-    }
-
-    private final int getEnWidth() {
-        char mappedChar = currentFontState.mapChar('n');
-        // the mapping returns '#' for unmapped characters in standard fonts
-        // what happens for other fonts?
-        if (mappedChar != '#') {
-            // should do something to discover non-proportional fonts
-            return (getEmWidth()*9)/10;
-        } else {
-            return currentFontState.width(mappedChar);
-        }
-    }
-
-    /**
-     * Helper method for getting the width of a unicode char
-     * from the current fontstate.
-     * This also performs some guessing on widths on various
-     * versions of space that might not exists in the font.
-     */
-    private int getCharWidth(char c) {
-        if ((c == '\n') || (c == '\r') || (c == '\t')) {
-            return getCharWidth(' ');
-        } else {
-            char mappedChar = currentFontState.mapChar(c);
-            if (mappedChar == '#' || mappedChar == 0) {
-                // Estimate the width of spaces not represented in
-                // the font
-                if (c == '#') {
-                    return currentFontState.width(mappedChar);
-                } else if (c == ' ') {
-                    return getEmWidth();
-                } else if (c == '\u00A0') {
-                    return getCharWidth(' ');
-                } else if (c == '\u2000') {
-                    return getEnWidth();
-                } else if (c == '\u2001') {
-                    return getEmWidth();
-                } else if (c == '\u2002') {
-                    return getEnWidth();
-                } else if (c == '\u2003') {
-                    return getEmWidth();
-                } else if (c == '\u2004') {
-                    return getEmWidth() / 3;
-                } else if (c == '\u2005') {
-                    return getEmWidth() / 4;
-                } else if (c == '\u2006') {
-                    return getEmWidth() / 6;
-                } else if (c == '\u2007') {
-                    return getCharWidth(' ');
-                } else if (c == '\u2008') {
-                    return getCharWidth('.');
-                } else if (c == '\u2009') {
-                    return getEmWidth() / 5;
-                } else if (c == '\u200A') {
-                    return getEmWidth() / 10;
-                } else if (c == '\u200B') {
-                    return 1;
-                } else if (c == '\u202F') {
-                    return getCharWidth(' ') / 2;
-                } else if (c == '\u3000') {
-                    return getCharWidth(' ') * 2;
-                } else if (c == '\u3000') {
-                    return getCharWidth(' ') * 2;
-                } else {
-                    return currentFontState.width(mappedChar);
-                }
-            } else {
-                return currentFontState.width(mappedChar);
-            }
-        }
-    }
 
 
     /**
@@ -1501,7 +1465,8 @@ public class LineArea extends Area {
             if (currentWord.length() == 1
                 && (isNBSP(currentWord.charAt(0)))) {
                 // Add an InlineSpace
-                int spaceWidth = getCharWidth(currentWord.charAt(0));
+                int spaceWidth = currentFontState
+                    .getCharWidth(currentWord.charAt(0));
                 if (spaceWidth > 0) {
                     InlineSpace is = new InlineSpace(spaceWidth);
                     startw += spaceWidth;
@@ -1523,7 +1488,7 @@ public class LineArea extends Area {
                     }
                 }
             } else {
-                int wordWidth = getWordWidth(currentWord);
+                int wordWidth = currentFontState.getWordWidth(currentWord);
                 WordArea ia = new WordArea(currentFontState, this.red,
                                            this.green, this.blue,
                                            currentWord,
@@ -1554,5 +1519,23 @@ public class LineArea extends Area {
         }
     }
 
+    public String getLineText() {
+        StringBuffer b = new StringBuffer(120);
+        for (int i=0;i<children.size();i++) {
+            Object o = children.get(i);
+            if (o instanceof WordArea) {
+                b.append(((WordArea)o).getText());
+            } else if (o instanceof InlineSpace) {
+                b.append(' ');
+            } else if (o instanceof org.apache.fop.image.ImageArea) {
+                b.append("<img>");
+            } else {
+                b.append('<');
+                b.append(o.getClass().getName());
+                b.append('>');
+            }
+        }
+        return b.toString();
+    }
 }
 
index edd3b50c68e1d884df5c1662f738d8121fdb3823..f5341a52532cfe1989f7b0aaf8b5402a5aa7dc5e 100644 (file)
@@ -63,7 +63,6 @@ public abstract class InlineArea extends Area {
     private int xOffset = 0;
     protected int height = 0;
     private int verticalAlign = 0;
-    protected String pageNumberId = null;
     private float red, green, blue;
 
     // Textdecoration
@@ -125,10 +124,6 @@ public abstract class InlineArea extends Area {
         return this.xOffset;
     }
 
-    public String getPageNumberID() {
-        return pageNumberId;
-    }
-
     public void setUnderlined(boolean ul) {
         this.underlined = ul;
     }
index 4a014cf82a5c37be6abdf750f1ba52aca104f0e4..ff1811c46209834d2182cafc41367113d2bf3636 100644 (file)
  */ 
 package org.apache.fop.layout.inline;
 
-import org.apache.fop.layout.*;
+import org.apache.fop.layout.inline.WordArea;
+import org.apache.fop.layout.FontState;
+import org.apache.fop.datatypes.IDReferences;
 
 public class PageNumberInlineArea extends WordArea {
-
+    private String pageNumberId = null;
 
     public PageNumberInlineArea(FontState fontState, float red, float green,
                                 float blue, String refid, int width) {
@@ -61,4 +63,10 @@ public class PageNumberInlineArea extends WordArea {
         this.pageNumberId = refid;
     }
 
+    public void resolve(IDReferences idReferences) {
+        text = idReferences.getPageNumber(pageNumberId);
+        if (text == null) {
+            text = "";
+        }
+    }
 }
index 7983999e823c96966922cdb2d0bb13b4ae754df4..15f19a6f445c7aac16f48fc547f21451cbd61cbe 100644 (file)
@@ -55,7 +55,7 @@ import org.apache.fop.layout.FontState;
 
 public class WordArea extends InlineArea {
 
-    private String text;
+    protected String text;
 
     public WordArea(FontState fontState, float red, float green, float blue,
                     String text, int width) {
index fce3690562e85a5e3b06397113d189f9f71a22b1..01eea731dc5cf5fe0468ab6b348cacb5b591260e 100644 (file)
@@ -87,6 +87,8 @@ public abstract class AbstractRenderer implements Renderer {
      */
     protected int currentAreaContainerXPosition = 0;
 
+    protected IDReferences idReferences;
+
     public void setLogger(Logger logger) {
         log = logger;
     }
@@ -492,14 +494,6 @@ public abstract class AbstractRenderer implements Renderer {
      * @param area area to render
      */
     public void renderLineArea(LineArea area) {
-        if (area.pendingWidth > 0) {
-            final String pageNumber = (area.getPage() != null 
-                    ? area.getPage().getFormattedNumber()
-                    : "<unknown>");
-            log.error("Areas pending, text probably lost. Check Page " +
-                      pageNumber +
-                      " and following page.");
-        }
         int rx = this.currentAreaContainerXPosition + area.getStartIndent();
         int ry = this.currentYPosition;
         int w = area.getContentWidth();
@@ -542,4 +536,8 @@ public abstract class AbstractRenderer implements Renderer {
         if (page.getEnd() != null)
             page.getEnd().render(this);
     }
+
+    public IDReferences getIDReferences() {
+        return idReferences;
+    }
 }
index 409c803b5af3176b2954093ebea78cd825b30f7d..ad31fbc0c2a0a418103ffaa54a88ecbe4a8b9065 100644 (file)
@@ -134,11 +134,6 @@ public abstract class PrintRenderer extends AbstractRenderer {
 
     protected FontInfo fontInfo;
 
-    /**
-     * the IDReferences for this document
-     */
-    protected IDReferences idReferences;
-
     /**
      * set the document's producer
      * 
@@ -474,7 +469,6 @@ public abstract class PrintRenderer extends AbstractRenderer {
         prevOverlineColor = null;
         prevLineThroughColor = null;
         fontInfo = null;
-        this.idReferences = null;
     }
 
 }
index 4d55b617f0c536867d1192b432d4e59b3256607f..c0e1168883e1a981e2f6a45c29d90824b86fe9ac 100644 (file)
@@ -56,6 +56,7 @@ import org.apache.fop.image.ImageArea;
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.layout.*;
 import org.apache.fop.layout.inline.*;
+import org.apache.fop.datatypes.IDReferences;
 
 // Avalon
 import org.apache.avalon.framework.logger.Logger;
@@ -175,4 +176,5 @@ public interface Renderer {
     void stopRenderer(OutputStream outputStream)
         throws IOException;
 
+    IDReferences getIDReferences();
 }
index a8eb78a177e2bae1989295a180e532fa734beac9..98997901c45e23c6a64bb03748d1e7ef82e0b60a 100644 (file)
@@ -106,8 +106,6 @@ public class AWTRenderer extends AbstractRenderer implements Printable, Pageable
     protected Map fontStyles = new java.util.HashMap();
     protected Color saveColor = null;
 
-    protected IDReferences idReferences = null;
-
     /**
      * Image Object and Graphics Object. The Graphics Object is the Graphics
      * object that is contained withing the Image Object.
@@ -667,16 +665,7 @@ public class AWTRenderer extends AbstractRenderer implements Printable, Pageable
         int bl = this.currentYPosition;
 
 
-        String s;
-        if (area.getPageNumberID()
-                != null) {    // this text is a page number, so resolve it
-            s = idReferences.getPageNumber(area.getPageNumberID());
-            if (s == null) {
-                s = "";
-            }
-        } else {
-            s = area.getText();
-        }
+        String s = area.getText();
 
         Color oldColor = graphics.getColor();
         java.awt.Font oldFont = graphics.getFont();
index 28c6fb18859f31ec9dd16e2970318286ae6596e4..60838068a576869663b7d959edcbb16105706e70 100755 (executable)
@@ -684,15 +684,7 @@ public class PCLRenderer extends PrintRenderer {
         int rx = this.currentXPosition;
         int bl = this.currentYPosition;
 
-        String s;
-        if (area.getPageNumberID() != null) {
-            // this text is a page number, so resolve it
-            s = idReferences.getPageNumber(area.getPageNumberID());
-            if (s == null)
-                s = "";
-        } else {
-            s = area.getText();
-        }
+        String s = area.getText();
 
         addWordLines(area, rx, bl, size, theAreaColor);
 
index abb47c18eac5678609678b43f3a07e8948ce6aa0..097495ade5a0941171b0b70c2223f0dd2fbd41c1 100644 (file)
@@ -716,17 +716,7 @@ public class PDFRenderer extends PrintRenderer {
             prevWordWidth = area.getContentWidth();
             prevWordX = rx;
 
-            String s;
-            if (area.getPageNumberID()
-                    != null) {// this text is a page number, so resolve it
-                s = idReferences.getPageNumber(area.getPageNumberID());
-                if (s == null) {
-                    s = "";
-                }
-            } else {
-                s = area.getText();
-            }
-
+            String s = area.getText();
             int l = s.length();
 
             for (int i = 0; i < l; i++) {
index dcb6c4350373ddc74f6f15c68506bf3a4defe731..5b978488bb9390382ae681213630692ff80a5343 100644 (file)
@@ -149,8 +149,6 @@ public class PSRenderer extends AbstractRenderer {
 
     private int psLevel = 3;
 
-    protected IDReferences idReferences;
-
     protected java.util.Map options;
 
 
@@ -720,16 +718,7 @@ public class PSRenderer extends AbstractRenderer {
         FontState fs = area.getFontState();
         String fontWeight = fs.getFontWeight();
         StringBuffer sb = new StringBuffer();
-        String s;
-        if (area.getPageNumberID()
-                != null) {    // this text is a page number, so resolve it
-            s = idReferences.getPageNumber(area.getPageNumberID());
-            if (s == null) {
-                s = "";
-            }
-        } else {
-            s = area.getText();
-        }
+        String s = area.getText();
         int l = s.length();
 
         for (int i = 0; i < l; i++) {
index e95589c5a3e2e688f8be844511006d186846c3f8..f713d3c7a5c03020635f0d349f173ba3ecd29ed8 100644 (file)
@@ -106,8 +106,6 @@ public class SVGRenderer extends AbstractRenderer {
     protected Map fontStyles = new java.util.HashMap();
     protected Color saveColor = null;
 
-    protected IDReferences idReferences = null;
-
     /**
      * The current (internal) font name
      */
@@ -503,16 +501,7 @@ public class SVGRenderer extends AbstractRenderer {
         int rx = this.currentXPosition;
         int bl = this.currentYPosition;
 
-        String s;    // = area.getText();
-        if (area.getPageNumberID()
-                != null) {    // this text is a page number, so resolve it
-            s = idReferences.getPageNumber(area.getPageNumberID());
-            if (s == null) {
-                s = "";
-            }
-        } else {
-            s = area.getText();
-        }
+        String s = area.getText();
 
         if (saveColor != null) {
             if (saveColor.getRed() != red || saveColor.getGreen() != green
index 1288a43c1a450ee7a50ea8d8de9a73d7d058b040..c0b613d0c2f44c4bb95fee2321eded3a8fddc35f 100755 (executable)
@@ -1608,15 +1608,7 @@ public class TXTRenderer extends PrintRenderer {
         int rx = this.currentXPosition;
         int bl = this.currentYPosition;
 
-        String s;
-        if (area.getPageNumberID() != null) {
-            // this text is a page number, so resolve it
-            s = idReferences.getPageNumber(area.getPageNumberID());
-            if (s == null)
-                s = "";
-        } else {
-            s = area.getText();
-        }
+        String s = area.getText();
 
         if (debug)
             System.out.println("TXTRenderer.renderInlineArea: rx=" + rx
index 72696af5e143d300dce213a5b6e605b4b63b49f9..55298f001020ec680f7555ab8a82ef24978ec7c2 100644 (file)
@@ -59,6 +59,7 @@ import org.apache.fop.layout.*;
 import org.apache.fop.layout.inline.*;
 import org.apache.fop.fo.properties.LeaderPattern;
 import org.apache.fop.apps.FOPException;
+import org.apache.fop.datatypes.IDReferences;
 
 // Avalon
 import org.apache.avalon.framework.logger.Logger;
@@ -104,6 +105,8 @@ public class XMLRenderer implements Renderer {
     protected java.util.Map options;
     private boolean consistentOutput = false;
 
+    protected IDReferences idReferences;
+
     public XMLRenderer() {}
 
     /**
@@ -129,6 +132,7 @@ public class XMLRenderer implements Renderer {
 
     public void render(Page page, OutputStream outputStream)
     throws IOException {
+        idReferences = page.getIDReferences();
         this.renderPage(page);
     }
 
@@ -577,4 +581,8 @@ public class XMLRenderer implements Renderer {
         this.writer.flush();
         log.debug("written out XML");
     }
+
+    public IDReferences getIDReferences() {
+        return idReferences;
+    }
 }