You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by ad...@apache.org on 2008/06/23 00:10:56 UTC

svn commit: r670422 - in /xmlgraphics/fop/trunk/src/java/org/apache/fop: fo/ fo/flow/ layoutmgr/ layoutmgr/inline/ render/rtf/

Author: adelmelle
Date: Sun Jun 22 15:10:55 2008
New Revision: 670422

URL: http://svn.apache.org/viewvc?rev=670422&view=rev
Log:
Switch FOText to use a java.nio.CharBuffer, and implement the CharSequence interface.
TextLayoutManager no longer duplicates the char array, operates on the FOText (charAt(i))
Additionally: endOfNode() for FOText and Character deferred until after white-space handling.

Modified:
    xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FOText.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FOTreeBuilder.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FObjMixed.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/render/rtf/RTFHandler.java

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FOText.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FOText.java?rev=670422&r1=670421&r2=670422&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FOText.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FOText.java Sun Jun 22 15:10:55 2008
@@ -20,6 +20,7 @@
 package org.apache.fop.fo;
 
 import java.awt.Color;
+import java.nio.CharBuffer;
 import java.util.NoSuchElementException;
 
 import org.xml.sax.Locator;
@@ -33,48 +34,17 @@
 import org.apache.fop.fo.properties.KeepProperty;
 import org.apache.fop.fo.properties.Property;
 import org.apache.fop.fo.properties.SpaceProperty;
+import org.apache.fop.util.CharUtilities;
 
 /**
  * A text node (PCDATA) in the formatting object tree.
- *
- * 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.
  */
-public class FOText extends FONode {
+public class FOText extends FONode implements CharSequence {
 
-    /**
-     * the character array containing the text
-     */
-    public char[] ca;
-
-    /**
-     * The starting valid index of the ca array 
-     * to be processed.
-     *
-     * This value is originally equal to 0, but becomes 
-     * incremented during leading whitespace removal by the flow.Block class,  
-     * via the TextCharIterator.remove() method below.
-     */
-    public int startIndex = 0;
+    /** the <code>CharBuffer</code> containing the text */
+    private CharBuffer charBuffer;
 
-    /**
-     * The ending valid index of the ca array 
-     * to be processed.
-     *
-     * This value is originally equal to ca.length, but becomes 
-     * decremented during between-word whitespace removal by the 
-     * XMLWhiteSpaceHandler via the TextCharIterator.remove() 
-     * method below.
-     */
-    public int endIndex = 0;
-
-    /** properties relevant for PCDATA */
-    /* TODO: these are basically always the same as the parent FObj or FObjMixed
-     *      so maybe those can be removed, and the accessors could  
-     *      dispatch the call to the parent?
-     */
+    /** properties relevant for #PCDATA */
     private CommonFont commonFont;
     private CommonHyphenation commonHyphenation;
     private Color color;
@@ -105,10 +75,10 @@
      * which FOText nodes are descendants of the same block.
      */
     private Block ancestorBlock = null;
-    
+
     /** Holds the text decoration values. May be null */
     private CommonTextDecoration textDecoration;
-    
+
     private static final int IS_WORD_CHAR_FALSE = 0;
     private static final int IS_WORD_CHAR_TRUE = 1;
     private static final int IS_WORD_CHAR_MAYBE = 2;
@@ -126,33 +96,58 @@
     protected void addCharacters(char[] data, int start, int length,
             PropertyList list, Locator locator) throws FOPException {
 
-        int calength = 0;
-        char[] nca;
-        if (ca != null) {
-            calength = ca.length;
-            nca = new char[calength + length];
-            System.arraycopy(ca, 0, nca, 0, calength);
+        if (this.charBuffer == null) {
+            // buffer not yet initialized, do so now
+            this.charBuffer = CharBuffer.allocate(length);
         } else {
-            nca = new char[length];
+            // allocate a larger buffer, and transfer contents
+            int newLength = this.charBuffer.limit() + length;
+            CharBuffer newBuffer = CharBuffer.allocate(newLength);
+            this.charBuffer.rewind();
+            newBuffer.put(this.charBuffer);
+            this.charBuffer = newBuffer;
         }
-        System.arraycopy(data, start, nca, calength, length);
-        endIndex = nca.length;
-        this.ca = nca;
-     }
+        // append characters
+        this.charBuffer.put(data, start, length);
+
+    }
 
     /**
-     * {@inheritDoc} 
+     * Return the array of characters for this instance.
+     *
+     * @return  a char array containing the text
      */
+    public char[] getCharArray() {
+
+        if (this.charBuffer == null) {
+            return null;
+        }
+
+        if (this.charBuffer.hasArray()) {
+            return this.charBuffer.array();
+        }
+
+        // only if the buffer implementation has
+        // no accessible backing array, return a new one
+        char[] ca = new char[this.charBuffer.limit()];
+        this.charBuffer.rewind();
+        this.charBuffer.get(ca);
+        return ca;
+
+    }
+
+    /** {@inheritDoc} */
     public FONode clone(FONode parent, boolean removeChildren)
             throws FOPException {
         FOText ft = (FOText) super.clone(parent, removeChildren);
         if (removeChildren) {
-            //not really removing, but just make sure the char array 
-            //pointed to is really a different one, and reset any
-            //possible whitespace-handling effects
-            if (ca != null) {
-                ft.ca = new char[ca.length];
-                System.arraycopy(ca, 0, ft.ca, 0, ca.length);
+            // not really removing, just make sure the char buffer
+            // pointed to is really a different one
+            if (this.charBuffer != null) {
+                ft.charBuffer = CharBuffer.allocate(this.charBuffer.limit());
+                this.charBuffer.rewind();
+                ft.charBuffer.put(this.charBuffer);
+                ft.charBuffer.rewind();
             }
         }
         ft.prevFOTextThisBlock = null;
@@ -161,29 +156,33 @@
         return ft;
     }
 
-    /**
-     * {@inheritDoc}
-     */
+    /** {@inheritDoc} */
     public void bind(PropertyList pList) throws FOPException {
-        commonFont = pList.getFontProps();
-        commonHyphenation = pList.getHyphenationProps();
-        color = pList.get(Constants.PR_COLOR).getColor(getUserAgent());
-        keepTogether = pList.get(Constants.PR_KEEP_TOGETHER).getKeep();
-        lineHeight = pList.get(Constants.PR_LINE_HEIGHT).getSpace();
-        letterSpacing = pList.get(Constants.PR_LETTER_SPACING);
-        whiteSpaceCollapse = pList.get(Constants.PR_WHITE_SPACE_COLLAPSE).getEnum();
-        whiteSpaceTreatment = pList.get(Constants.PR_WHITE_SPACE_TREATMENT).getEnum();
-        textTransform = pList.get(Constants.PR_TEXT_TRANSFORM).getEnum();
-        wordSpacing = pList.get(Constants.PR_WORD_SPACING);
-        wrapOption = pList.get(Constants.PR_WRAP_OPTION).getEnum();
-        textDecoration = pList.getTextDecorationProps();
-        baselineShift = pList.get(Constants.PR_BASELINE_SHIFT).getLength();
+        this.commonFont = pList.getFontProps();
+        this.commonHyphenation = pList.getHyphenationProps();
+        this.color = pList.get(Constants.PR_COLOR).getColor(getUserAgent());
+        this.keepTogether = pList.get(Constants.PR_KEEP_TOGETHER).getKeep();
+        this.lineHeight = pList.get(Constants.PR_LINE_HEIGHT).getSpace();
+        this.letterSpacing = pList.get(Constants.PR_LETTER_SPACING);
+        this.whiteSpaceCollapse = pList.get(Constants.PR_WHITE_SPACE_COLLAPSE).getEnum();
+        this.whiteSpaceTreatment = pList.get(Constants.PR_WHITE_SPACE_TREATMENT).getEnum();
+        this.textTransform = pList.get(Constants.PR_TEXT_TRANSFORM).getEnum();
+        this.wordSpacing = pList.get(Constants.PR_WORD_SPACING);
+        this.wrapOption = pList.get(Constants.PR_WRAP_OPTION).getEnum();
+        this.textDecoration = pList.getTextDecorationProps();
+        this.baselineShift = pList.get(Constants.PR_BASELINE_SHIFT).getLength();
     }
 
     /** {@inheritDoc} */
     protected void endOfNode() throws FOPException {
+        super.endOfNode();
+        getFOEventHandler().characters(
+                this.getCharArray(), 0, this.charBuffer.limit());
+    }
+
+    /** {@inheritDoc} */
+    public void finalizeNode() {
         textTransform();
-        getFOEventHandler().characters(ca, startIndex, endIndex - startIndex);
     }
 
     /**
@@ -197,16 +196,20 @@
      */
     public boolean willCreateArea() {
         if (whiteSpaceCollapse == Constants.EN_FALSE
-                && endIndex - startIndex > 0) {
+                && this.charBuffer.limit() > 0) {
             return true;
         }
 
-        for (int i = startIndex; i < endIndex; i++) {
-            char ch = ca[i];
-            if (!((ch == ' ')
-                    || (ch == '\n')
-                    || (ch == '\r')
-                    || (ch == '\t'))) { // whitespace
+        char ch;
+        this.charBuffer.rewind();
+        while (this.charBuffer.hasRemaining()) {
+            ch = this.charBuffer.get();
+            if (!((ch == CharUtilities.SPACE)
+                    || (ch == CharUtilities.LINEFEED_CHAR)
+                    || (ch == CharUtilities.CARRIAGE_RETURN)
+                    || (ch == CharUtilities.TAB))) {
+                // not whitespace
+                this.charBuffer.rewind();
                 return true;
             }
         }
@@ -221,7 +224,7 @@
     }
 
      /**
-     * This method is run as part of the ancestor Block's flushText(), to 
+     * This method is run as part of the ancestor Block's flushText(), to
      * create xref pointers to the previous FOText objects within the same Block
      * @param  ancestorBlock the ancestor fo:block
      */
@@ -229,7 +232,7 @@
         this.ancestorBlock = ancestorBlock;
         // if the last FOText is a sibling, point to it, and have it point here
         if (ancestorBlock.lastFOTextProcessed != null) {
-            if (ancestorBlock.lastFOTextProcessed.ancestorBlock 
+            if (ancestorBlock.lastFOTextProcessed.ancestorBlock
                     == this.ancestorBlock) {
                 prevFOTextThisBlock = ancestorBlock.lastFOTextProcessed;
                 prevFOTextThisBlock.nextFOTextThisBlock = this;
@@ -240,16 +243,47 @@
     }
 
     /**
-     * This method is run as part of the Constructor, to handle the
-     * text-transform property.
+     * This method is run as part of endOfNode(), to handle the
+     * text-transform property for accumulated FOText
      */
     private void textTransform() {
-        if (getBuilderContext().inMarker() 
+        if (getBuilderContext().inMarker()
                 || textTransform == Constants.EN_NONE) {
             return;
         }
-        for (int i = 0; i < endIndex; i++) {
-            ca[i] = charTransform(i);
+
+        this.charBuffer.rewind();
+        CharBuffer tmp = this.charBuffer.slice();
+        char c;
+        int lim = this.charBuffer.limit();
+        int pos = -1;
+        while (++pos < lim) {
+            c = this.charBuffer.get();
+            switch (textTransform) {
+                case Constants.EN_UPPERCASE:
+                    tmp.put(Character.toUpperCase(c));
+                    break;
+                case Constants.EN_LOWERCASE:
+                    tmp.put(Character.toLowerCase(c));
+                    break;
+                case Constants.EN_CAPITALIZE:
+                    if (isStartOfWord(pos)) {
+                        /*
+                         Use toTitleCase here. Apparently, some languages use
+                         a different character to represent a letter when using
+                         initial caps than when all of the letters in the word
+                         are capitalized. We will try to let Java handle this.
+                        */
+                        tmp.put(Character.toTitleCase(c));
+                    } else {
+                        tmp.put(c);
+                    }
+                    break;
+                default:
+                     //should never happen as the property subsystem catches that case
+                    assert false;
+                    //nop
+            }
         }
     }
 
@@ -260,7 +294,7 @@
      * well, such as word-spacing. The definition of "word" is somewhat ambiguous
      * and appears to be definable by the user agent.
      *
-     * @param i index into ca[]
+     * @param i index into charBuffer
      *
      * @return True if the character at this location is the start of a new
      * word.
@@ -268,33 +302,33 @@
     private boolean isStartOfWord(int i) {
         char prevChar = getRelativeCharInBlock(i, -1);
         /* All we are really concerned about here is of what type prevChar
-           is. If inputChar is not part of a word, then the Java
-           conversions will (we hope) simply return inputChar.
-        */
-        switch (isWordChar(prevChar)) {
-        case IS_WORD_CHAR_TRUE:
-            return false;
-        case IS_WORD_CHAR_FALSE:
-            return true;
-        /* "MAYBE" implies that additional context is needed. An example is a
-         * single-quote, either straight or closing, which might be interpreted
-         * as a possessive or a contraction, or might be a closing quote.
+         * is. If inputChar is not part of a word, then the Java
+         * conversions will (we hope) simply return inputChar.
          */
-        case IS_WORD_CHAR_MAYBE:
-            char prevPrevChar = getRelativeCharInBlock(i, -2);
-            switch (isWordChar(prevPrevChar)) {
+        switch (isWordChar(prevChar)) {
             case IS_WORD_CHAR_TRUE:
                 return false;
             case IS_WORD_CHAR_FALSE:
                 return true;
+            /* "MAYBE" implies that additional context is needed. An example is a
+             * single-quote, either straight or closing, which might be interpreted
+             * as a possessive or a contraction, or might be a closing quote.
+             */
             case IS_WORD_CHAR_MAYBE:
-                return true;
+                char prevPrevChar = getRelativeCharInBlock(i, -2);
+                switch (isWordChar(prevPrevChar)) {
+                case IS_WORD_CHAR_TRUE:
+                    return false;
+                case IS_WORD_CHAR_FALSE:
+                    return true;
+                case IS_WORD_CHAR_MAYBE:
+                    return true;
+                default:
+                    return false;
+            }
             default:
                 return false;
         }
-        default:
-            return false;
-        }
     }
 
     /**
@@ -303,7 +337,7 @@
      * block as one unit, allowing text in adjoining FOText objects to be
      * returned if the parameters are outside of the current object.
      *
-     * @param i index into ca[]
+     * @param i index into the CharBuffer
      * @param offset signed integer with relative position within the
      *   block of the character to return. To return the character immediately
      *   preceding i, pass -1. To return the character immediately after i,
@@ -312,30 +346,34 @@
      * the offset points to an area outside of the block.
      */
     private char getRelativeCharInBlock(int i, int offset) {
+
+        int charIndex = i + offset;
         // The easy case is where the desired character is in the same FOText
-        if (((i + offset) >= 0) && ((i + offset) <= this.endIndex)) {
-            return ca[i + offset];
+        if (charIndex >= 0 && charIndex < this.length()) {
+            return this.charAt(i + offset);
         }
+
         // For now, we can't look at following FOText nodes
         if (offset > 0) {
-             return '\u0000';
-         }
+             return CharUtilities.NULL_CHAR;
+        }
+
         // Remaining case has the text in some previous FOText node
         boolean foundChar = false;
-        char charToReturn = '\u0000';
+        char charToReturn = CharUtilities.NULL_CHAR;
         FOText nodeToTest = this;
         int remainingOffset = offset + i;
         while (!foundChar) {
             if (nodeToTest.prevFOTextThisBlock == null) {
-                foundChar = true;
                 break;
             }
             nodeToTest = nodeToTest.prevFOTextThisBlock;
-            if ((nodeToTest.endIndex + remainingOffset) >= 0) {
-                charToReturn = nodeToTest.ca[nodeToTest.endIndex + remainingOffset];
+            int diff = nodeToTest.length() + remainingOffset - 1;
+            if (diff >= 0) {
+                charToReturn = nodeToTest.charAt(diff);
                 foundChar = true;
             } else {
-                remainingOffset = remainingOffset + nodeToTest.endIndex;
+                remainingOffset += diff;
             }
         }
         return charToReturn;
@@ -366,39 +404,6 @@
     }
 
     /**
-     * Transforms one character in ca[] using the text-transform property.
-     *
-     * @param i the index into ca[]
-     * @return char with transformed value
-     */
-    private char charTransform(int i) {
-        switch (textTransform) {
-        /* put NONE first, as this is probably the common case */
-        case Constants.EN_NONE:
-            return ca[i];
-        case Constants.EN_UPPERCASE:
-            return Character.toUpperCase(ca[i]);
-        case Constants.EN_LOWERCASE:
-            return Character.toLowerCase(ca[i]);
-        case Constants.EN_CAPITALIZE:
-            if (isStartOfWord(i)) {
-                /*
-                 Use toTitleCase here. Apparently, some languages use
-                 a different character to represent a letter when using
-                 initial caps than when all of the letters in the word
-                 are capitalized. We will try to let Java handle this.
-                */
-                return Character.toTitleCase(ca[i]);
-            } else {
-                return ca[i];
-            }
-        default:
-            assert false; //should never happen as the property subsystem catches that case
-            return ca[i];
-        }
-    }
-
-    /**
      * Determines whether the input char should be considered part of a
      * "word". This is used primarily to determine whether the character
      * immediately following starts a new word, but may have other uses.
@@ -483,57 +488,64 @@
     }
 
     private class TextCharIterator extends CharIterator {
-        private int curIndex = 0;
 
-        /* Current space removal process:  just increment the startIndex
-           to "remove" leading spaces from ca, until an unremoved character
-           is found.  Then perform arraycopy's to remove extra spaces
-           between words.  nextCharCalled is used to determine if an 
-           unremoved character has already been found--if its value > 2
-           than it means that has occurred (it is reset to zero each time we 
-           remove a space via incrementing the startIndex.)  */
-        private int nextCharCalled = 0;
-        
+        int currentPosition = 0;
+
+        boolean canRemove = false;
+        boolean canReplace = false;
+
+        /** {@inheritDoc} */
         public boolean hasNext() {
-           if (curIndex == 0) {
-//             log.debug("->" + new String(ca) + "<-");
-          }
-           return (curIndex < endIndex);
+           return (this.currentPosition < charBuffer.limit());
         }
 
+        /** {@inheritDoc} */
         public char nextChar() {
-            if (curIndex < endIndex) {
-                nextCharCalled++;
-                // Just a char class? Don't actually care about the value!
-                return ca[curIndex++];
+
+            if (this.currentPosition < charBuffer.limit()) {
+                this.canRemove = true;
+                this.canReplace = true;
+                return charBuffer.get(currentPosition++);
             } else {
                 throw new NoSuchElementException();
             }
+
         }
 
+        /** {@inheritDoc} */
         public void remove() {
-            if (curIndex < endIndex && nextCharCalled < 2) {
-                startIndex++;
-                nextCharCalled = 0;
-//              log.debug("removeA: " + new String(ca, startIndex, endIndex - startIndex));
-            } else if (curIndex < endIndex) {
-                // copy from curIndex to end to curIndex-1
-                System.arraycopy(ca, curIndex, ca, curIndex - 1, 
-                    endIndex - curIndex);
-                endIndex--;
-                curIndex--;
-//              log.debug("removeB: " + new String(ca, startIndex, endIndex - startIndex));
-            } else if (curIndex == endIndex) {
-//              log.debug("removeC: " + new String(ca, startIndex, endIndex - startIndex));
-                endIndex--;
-                curIndex--;
+
+            if (this.canRemove) {
+                charBuffer.position(currentPosition);
+                // Slice the buffer at the current position
+                CharBuffer tmp = charBuffer.slice();
+                // Reset position to before current character
+                charBuffer.position(--currentPosition);
+                if (tmp.hasRemaining()) {
+                    // Transfer any remaining characters
+                    charBuffer.mark();
+                    charBuffer.put(tmp);
+                    charBuffer.reset();
+                }
+                // Decrease limit
+                charBuffer.limit(charBuffer.limit() - 1);
+                // Make sure following calls fail, unless nextChar() was called
+                this.canRemove = false;
+            } else {
+                throw new IllegalStateException();
             }
+
         }
 
+        /** {@inheritDoc} */
         public void replaceChar(char c) {
-            if (curIndex > 0 && curIndex <= endIndex) {
-                ca[curIndex - 1] = c;
+
+            if (this.canReplace) {
+                charBuffer.put(currentPosition - 1, c);
+            } else {
+                throw new IllegalStateException();
             }
+
         }
 
     }
@@ -559,7 +571,7 @@
         return color;
     }
 
-    /** 
+    /**
      * @return the "keep-together" property.
      */
     public KeepProperty getKeepTogether() {
@@ -570,40 +582,40 @@
      * @return the "letter-spacing" property.
      */
     public Property getLetterSpacing() {
-        return letterSpacing; 
+        return letterSpacing;
     }
-    
+
     /**
      * @return the "line-height" property.
      */
     public SpaceProperty getLineHeight() {
         return lineHeight;
     }
-    
+
     /**
      * @return the "white-space-treatment" property
      */
     public int getWhitespaceTreatment() {
         return whiteSpaceTreatment;
     }
-    
+
     /**
      * @return the "word-spacing" property.
      */
     public Property getWordSpacing() {
-        return wordSpacing; 
+        return wordSpacing;
     }
-    
+
     /**
      * @return the "wrap-option" property.
      */
     public int getWrapOption() {
-        return wrapOption; 
+        return wrapOption;
     }
-    
+
     /** @return the "text-decoration" property. */
     public CommonTextDecoration getTextDecoration() {
-        return textDecoration; 
+        return textDecoration;
     }
 
     /** @return the baseline-shift property */
@@ -613,14 +625,12 @@
 
     /** {@inheritDoc} */
     public String toString() {
-        StringBuffer sb = new StringBuffer(super.toString());
-        sb.append(" (").append(ca).append(")");
-        return sb.toString();
+        return (this.charBuffer == null) ? "" : this.charBuffer.toString();
     }
- 
+
     /** {@inheritDoc} */
     public String getLocalName() {
-        return null;
+        return "#PCDATA";
     }
 
     /** {@inheritDoc} */
@@ -630,10 +640,34 @@
 
     /** {@inheritDoc} */
     protected String gatherContextInfo() {
-        if (getLocator() != null) {
+        if (this.locator != null) {
             return super.gatherContextInfo();
         } else {
-            return new String(ca).trim();
+            return this.toString();
         }
-    }    
-}
\ No newline at end of file
+    }
+
+    /** {@inheritDoc} */
+    public char charAt(int position) {
+        return this.charBuffer.get(position);
+    }
+
+    /** {@inheritDoc} */
+    public CharSequence subSequence(int start, int end) {
+        return this.charBuffer.subSequence(start, end);
+    }
+
+    /** {@inheritDoc} */
+    public int length() {
+        return this.charBuffer.limit();
+    }
+
+    /**
+     * Resets the backing <code>java.nio.CharBuffer</code>
+     */
+    public void resetBuffer() {
+        if (this.charBuffer != null) {
+            this.charBuffer.rewind();
+        }
+    }
+}

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FOTreeBuilder.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FOTreeBuilder.java?rev=670422&r1=670421&r2=670422&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FOTreeBuilder.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FOTreeBuilder.java Sun Jun 22 15:10:55 2008
@@ -144,7 +144,7 @@
             log.debug("Building formatting object tree");
         }
         foEventHandler.startDocument();
-        this.mainFOHandler = new MainFOHandler(); 
+        this.mainFOHandler = new MainFOHandler();
         this.mainFOHandler.startDocument();
         this.delegate = this.mainFOHandler;
     }
@@ -224,7 +224,7 @@
         } else {
             //No formatting results available for output formats no 
             //involving the layout engine.
-            return null;   
+            return null;
         }
     }
     
@@ -316,7 +316,13 @@
             if (propertyList != null && !builderContext.inMarker()) {
                 currentPropertyList = propertyList;
             }
-            currentFObj.startOfNode();
+
+            // fo:characters can potentially be removed during
+            // white-space handling.
+            // Do not notify the FOEventHandler.
+            if (currentFObj.getNameId() != Constants.FO_CHARACTER) {
+                currentFObj.startOfNode();
+            }
         }
 
         /** {@inheritDoc} */
@@ -333,7 +339,12 @@
                         + ") vs. " + localName + " (" + uri + ")");
             }
             
-            currentFObj.endOfNode();
+            // fo:characters can potentially be removed during
+            // white-space handling.
+            // Do not notify the FOEventHandler.
+            if (currentFObj.getNameId() != Constants.FO_CHARACTER) {
+                currentFObj.endOfNode();
+            }
             
             if (currentPropertyList != null
                     && currentPropertyList.getFObj() == currentFObj

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FObjMixed.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FObjMixed.java?rev=670422&r1=670421&r2=670422&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FObjMixed.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FObjMixed.java Sun Jun 22 15:10:55 2008
@@ -28,27 +28,27 @@
  * (= those that can contain both child {@link FONode}s and <code>#PCDATA</code>).
  */
 public abstract class FObjMixed extends FObj {
-    
+
     /** Represents accumulated, pending FO text. See {@link #flushText()}. */
-    protected FOText ft = null;
-    
+    private FOText ft = null;
+
     /** Used for white-space handling; start CharIterator at node ... */
     protected FONode currentTextNode;
-    
+
     /** Used in creating pointers between subsequent {@link FOText} nodes
-     *  in the same {@link org.apache.fop.fo.flow.Block} 
+     *  in the same {@link org.apache.fop.fo.flow.Block}
      *  (for handling text-transform) */
     protected FOText lastFOTextProcessed = null;
-    
+
     /**
      * Base constructor
-     * 
+     *
      * @param parent FONode that is the parent of this object
      */
     protected FObjMixed(FONode parent) {
         super(parent);
     }
-    
+
     /** {@inheritDoc} */
     protected void addCharacters(char[] data, int start, int length,
                                  PropertyList pList,
@@ -65,20 +65,21 @@
 
     /** {@inheritDoc} */
     protected void endOfNode() throws FOPException {
-        flushText();
-        if (!inMarker()
-                || getNameId() == FO_MARKER) {
-            handleWhiteSpaceFor(this, null);
-        }
+
         super.endOfNode();
+        if (!inMarker() || getNameId() == FO_MARKER) {
+            // send character[s]() events to the FOEventHandler
+            sendCharacters();
+        }
+        
     }
 
     /**
-     * Handles white-space for the node that is passed in, 
+     * Handles white-space for the node that is passed in,
      * starting at its current text-node
-     * (used by {@link org.apache.fop.fo.flow.RetrieveMarker} 
+     * (used by {@link org.apache.fop.fo.flow.RetrieveMarker}
      *  to trigger 'end-of-node' white-space handling)
-     *  
+     *
      * @param fobj  the node for which to handle white-space
      * @param nextChild the next child to be added
      */
@@ -86,86 +87,97 @@
         fobj.getBuilderContext().getXMLWhiteSpaceHandler()
             .handleWhiteSpace(fobj, fobj.currentTextNode, nextChild);
     }
-    
+
     /**
-     * Adds accumulated text as one FOText instance, unless
-     * the one instance's <code>char</code> array contains more than 
-     * <code>Short.MAX_VALUE</code> characters. In the latter case the 
-     * instance is split up into more manageable chunks.
-     * 
+     * Creates block-pointers between subsequent FOText nodes
+     * in the same Block. (used for handling text-transform)
+     *
+     * TODO: !! Revisit: does not take into account fo:characters !!
+     *
      * @throws FOPException if there is a problem during processing
      */
-    protected void flushText() throws FOPException {
+    private void flushText() throws FOPException {
         if (ft != null) {
             FOText lft = ft;
             /* make sure nested calls to itself have no effect */
             ft = null;
-            FOText tmpText;
-            int indexStart = 0;
-            int indexEnd = (lft.ca.length > Short.MAX_VALUE 
-                            ? Short.MAX_VALUE : lft.ca.length) - 1;
-            int charCount = 0;
-            short tmpSize;
-            while (charCount < lft.ca.length) {
-                tmpSize = (short) (indexEnd - indexStart + 1);
-                charCount += tmpSize;
-                tmpText = (FOText) lft.clone(this, false);
-                tmpText.ca = new char[tmpSize];
-                tmpText.startIndex = 0;
-                tmpText.endIndex = tmpSize;
-                System.arraycopy(lft.ca, indexStart, 
-                                tmpText.ca, 0, indexEnd - indexStart + 1);
-                if (getNameId() == FO_BLOCK) {
-                    tmpText.createBlockPointers((org.apache.fop.fo.flow.Block) this);
-                    this.lastFOTextProcessed = tmpText;
-                } else if (getNameId() != FO_MARKER
-                        && getNameId() != FO_TITLE
-                        && getNameId() != FO_BOOKMARK_TITLE) {
-                    FONode fo = parent;
-                    int foNameId = fo.getNameId();
-                    while (foNameId != FO_BLOCK
-                            && foNameId != FO_MARKER
-                            && foNameId != FO_TITLE
-                            && foNameId != FO_BOOKMARK_TITLE
-                            && foNameId != FO_PAGE_SEQUENCE) {
-                        fo = fo.getParent();
-                        foNameId = fo.getNameId();
-                    }
-                    if (foNameId == FO_BLOCK) {
-                        tmpText.createBlockPointers((org.apache.fop.fo.flow.Block) fo);
-                        ((FObjMixed) fo).lastFOTextProcessed = tmpText;
-                    } else if (foNameId == FO_PAGE_SEQUENCE
-                                && tmpText.willCreateArea()) {
-                        log.error("Could not create block pointers."
-                                + " FOText w/o Block ancestor.");
-                    }
+            if (getNameId() == FO_BLOCK) {
+                lft.createBlockPointers((org.apache.fop.fo.flow.Block) this);
+                this.lastFOTextProcessed = lft;
+            } else if (getNameId() != FO_MARKER
+                    && getNameId() != FO_TITLE
+                    && getNameId() != FO_BOOKMARK_TITLE) {
+                FONode fo = parent;
+                int foNameId = fo.getNameId();
+                while (foNameId != FO_BLOCK
+                        && foNameId != FO_MARKER
+                        && foNameId != FO_TITLE
+                        && foNameId != FO_BOOKMARK_TITLE
+                        && foNameId != FO_PAGE_SEQUENCE) {
+                    fo = fo.getParent();
+                    foNameId = fo.getNameId();
+                }
+                if (foNameId == FO_BLOCK) {
+                    lft.createBlockPointers((org.apache.fop.fo.flow.Block) fo);
+                    ((FObjMixed) fo).lastFOTextProcessed = lft;
+                } else if (foNameId == FO_PAGE_SEQUENCE
+                            && lft.willCreateArea()) {
+                    log.error("Could not create block pointers."
+                            + " FOText w/o Block ancestor.");
+                }
+            }
+            this.addChildNode(lft);
+        }
+    }
+
+    private void sendCharacters() throws FOPException {
+
+        if (this.currentTextNode != null) {
+            FONodeIterator nodeIter
+                    = this.getChildNodes(this.currentTextNode);
+            FONode node;
+            while (nodeIter.hasNext()) {
+                node = nodeIter.nextNode();
+                assert (node instanceof FOText
+                        || node.getNameId() == FO_CHARACTER);
+                if (node.getNameId() == FO_CHARACTER) {
+                    node.startOfNode();
                 }
-                tmpText.endOfNode();
-                addChildNode(tmpText);
-                indexStart = indexEnd + 1;
-                indexEnd = (((lft.ca.length - charCount) < Short.MAX_VALUE)
-                    ? lft.ca.length : charCount + Short.MAX_VALUE) - 1;
+                node.endOfNode();
             }
         }
+        this.currentTextNode = null;
     }
 
     /** {@inheritDoc} */
     protected void addChildNode(FONode child) throws FOPException {
+
         flushText();
         if (!inMarker()) {
             if (child instanceof FOText || child.getNameId() == FO_CHARACTER) {
-                if (currentTextNode == null) {
-                    currentTextNode = child;
+                if (this.currentTextNode == null) {
+                    this.currentTextNode = child;
                 }
             } else {
                 // handle white-space for all text up to here
                 handleWhiteSpaceFor(this, child);
-                currentTextNode = null;
+                // send character[s]() events to the FOEventHandler
+                sendCharacters();
             }
         }
         super.addChildNode(child);
     }
-    
+
+    /** {@inheritDoc} */
+    public void finalizeNode() throws FOPException {
+
+        flushText();
+        if (!inMarker() || getNameId() == FO_MARKER) {
+            handleWhiteSpaceFor(this, null);
+        }
+
+    }
+
     /**
      * Returns a {@link CharIterator} over this FO's character content
      * 

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java?rev=670422&r1=670421&r2=670422&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java Sun Jun 22 15:10:55 2008
@@ -119,12 +119,10 @@
                 ft.bind(parentPropertyList);
                 addChildTo(newChild, (FObj) newParent);
             }
-            
+
+            // trigger end-of-node white-space handling
+            // and finalization for table-FOs
             newChild.finalizeNode();
-            // trigger 'end-of-node' white-space handling
-            if (newChild instanceof FObjMixed) {
-                handleWhiteSpaceFor((FObjMixed) newChild, null);
-            }
         }
     }
 

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java?rev=670422&r1=670421&r2=670422&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java Sun Jun 22 15:10:55 2008
@@ -41,8 +41,8 @@
 import org.apache.fop.fo.flow.ExternalGraphic;
 import org.apache.fop.fo.flow.Footnote;
 import org.apache.fop.fo.flow.Inline;
-import org.apache.fop.fo.flow.InlineLevel;
 import org.apache.fop.fo.flow.InlineContainer;
+import org.apache.fop.fo.flow.InlineLevel;
 import org.apache.fop.fo.flow.InstreamForeignObject;
 import org.apache.fop.fo.flow.Leader;
 import org.apache.fop.fo.flow.ListBlock;
@@ -224,7 +224,7 @@
     public static class FOTextLayoutManagerMaker extends Maker {
         public void make(FONode node, List lms) {
             FOText foText = (FOText) node;
-            if (foText.endIndex - foText.startIndex > 0) {
+            if (foText.length() > 0) {
                 lms.add(new TextLayoutManager(foText));
             }
         }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java?rev=670422&r1=670421&r2=670422&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java Sun Jun 22 15:10:55 2008
@@ -61,20 +61,20 @@
      * Number of word-spaces?
      */
     private class AreaInfo {
-        private final short startIndex;
-        private final short breakIndex;
-        private final short wordSpaceCount;
-        private short letterSpaceCount;
+        private final int startIndex;
+        private final int breakIndex;
+        private final int wordSpaceCount;
+        private int letterSpaceCount;
         private final MinOptMax areaIPD;
         private final boolean isHyphenated;
         private final boolean isSpace;
         private boolean breakOppAfter;
         private final Font font;
 
-        AreaInfo(final short startIndex,
-                        final short breakIndex,
-                        final short wordSpaceCount,
-                        final short letterSpaceCount,
+        AreaInfo(final int startIndex,
+                        final int breakIndex,
+                        final int wordSpaceCount,
+                        final int letterSpaceCount,
                         final MinOptMax areaIPD,
                         final boolean isHyphenated,
                         final boolean isSpace,
@@ -132,7 +132,7 @@
     private static final MinOptMax ZERO_MINOPTMAX = new MinOptMax(0);
 
     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
@@ -143,7 +143,7 @@
     /** Font used for the space between words. */
     private Font spaceFont = null;
     /** Start index of next TextArea */
-    private short nextStart = 0;
+    private int nextStart = 0;
     /** size of a space character (U+0020) glyph in current font */
     private int spaceCharIPD;
     private MinOptMax wordSpaceIPD;
@@ -155,8 +155,8 @@
 
     private boolean hasChanged = false;
     private int returnedIndex = 0;
-    private short thisStart = 0;
-    private short tempStart = 0;
+    private int thisStart = 0;
+    private int tempStart = 0;
     private List changeList = null;
 
     private AlignmentContext alignmentContext = null;
@@ -177,10 +177,7 @@
         super();
         this.foText = node;
 
-        this.textArray = new char[node.endIndex - node.startIndex];
-        System.arraycopy(node.ca, node.startIndex, this.textArray, 0,
-            node.endIndex - node.startIndex);
-        this.letterAdjustArray = new MinOptMax[this.textArray.length + 1];
+        this.letterAdjustArray = new MinOptMax[node.length() + 1];
 
         this.vecAreaInfo = new java.util.ArrayList();
     }
@@ -205,6 +202,8 @@
     /** {@inheritDoc} */
     public void initialize() {
 
+        this.foText.resetBuffer();
+        
         this.spaceFont = FontSelector.selectFontForCharacterInText(' ', this.foText, this);
 
         // With CID fonts, space isn't neccesary currentFontState.width(32)
@@ -296,7 +295,7 @@
             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
+        // TODO: These two statements (if, for) were 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.
@@ -441,7 +440,7 @@
                 // areaInfo stores information about spaces
                 // add the spaces - except zero-width spaces - to the TextArea
                 for (int j = areaInfo.startIndex; j < areaInfo.breakIndex; j++) {
-                    final char spaceChar = this.textArray[j];
+                    final char spaceChar = this.foText.charAt(j);
                     if (!CharUtilities.isZeroWidthSpace(spaceChar)) {
                         textArea.addSpace(spaceChar, 0,
                                 CharUtilities.isAdjustableSpace(spaceChar));
@@ -469,8 +468,15 @@
                     for (int j = wordStartIndex; j <= i; j++) {
                         final AreaInfo ai = (AreaInfo) this.vecAreaInfo.get(j);
                         int lsCount = ai.letterSpaceCount;
-                        wordChars.append(this.textArray, ai.startIndex,
-                                ai.breakIndex - ai.startIndex);
+                        /* TODO: in Java 5, StringBuffer has an append() variant
+                         * for CharSequence, so the below iteration can be replaced
+                         * by:
+                         *  wordChars.append(this.foText, ai.startIndex,
+                         *       ai.breakIndex - ai.startIndex);
+                         */
+                        for (int ci = ai.startIndex; ci < ai.breakIndex; ci++) {
+                            wordChars.append(this.foText.charAt(ci));
+                        }
                         for (int k = 0; k < ai.breakIndex - ai.startIndex; k++) {
                             final MinOptMax adj = this.letterAdjustArray[ai.startIndex + k];
                             if (letter > 0) {
@@ -522,7 +528,7 @@
             || CharUtilities.isNonBreakableSpace(ch)
             || CharUtilities.isFixedWidthSpace(ch);
     }
-    
+
     /** {@inheritDoc} */
     public List getNextKnuthElements(final LayoutContext context, final int alignment) {
         this.lineStartBAP = context.getLineStartBorderAndPaddingWidth();
@@ -540,8 +546,8 @@
         boolean inWord = false;
         boolean inWhitespace = false;
         char ch = 0;
-        while (this.nextStart < this.textArray.length) {
-            ch = this.textArray[this.nextStart];
+        while (this.nextStart < this.foText.length()) {
+            ch = this.foText.charAt(this.nextStart);
             boolean breakOpportunity = false;
             final byte breakAction = this.keepTogether ? LineBreakStatus.PROHIBITED_BREAK
                     : lbs.nextChar(ch);
@@ -560,10 +566,10 @@
                     TextLayoutManager.LOG.error("Unexpected breakAction: " + breakAction);
             }
             if (inWord) {
-                if (breakOpportunity 
+                if (breakOpportunity
                         || TextLayoutManager.isSpace(ch)
                         || CharUtilities.isExplicitBreak(ch)) {
-                    // this.textArray[lastIndex] == CharUtilities.SOFT_HYPHEN
+                    // this.foText.charAt(lastIndex) == CharUtilities.SOFT_HYPHEN
                     prevAi = this.processWord(alignment, sequence, prevAi, ch,
                             breakOpportunity, true);
                 }
@@ -588,24 +594,24 @@
                     || ch == CharUtilities.NBSPACE) {
                 // preserved space or non-breaking space:
                 // create the AreaInfo object
-                ai = new AreaInfo(this.nextStart, (short) (this.nextStart + 1),
-                        (short) 1, (short) 0, this.wordSpaceIPD, false, true,
+                ai = new AreaInfo(this.nextStart, this.nextStart + 1,
+                        1, 0, this.wordSpaceIPD, false, true,
                         breakOpportunity, this.spaceFont);
-                this.thisStart = (short) (this.nextStart + 1);
+                this.thisStart = this.nextStart + 1;
             } else if (CharUtilities.isFixedWidthSpace(ch) || CharUtilities.isZeroWidthSpace(ch)) {
                 // create the AreaInfo object
                 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,
+                ai = new AreaInfo(this.nextStart, this.nextStart + 1,
+                        0, 0, ipd, false, true,
                         breakOpportunity, font);
-                this.thisStart = (short) (this.nextStart + 1);
+                this.thisStart = this.nextStart + 1;
             } else if (CharUtilities.isExplicitBreak(ch)) {
                 //mandatory break-character: only advance index
-                this.thisStart = (short) (this.nextStart + 1);
+                this.thisStart = this.nextStart + 1;
             }
-            
+
             inWord = !TextLayoutManager.isSpace(ch)
                     && !CharUtilities.isExplicitBreak(ch);
             inWhitespace = ch == CharUtilities.SPACE
@@ -619,17 +625,17 @@
         } else if (inWhitespace) {
             this.processWhitespace(alignment, sequence, true);
         } else if (ai != null) {
-            ai = this.processLeftoverAi(alignment, sequence, ai, ch,
+            this.processLeftoverAi(alignment, sequence, ai, ch,
                     ch == CharUtilities.ZERO_WIDTH_SPACE);
         } else if (CharUtilities.isExplicitBreak(ch)) {
-            sequence = this.processLinebreak(returnList, sequence);
+            this.processLinebreak(returnList, sequence);
         }
 
         if (((List) ListUtil.getLast(returnList)).isEmpty()) {
             //Remove an empty sequence because of a trailing newline
             ListUtil.removeLast(returnList);
         }
-        
+
         this.setFinished(true);
         if (returnList.isEmpty()) {
             return null;
@@ -663,24 +669,20 @@
 
     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,
+        AreaInfo ai = new AreaInfo(this.thisStart, this.nextStart,
+                this.nextStart - this.thisStart, 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;
+        return ai;
     }
 
     private AreaInfo processWord(final int alignment, final KnuthSequence sequence,
@@ -688,21 +690,21 @@
             final boolean checkEndsWithHyphen) {
         AreaInfo ai;
         //Word boundary found, process widths and kerning
-        short lastIndex = this.nextStart;
+        int lastIndex = this.nextStart;
         while (lastIndex > 0
-                && this.textArray[lastIndex - 1] == CharUtilities.SOFT_HYPHEN) {
+                && this.foText.charAt(lastIndex - 1) == CharUtilities.SOFT_HYPHEN) {
             lastIndex--;
         }
         final boolean endsWithHyphen = checkEndsWithHyphen
-                && this.textArray[lastIndex] == CharUtilities.SOFT_HYPHEN;
+                && this.foText.charAt(lastIndex) == CharUtilities.SOFT_HYPHEN;
         final Font font = FontSelector
-                .selectFontForCharactersInText(this.textArray,
+                .selectFontForCharactersInText(this.foText,
                         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];
+            final char c = this.foText.charAt(i);
 
             //character width
             final int charWidth = font.getCharWidth(c);
@@ -712,10 +714,10 @@
             if (kerning) {
                 int kern = 0;
                 if (i > this.thisStart) {
-                    final char previous = this.textArray[i - 1];
+                    final char previous = this.foText.charAt(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];
+                    final char previous = this.foText.charAt(prevAi.breakIndex - 1);
                     kern = font.getKernValue(previous, c) * font.getFontSize() / 1000;
                 }
                 if (kern != 0) {
@@ -730,7 +732,7 @@
                 && lastIndex > 0
                 && endsWithHyphen) {
             final int kern = font.getKernValue(
-                    this.textArray[lastIndex - 1], ch)
+                    this.foText.charAt(lastIndex - 1), ch)
                     * font.getFontSize() / 1000;
             if (kern != 0) {
                 this.addToLetterAdjust(lastIndex, kern);
@@ -746,8 +748,8 @@
         wordIPD.add(MinOptMax.multiply(this.letterSpaceIPD, iLetterSpaces));
 
         // create the AreaInfo object
-        ai = new AreaInfo(this.thisStart, lastIndex, (short) 0,
-                (short) iLetterSpaces, wordIPD,
+        ai = new AreaInfo(this.thisStart, lastIndex, 0,
+                iLetterSpaces, wordIPD,
                 endsWithHyphen,
                 false, breakOpportunity, font);
         prevAi = ai;
@@ -776,7 +778,7 @@
             final AreaInfo ai = (AreaInfo) this.vecAreaInfo.get(idx);
             ai.letterSpaceCount++;
             ai.areaIPD.add(this.letterSpaceIPD);
-            if (TextLayoutManager.BREAK_CHARS.indexOf(this.textArray[this.tempStart - 1]) >= 0) {
+            if (TextLayoutManager.BREAK_CHARS.indexOf(this.foText.charAt(this.tempStart - 1)) >= 0) {
                 // the last character could be used as a line break
                 // append new elements to oldList
                 oldListIterator = oldList.listIterator(oldList.size());
@@ -867,7 +869,7 @@
 
             //log.info("Word: " + new String(textArray, startIndex, stopIndex - startIndex));
             for (int i = startIndex; i < stopIndex; i++) {
-                final char c = this.textArray[i];
+                final char c = this.foText.charAt(i);
                 newIPD.add(new MinOptMax(font.getCharWidth(c)));
                 //if (i > startIndex) {
                 if (i < stopIndex) {
@@ -899,8 +901,8 @@
                     this.changeList = new LinkedList();
                 }
                 this.changeList.add(new PendingChange(new AreaInfo(
-                        (short) startIndex, (short) stopIndex, (short) 0,
-                        (short) (isWordEnd ? stopIndex - startIndex - 1
+                        startIndex, stopIndex, 0,
+                        (isWordEnd ? stopIndex - startIndex - 1
                                 : stopIndex - startIndex), newIPD,
                         hyphenFollows, false, false, font),
                         ((LeafPosition) pos).getLeafPos()));
@@ -973,7 +975,9 @@
         final int leafValue = ((LeafPosition) pos).getLeafPos();
         if (leafValue != -1) {
             final AreaInfo ai = (AreaInfo) this.vecAreaInfo.get(leafValue);
-            sbChars.append(this.textArray, ai.startIndex, ai.breakIndex - ai.startIndex);
+            for (int i = ai.startIndex; i < ai.breakIndex; ++i) {
+                sbChars.append(this.foText.charAt(i));
+            }
         }
     }
 
@@ -999,7 +1003,7 @@
                         mainPosition, true));
             }
         } else {
-            if (this.textArray[ai.startIndex] != CharUtilities.SPACE
+            if (this.foText.charAt(ai.startIndex) != CharUtilities.SPACE
                     || this.foText.getWhitespaceTreatment() == Constants.EN_PRESERVE) {
                 // a breaking space that needs to be preserved
                 this.addElementsForBreakingSpace(baseList, alignment, ai,
@@ -1153,7 +1157,7 @@
         // or it ends with a character that can be used as a line break
         if (ai.isHyphenated) {
             MinOptMax widthIfNoBreakOccurs = null;
-            if (ai.breakIndex < this.textArray.length) {
+            if (ai.breakIndex < this.foText.length()) {
                 //Add in kerning in no-break condition
                 widthIfNoBreakOccurs = this.letterAdjustArray[ai.breakIndex];
             }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/rtf/RTFHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/rtf/RTFHandler.java?rev=670422&r1=670421&r2=670422&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/rtf/RTFHandler.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/rtf/RTFHandler.java Sun Jun 22 15:10:55 2008
@@ -1568,7 +1568,7 @@
         } else if (foNode instanceof FOText) {
             if (bStart) {
                 FOText text = (FOText) foNode;
-                text(text, text.ca, text.startIndex, text.endIndex);
+                text(text, text.getCharArray(), 0, text.length());
             }
         } else if (foNode instanceof Character) {
             if (bStart) {



---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org


Re: svn commit: r670422 - in /xmlgraphics/fop/trunk/src/java/org/apache/fop: fo/ fo/flow/ layoutmgr/ layoutmgr/inline/ render/rtf/

Posted by Max Berger <ma...@berger.name>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Andreas,

Alhtough the testcases pass, this broke MathML. I get the (attached)
error message on this fo file (which worked fine before updating).
Please note that I get the same error message no matter if the JEuclid
extension is installed or not.

Max

P.S. maybe we should add this as a test file for fop? Of course, there
is no expected output without the extension, but it should not throw an
exception, just a warning.

- --- choose.fo
<root xmlns="http://www.w3.org/1999/XSL/Format">
  <layout-master-set>
    <simple-page-master master-name="master">
      <region-body/>
    </simple-page-master>
  </layout-master-set>
  <page-sequence master-reference="master">
    <flow flow-name="xsl-region-body">
      <block>
	<instream-foreign-object>
	  <math xmlns="http://www.w3.org/1998/Math/MathML">
	    <mfrac linethickness="0">
	      <mi>a</mi>
	      <mi>b</mi>
	    </mfrac>
	  </math>
	</instream-foreign-object>
      </block>
    </flow>
  </page-sequence>
</root>
- --- stacktrace

 fop -fo choose.fo -pdf choose.pdf
23.06.2008 15:42:13 org.apache.fop.cli.Main startFOP
SCHWERWIEGEND: Exception
java.lang.StringIndexOutOfBoundsException: String index out of range: -356
	at org.apache.fop.cli.InputHandler.transformTo(InputHandler.java:217)
	at org.apache.fop.cli.InputHandler.renderTo(InputHandler.java:125)
	at org.apache.fop.cli.Main.startFOP(Main.java:169)
	at org.apache.fop.cli.Main.main(Main.java:200)

- ---------

java.lang.StringIndexOutOfBoundsException: String index out of range: -356
	at java.lang.String.<init>(String.java:208)
	at org.apache.fop.fo.XMLObj.addCharacters(XMLObj.java:217)
	at
org.apache.fop.fo.FOTreeBuilder$MainFOHandler.characters(FOTreeBuilder.java:374)
	at org.apache.fop.fo.FOTreeBuilder.characters(FOTreeBuilder.java:130)
	at
org.apache.xalan.transformer.TransformerIdentityImpl.characters(TransformerIdentityImpl.java:1125)
	at org.apache.xerces.parsers.AbstractSAXParser.characters(Unknown Source)
	at org.apache.xerces.xinclude.XIncludeHandler.characters(Unknown Source)
	at
org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanContent(Unknown
Source)
	at
org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown
Source)
	at
org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown
Source)
	at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
	at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
	at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
	at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
	at
org.apache.xalan.transformer.TransformerIdentityImpl.transform(TransformerIdentityImpl.java:484)
	at org.apache.fop.cli.InputHandler.transformTo(InputHandler.java:214)
	at org.apache.fop.cli.InputHandler.renderTo(InputHandler.java:125)
	at org.apache.fop.cli.Main.startFOP(Main.java:169)
	at org.apache.fop.cli.Main.main(Main.java:200)



adelmelle@apache.org schrieb:
> Author: adelmelle
> Date: Sun Jun 22 15:10:55 2008
> New Revision: 670422
> 
> URL: http://svn.apache.org/viewvc?rev=670422&view=rev
> Log:
> Switch FOText to use a java.nio.CharBuffer, and implement the CharSequence interface.
> TextLayoutManager no longer duplicates the char array, operates on the FOText (charAt(i))
> Additionally: endOfNode() for FOText and Character deferred until after white-space handling.
> 
> Modified:
>     xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FOText.java
>     xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FOTreeBuilder.java
>     xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FObjMixed.java
>     xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java
>     xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
>     xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
>     xmlgraphics/fop/trunk/src/java/org/apache/fop/render/rtf/RTFHandler.java
> 
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFIX6rB+Gr+4pk71JwRAgRhAJ4yiAe0sRIc1ez6cVC73PdKaWlRtACdGtyU
cIwGzxNrUfCxhnOXEsaFM6Q=
=vvMe
-----END PGP SIGNATURE-----