You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-commits@xmlgraphics.apache.org by ca...@apache.org on 2006/03/08 01:04:03 UTC

svn commit: r384062 [5/6] - in /xmlgraphics/batik/branches/anim: ./ lib/ resources/META-INF/services/ resources/org/apache/batik/apps/rasterizer/resources/ resources/org/apache/batik/apps/svgbrowser/resources/ resources/org/apache/batik/dom/svg/resourc...

Modified: xmlgraphics/batik/branches/anim/sources/org/apache/batik/ext/awt/image/spi/MagicNumberRegistryEntry.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/anim/sources/org/apache/batik/ext/awt/image/spi/MagicNumberRegistryEntry.java?rev=384062&r1=384061&r2=384062&view=diff
==============================================================================
--- xmlgraphics/batik/branches/anim/sources/org/apache/batik/ext/awt/image/spi/MagicNumberRegistryEntry.java (original)
+++ xmlgraphics/batik/branches/anim/sources/org/apache/batik/ext/awt/image/spi/MagicNumberRegistryEntry.java Tue Mar  7 16:03:46 2006
@@ -1,6 +1,6 @@
 /*
 
-   Copyright 2001,2003  The Apache Software Foundation 
+   Copyright 2001,2003,2006  The Apache Software Foundation 
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -114,63 +114,136 @@
      * Constructor, simplifies construction of entry when only
      * one extension and one magic number is required.
      * @param name        Format Name
+     * @param priority    the priority of the RegistryEntry
      * @param ext         Standard extension
+     * @param mimeType    the supported MIME type
      * @param offset      Offset of magic number
      * @param magicNumber byte array to match.
      */
     public MagicNumberRegistryEntry(String name,
+                                    float priority,
                                     String ext,
                                     String mimeType,
                                     int offset, byte[]magicNumber) {
-        super(name, PRIORITY, ext, mimeType);
+        super(name, priority, ext, mimeType);
         magicNumbers    = new MagicNumber[1];
         magicNumbers[0] = new MagicNumber(offset, magicNumber);
     }
     
     /**
      * Constructor, simplifies construction of entry when only
+     * one extension and one magic number is required.
+     * @param name        Format Name
+     * @param ext         Standard extension
+     * @param mimeType    the supported MIME type
+     * @param offset      Offset of magic number
+     * @param magicNumber byte array to match.
+     */
+    public MagicNumberRegistryEntry(String name,
+                                    String ext,
+                                    String mimeType,
+                                    int offset, byte[] magicNumber) {
+        this(name, PRIORITY, ext, mimeType, offset, magicNumber);
+    }
+    
+    /**
+     * Constructor, simplifies construction of entry when only
      * one extension is required.
      * @param name         Format Name
+     * @param priority     the priority of the RegistryEntry
      * @param ext          Standard extension
+     * @param mimeType     the supported MIME type
      * @param magicNumbers Array of magic numbers any of which can match.
      */
     public MagicNumberRegistryEntry(String name,
+                                    float priority,
                                     String ext,
                                     String mimeType,
-                                    MagicNumber [] magicNumbers) {
-        super(name, PRIORITY, ext, mimeType);
+                                    MagicNumber[] magicNumbers) {
+        super(name, priority, ext, mimeType);
         this.magicNumbers = magicNumbers;
     }
 
     /**
      * Constructor, simplifies construction of entry when only
+     * one extension is required.
+     * @param name         Format Name
+     * @param ext          Standard extension
+     * @param mimeType     the supported MIME type
+     * @param magicNumbers Array of magic numbers any of which can match.
+     */
+    public MagicNumberRegistryEntry(String name,
+                                    String ext,
+                                    String mimeType,
+                                    MagicNumber[] magicNumbers) {
+        this(name, PRIORITY, ext, mimeType, magicNumbers);
+    }
+
+    /**
+     * Constructor, simplifies construction of entry when only
      * one magic number is required.
      * @param name Format Name
+     * @param priority the priority of the RegistryEntry
      * @param exts Standard set of extensions
+     * @param mimeTypes array of supported MIME types
      * @param offset Offset of magic number
      * @param magicNumber byte array to match.
      */
     public MagicNumberRegistryEntry(String    name,
+                                    float     priority,
                                     String [] exts,
                                     String [] mimeTypes,
                                     int offset, byte[]magicNumber) {
-        super(name, PRIORITY, exts, mimeTypes);
+        super(name, priority, exts, mimeTypes);
         magicNumbers    = new MagicNumber[1];
         magicNumbers[0] = new MagicNumber(offset, magicNumber);
     }
     
     /**
+     * Constructor, simplifies construction of entry when only
+     * one magic number is required.
+     * @param name Format Name
+     * @param exts Standard set of extensions
+     * @param mimeTypes array of supported MIME types
+     * @param offset Offset of magic number
+     * @param magicNumber byte array to match.
+     */
+    public MagicNumberRegistryEntry(String    name,
+                                    String [] exts,
+                                    String [] mimeTypes,
+                                    int offset, byte[] magicNumbers) {
+        this(name, PRIORITY, exts, mimeTypes, offset, magicNumbers);
+    }
+    
+    /**
      * Constructor
      * @param name Format Name
+     * @param priority the priority of the RegistryEntry
      * @param exts Standard set of extensions
+     * @param mimeTypes array of supported MIME types
      * @param magicNumbers array of magic numbers any of which can match.
      */
     public MagicNumberRegistryEntry(String    name,
+                                    float     priority,
                                     String [] exts,
                                     String [] mimeTypes,
                                     MagicNumber [] magicNumbers) {
-        super(name, PRIORITY, exts, mimeTypes);
+        super(name, priority, exts, mimeTypes);
         this.magicNumbers = magicNumbers;
+    }
+    
+    /**
+     * Constructor
+     * @param name Format Name
+     * @param exts Standard set of extensions
+     * @param mimeTypes array of supported MIME types
+     * @param magicNumbers array of magic numbers any of which can match.
+     */
+    public MagicNumberRegistryEntry(String    name,
+                                    String [] exts,
+                                    String [] mimeTypes,
+                                    MagicNumber [] magicNumbers) {
+        this(name, PRIORITY, exts, mimeTypes, magicNumbers);
     }
     
     /**

Modified: xmlgraphics/batik/branches/anim/sources/org/apache/batik/extension/StylableExtensionElement.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/anim/sources/org/apache/batik/extension/StylableExtensionElement.java?rev=384062&r1=384061&r2=384062&view=diff
==============================================================================
--- xmlgraphics/batik/branches/anim/sources/org/apache/batik/extension/StylableExtensionElement.java (original)
+++ xmlgraphics/batik/branches/anim/sources/org/apache/batik/extension/StylableExtensionElement.java Tue Mar  7 16:03:46 2006
@@ -1,6 +1,6 @@
 /*
 
-   Copyright 1999-2003  The Apache Software Foundation 
+   Copyright 1999-2003,2006  The Apache Software Foundation 
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
 import java.net.URL;
 
 import org.apache.batik.css.engine.CSSStylableElement;
+import org.apache.batik.css.engine.StyleDeclarationProvider;
 import org.apache.batik.css.engine.StyleMap;
 import org.apache.batik.dom.AbstractDocument;
 import org.w3c.dom.Node;
@@ -132,6 +133,15 @@
             return n == null;
         }
         return false;
+    }
+
+    /**
+     * Returns the object that gives access to the underlying
+     * {@link org.apache.batik.css.engine.StyleDeclaration} for the override
+     * style of this element.
+     */
+    public StyleDeclarationProvider getOverrideStyleDeclarationProvider() {
+        return null;
     }
 
     // SVGStylable //////////////////////////////////////////////////

Modified: xmlgraphics/batik/branches/anim/sources/org/apache/batik/extension/svg/BatikFlowTextElementBridge.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/anim/sources/org/apache/batik/extension/svg/BatikFlowTextElementBridge.java?rev=384062&r1=384061&r2=384062&view=diff
==============================================================================
--- xmlgraphics/batik/branches/anim/sources/org/apache/batik/extension/svg/BatikFlowTextElementBridge.java (original)
+++ xmlgraphics/batik/branches/anim/sources/org/apache/batik/extension/svg/BatikFlowTextElementBridge.java Tue Mar  7 16:03:46 2006
@@ -137,6 +137,8 @@
                                                      Element element) {
         List rgns = getRegions(ctx, element);
         AttributedString ret = getFlowDiv(ctx, element);
+        if (ret == null) return ret;
+
         ret.addAttribute(FLOW_REGIONS, rgns, 0, 1);
         return ret;
     }

Modified: xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/FillShapePainter.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/FillShapePainter.java?rev=384062&r1=384061&r2=384062&view=diff
==============================================================================
--- xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/FillShapePainter.java (original)
+++ xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/FillShapePainter.java Tue Mar  7 16:03:46 2006
@@ -65,6 +65,13 @@
     }
 
     /**
+     * Gets the paint used to draw the outline of the shape.
+     */
+    public Paint getPaint() {
+        return paint;
+    }
+
+    /**
      * Paints the specified shape using the specified Graphics2D.
      *
      * @param g2d the Graphics2D to use

Modified: xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/StrokeShapePainter.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/StrokeShapePainter.java?rev=384062&r1=384061&r2=384062&view=diff
==============================================================================
--- xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/StrokeShapePainter.java (original)
+++ xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/StrokeShapePainter.java Tue Mar  7 16:03:46 2006
@@ -77,12 +77,26 @@
     }
 
     /**
+     * Gets the stroke used to draw the outline of the shape.
+     */
+    public Stroke getStroke() {
+        return stroke;
+    }
+
+    /**
      * Sets the paint used to fill a shape.
      *
      * @param newPaint the paint object used to draw the shape
      */
     public void setPaint(Paint newPaint) {
         this.paint = newPaint;
+    }
+
+    /**
+     * Gets the paint used to draw the outline of the shape.
+     */
+    public Paint getPaint() {
+        return paint;
     }
 
     /**

Modified: xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/FlowGlyphLayout.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/FlowGlyphLayout.java?rev=384062&r1=384061&r2=384062&view=diff
==============================================================================
--- xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/FlowGlyphLayout.java (original)
+++ xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/FlowGlyphLayout.java Tue Mar  7 16:03:46 2006
@@ -43,8 +43,10 @@
  */
 public class FlowGlyphLayout extends GlyphLayout {
 
-    public static final AttributedCharacterIterator.Attribute WORD_LIMIT
-        = TextLineBreaks.WORD_LIMIT;
+    public static final char SOFT_HYPHEN       = 0x00AD;
+    public static final char ZERO_WIDTH_SPACE  = 0x200B;
+    public static final char ZERO_WIDTH_JOINER = 0x200D;
+    public static final char SPACE             = ' ';
 
 
     public FlowGlyphLayout(AttributedCharacterIterator aci,
@@ -55,396 +57,4 @@
     }
 
 
-    public static boolean textWrapTextChunk
-        (AttributedCharacterIterator [] acis,
-         List chunkLayouts,
-         List flowRects,
-         FontRenderContext frc) {
-
-        int numChunks = acis.length;
-        // System.out.println("Len: " + acis.length + " Size: " + 
-        //                     chunkLayouts.size());
-
-        // Make a list of the GlyphVectors so we can construct a
-        // multiGlyphVector that makes them all look like one big
-        // glyphVector
-        GVTGlyphVector [] gvs            = new GVTGlyphVector[acis.length];
-        WordInfo       [][] wordInfos    = new WordInfo[acis.length][];
-        Iterator clIter = chunkLayouts.iterator();
-
-        float prevBotMargin = 0;
-        int numWords = 0;
-        BlockInfo [] blockInfos = new BlockInfo[acis.length];
-        float      [] topSkip   = new float[acis.length];
-        for (int chunk=0; clIter.hasNext(); chunk++) {
-            // System.err.print("Chunk: " + chunk + " Str: '");
-            AttributedCharacterIterator aci = acis[chunk];
-            List gvl = new LinkedList();
-            List layouts = (List)clIter.next();
-            Iterator iter = layouts.iterator();
-            while (iter.hasNext()) {
-                GlyphLayout gl = (GlyphLayout)iter.next();
-                gvl.add(gl.getGlyphVector());
-            }
-            GVTGlyphVector gv = new MultiGlyphVector(gvl);
-            gvs[chunk] = gv;
-            wordInfos[chunk] = doWordAnalysis(gv, aci, numWords, frc);
-            aci.first();
-            BlockInfo bi = (BlockInfo)aci.getAttribute(FLOW_PARAGRAPH);
-            bi.initLineInfo(frc);
-            blockInfos[chunk] = bi;
-            if (prevBotMargin > bi.getTopMargin())
-                topSkip[chunk] = prevBotMargin;
-            else
-                topSkip[chunk] = bi.getTopMargin();
-            prevBotMargin = bi.getBottomMargin();
-            numWords += wordInfos[chunk].length;
-        }
-
-        Iterator frIter = flowRects.iterator();
-        RegionInfo currentRegion = null;
-        int currWord = 0;
-        int chunk = 0;
-        List lineInfos = new LinkedList();
-        while(frIter.hasNext()) {
-            currentRegion = (RegionInfo) frIter.next();
-            FlowRegions fr = new FlowRegions(currentRegion.getShape());
-
-            while (chunk < wordInfos.length) {
-                WordInfo [] chunkInfo = wordInfos[chunk];
-                BlockInfo bi = blockInfos[chunk];
-                WordInfo  wi = chunkInfo[currWord];
-                Object    flowLine = wi.getFlowLine();
-                double    lh = Math.max(wi.getLineHeight(),bi.getLineHeight());
-                LineInfo li = new LineInfo(fr, bi, true);
-                double newY = li.getCurrentY()+topSkip[chunk];
-                topSkip[chunk] = 0;
-                if (li.gotoY(newY)) break;
-
-                while (!li.addWord(wi)) {
-                    // step down 1/10 of a line height and try again.
-                    newY = li.getCurrentY()+lh*.1;
-                    if (li.gotoY(newY)) break;
-                }
-                if (fr.done()) break;
-
-                currWord++;
-                for (;currWord < chunkInfo.length;currWord++) {
-                    wi = chunkInfo[currWord];
-                    if ((wi.getFlowLine() == flowLine) && (li.addWord(wi))) 
-                        continue;
-
-                    // Word didn't fit or we hit end of flowLine elem,
-                    // go to a new line.
-                    li.layout();
-                    lineInfos.add(li);
-                    li = null;
-
-                    flowLine = wi.getFlowLine();
-                    lh  = Math.max(wi.getLineHeight(),bi.getLineHeight());
-                    if (!fr.newLine(lh)) break; // region is done
-
-                    li = new LineInfo(fr, bi, false);
-                    while (!li.addWord(wi)) {
-                        newY =li.getCurrentY()+lh*.1;
-                        if (li.gotoY(newY)) break; 
-                    }
-                    if (fr.done()) break;
-                }
-                if (li != null) {
-                    li.setParaEnd(true);
-                    li.layout();
-                }
-
-                if (fr.done()) break;
-
-                chunk++;
-                currWord = 0;
-
-                if (bi.isFlowRegionBreak()) 
-                    break;
-
-                if (!fr.newLine(lh)) // Region is done.
-                    break;
-            }
-            if (chunk == wordInfos.length)
-                break;
-        }
-
-        boolean overflow = (chunk < wordInfos.length);
-
-        while (chunk < wordInfos.length) {
-            WordInfo [] chunkInfo = wordInfos[chunk];
-            while (currWord < chunkInfo.length) {
-                WordInfo wi = chunkInfo[currWord];
-                int numGG = wi.getNumGlyphGroups();
-                for (int gg=0; gg<numGG; gg++) {
-                    GlyphGroupInfo ggi = wi.getGlyphGroup(gg);
-                    GVTGlyphVector gv = ggi.getGlyphVector();
-                    int end = ggi.getEnd();
-                    for (int g=ggi.getStart(); g <= end; g++) {
-                        gv.setGlyphVisible(g, false);
-                    }
-                }
-                currWord++;
-            }
-            chunk++;
-            currWord = 0;
-        }
-
-        return overflow;
-    }
-
-    static int [] allocWordMap(int [] wordMap, int sz) {
-        if (wordMap != null) {
-            if (sz <= wordMap.length)
-                return wordMap;
-            if (sz < wordMap.length*2)
-                sz = wordMap.length*2;
-        }
-
-        int [] ret = new int[sz];
-        int ext=0;
-        if (wordMap != null)
-            ext = wordMap.length;
-        if (sz < ext) ext = sz;
-        int i=0;
-        for (; i<ext; i++) {
-            ret[i] = wordMap[i];
-        }
-        for (; i<sz; i++) {
-            ret[i] = -1;
-        }
-        return ret;
-    }
-
-    /**
-     * This returns an array of glyphs numbers for each glyph
-     * group in each word: ret[word][glyphGroup][glyphNum].
-     */
-    static WordInfo[] doWordAnalysis(GVTGlyphVector gv, 
-                                    AttributedCharacterIterator aci,
-                                    int numWords,
-                                    FontRenderContext frc) {
-        int numGlyphs = gv.getNumGlyphs();
-        int [] glyphWords = new int[numGlyphs];
-        int [] wordMap = allocWordMap(null, 10);
-        int maxWord = 0;
-        int aciIdx = aci.getBeginIndex();
-        // First we go through the glyphs seeing if any two ajacent
-        // words need to be collapsed because of a ligature.  This
-        // would be an odd case.  If it happens we consider the
-        // two words to be one.
-        for (int i=0; i<numGlyphs; i++) {
-            int cnt = gv.getCharacterCount(i,i);
-            aci.setIndex(aciIdx);
-            Integer integer = (Integer)aci.getAttribute(WORD_LIMIT);
-            int minWord = integer.intValue()-numWords;
-            if (minWord > maxWord) {
-                maxWord = minWord;
-                wordMap = allocWordMap(wordMap, maxWord+1);
-            }
-            aciIdx++;
-            for (int c=1; c<cnt; c++) {
-                aci.setIndex(aciIdx);
-                integer = (Integer)aci.getAttribute(WORD_LIMIT);
-                int cWord = integer.intValue()-numWords;
-                if (cWord > maxWord) {
-                    maxWord = cWord;
-                    wordMap = allocWordMap(wordMap, maxWord+1);
-                }
-                // We always want to use the min word as the main
-                // index for the new composite word.
-                if (cWord < minWord) {
-                    wordMap[minWord] = cWord;
-                    minWord = cWord;
-                } else if (cWord > minWord) {
-                    wordMap[cWord] = minWord;
-                }
-                aciIdx++;
-            }
-            glyphWords[i] = minWord;
-        }
-        int words=0;
-        WordInfo [] cWordMap = new WordInfo[maxWord+1];
-        for (int i=0; i<=maxWord; i++) {
-            int nw = wordMap[i];
-            if (nw == -1) {
-                // new word so give it a number.
-                cWordMap[i] = new WordInfo(words++);
-            } else {
-                int word = nw;
-                nw = wordMap[i];
-                while (nw != -1) {
-                    word = nw;
-                    nw = wordMap[word];
-                }
-                wordMap[i] = word; // help the next guy out
-                cWordMap[i] = cWordMap[word];
-            }
-        }
-        wordMap = null;
-        WordInfo [] wordInfos = new WordInfo[words];
-        for (int i=0; i<=maxWord; i++) {
-            WordInfo wi = cWordMap[i];
-            wordInfos[wi.getIndex()] = cWordMap[i];
-        }
-        
-        aciIdx = aci.getBeginIndex();
-        int aciEnd = aci.getEndIndex();
-        char ch = aci.setIndex(aciIdx);
-        
-        int aciWordStart = aciIdx;
-        GVTFont gvtFont = (GVTFont)aci.getAttribute(GVT_FONT);
-        float lineHeight = 1.f;
-        Float lineHeightFloat = (Float)aci.getAttribute(LINE_HEIGHT);
-        if (lineHeightFloat != null) 
-            lineHeight = lineHeightFloat.floatValue();
-        int runLimit = aci.getRunLimit(szAtts);
-        WordInfo prevWI = null;
-        float   [] lastAdvAdj = new float  [numGlyphs];
-        float   [] advAdj     = new float  [numGlyphs];
-        boolean [] hideLast   = new boolean[numGlyphs];
-        boolean [] hide       = new boolean[numGlyphs];
-        boolean [] space      = new boolean[numGlyphs];
-        float   [] glyphPos = gv.getGlyphPositions(0, numGlyphs+1, null);
-        for (int i=0; i<numGlyphs; i++) {
-            char pch = ch;
-            ch = aci.setIndex(aciIdx);
-            Integer integer = (Integer)aci.getAttribute(WORD_LIMIT);
-            WordInfo theWI = cWordMap[integer.intValue()-numWords];
-            if (theWI.getFlowLine() == null)
-                theWI.setFlowLine(aci.getAttribute(FLOW_LINE_BREAK));
-
-            if (prevWI == null) {
-                prevWI = theWI;
-            } else if (prevWI != theWI) {
-                GVTLineMetrics lm = gvtFont.getLineMetrics
-                    (aci, aciWordStart, aciIdx, frc);
-                prevWI.addLineMetrics(gvtFont, lm);
-                prevWI.addLineHeight(lineHeight);
-                aciWordStart = aciIdx;
-                prevWI = theWI;
-            } 
-
-            int chCnt = gv.getCharacterCount(i,i);
-            if (chCnt == 1) {
-                char nch;
-                float kern;
-                switch(ch) {
-                case SOFT_HYPHEN:
-                    hideLast[i] = true;
-                    nch = aci.next(); aci.previous();
-                    kern = gvtFont.getHKern(pch, nch);
-                    advAdj[i] = -(glyphPos[2*i+2]-glyphPos[2*i]+kern);
-                    break;
-                case ZERO_WIDTH_JOINER:
-                    hide[i] = true;
-                    break;
-                case ZERO_WIDTH_SPACE:
-                    hide[i] = true;
-                    break;
-                case SPACE:
-                    space[i] = true;
-                    nch = aci.next(); aci.previous();
-                    kern = gvtFont.getHKern(pch, nch);
-                    lastAdvAdj[i] = -(glyphPos[2*i+2]-glyphPos[2*i]+kern);
-                default:
-                }
-            }
-
-            aciIdx += chCnt;
-            if ((aciIdx > runLimit) && (aciIdx < aciEnd)) {
-                // Possible font size/style change so record current
-                // line metrics and start fresh.
-                GVTLineMetrics lm = gvtFont.getLineMetrics
-                    (aci,aciWordStart, runLimit, frc);
-                prevWI.addLineMetrics(gvtFont, lm);
-                prevWI.addLineHeight(lineHeight);
-                prevWI = null;
-                aciWordStart = aciIdx;
-                aci.setIndex(aciIdx);
-                gvtFont = (GVTFont)aci.getAttribute(GVT_FONT);
-                Float f = (Float)aci.getAttribute(LINE_HEIGHT);
-                lineHeight = f.floatValue();
-                runLimit = aci.getRunLimit(szAtts);
-            }
-        }
-        GVTLineMetrics lm = gvtFont.getLineMetrics
-            (aci,aciWordStart, runLimit, frc);
-        prevWI.addLineMetrics(gvtFont, lm);
-        prevWI.addLineHeight(lineHeight);
-
-        int [] wordGlyphCounts = new int[words];
-        // Build a mapping from words to glyphs.
-        for (int i=0; i<numGlyphs; i++) {
-            int word = glyphWords[i];
-            int cWord = cWordMap[word].getIndex();
-            glyphWords[i] = cWord;
-            wordGlyphCounts[cWord]++;
-        }
-
-        cWordMap = null;
-        int [][]wordGlyphs = new int [words][];
-        int []wordGlyphGroupsCounts = new int [words];
-        for (int i=0; i<numGlyphs; i++) {
-            int cWord = glyphWords[i];
-            // System.err.println("CW: " + cWord);
-            int [] wgs = wordGlyphs[cWord];
-            if (wgs == null) {
-                wgs = wordGlyphs[cWord] 
-                    = new int[wordGlyphCounts[cWord]];
-                // We use this to track where the next
-                // glyph should go in wordGlyphs
-                // by the time we are done it should be correct again.
-                wordGlyphCounts[cWord] =0;
-            }
-            int cnt = wordGlyphCounts[cWord];
-            wgs[cnt] = i;
-            // Track the number of glyph groups in this word.
-            if (cnt==0) {
-                wordGlyphGroupsCounts[cWord]++;
-            } else {
-                if (wgs[cnt-1] != i-1)
-                    wordGlyphGroupsCounts[cWord]++;
-            }
-            wordGlyphCounts[cWord]++;
-        }
-
-        for (int i=0; i<words; i++) {
-            int cnt = wordGlyphGroupsCounts[i];
-            // System.err.println("WGGC: " + cnt);
-            GlyphGroupInfo []wordGlyphGroups = new GlyphGroupInfo[cnt];
-            if (cnt == 1) {
-                int [] glyphs = wordGlyphs[i];
-                int start  = glyphs[0];
-                int end    = glyphs[glyphs.length-1];
-                wordGlyphGroups[0] = new GlyphGroupInfo
-                    (gv, start, end, hide, hideLast[end], 
-                     glyphPos, advAdj, lastAdvAdj, space);
-            } else {
-                int glyphGroup = 0;
-                int []glyphs = wordGlyphs[i]; 
-                int prev = glyphs[0];
-                int start = prev;
-                for (int j=1; j<glyphs.length; j++) {
-                    if (prev+1 != glyphs[j]) {
-                        int end = glyphs[j-1];
-                        wordGlyphGroups[glyphGroup] = new GlyphGroupInfo
-                            (gv, start, end, hide, hideLast[end], 
-                             glyphPos, advAdj, lastAdvAdj, space);
-                        start = glyphs[j];
-                        glyphGroup++;
-                    }
-                    prev = glyphs[j];
-                }
-                int end = glyphs[glyphs.length-1];
-                wordGlyphGroups[glyphGroup] = new GlyphGroupInfo
-                    (gv, start, end, hide, hideLast[end], 
-                     glyphPos, advAdj, lastAdvAdj, space);
-            }
-            wordInfos[i].setGlyphGroups(wordGlyphGroups);
-        }
-        return wordInfos;
-    }
 }

Modified: xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/FlowRegions.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/FlowRegions.java?rev=384062&r1=384061&r2=384062&view=diff
==============================================================================
--- xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/FlowRegions.java (original)
+++ xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/FlowRegions.java Tue Mar  7 16:03:46 2006
@@ -81,6 +81,7 @@
     }
 
     public int getNumRangeOnLine() {
+        if (validRanges == null) return 0;
         return validRanges.size();
     }
     public void resetRange() {

Modified: xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/FlowTextNode.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/FlowTextNode.java?rev=384062&r1=384061&r2=384062&view=diff
==============================================================================
--- xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/FlowTextNode.java (original)
+++ xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/FlowTextNode.java Tue Mar  7 16:03:46 2006
@@ -23,6 +23,24 @@
 import org.apache.batik.gvt.TextNode;
 import org.apache.batik.gvt.TextPainter;
 
+import java.text.AttributedCharacterIterator;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import java.awt.geom.Point2D;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextAttribute;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Set;
+
+import org.apache.batik.gvt.font.GVTFont;
+import org.apache.batik.gvt.font.GVTGlyphVector;
+import org.apache.batik.gvt.font.GVTLineMetrics;
+import org.apache.batik.gvt.font.MultiGlyphVector;
+import org.apache.batik.gvt.text.GlyphLayout;
+import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
+import org.apache.batik.gvt.renderer.StrokingTextPainter.TextRun;
 
 /**
  * One line Class Desc
@@ -44,5 +62,4 @@
         else
             this.textPainter = textPainter;
     }
-
 };

Modified: xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/FlowTextPainter.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/FlowTextPainter.java?rev=384062&r1=384061&r2=384062&view=diff
==============================================================================
--- xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/FlowTextPainter.java (original)
+++ xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/FlowTextPainter.java Tue Mar  7 16:03:46 2006
@@ -27,6 +27,20 @@
 import org.apache.batik.gvt.TextPainter;
 import org.apache.batik.gvt.renderer.StrokingTextPainter;
 
+import java.awt.geom.Point2D;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextAttribute;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Set;
+
+import org.apache.batik.gvt.font.GVTFont;
+import org.apache.batik.gvt.font.GVTGlyphVector;
+import org.apache.batik.gvt.font.GVTLineMetrics;
+import org.apache.batik.gvt.font.MultiGlyphVector;
+import org.apache.batik.gvt.text.GlyphLayout;
+import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
+
 /**
  * One line Class Desc
  *
@@ -76,11 +90,431 @@
                 layouts.add(tr.getLayout());
             }
 
-            FlowGlyphLayout.textWrapTextChunk
-                (chunkACIs, chunkLayouts, rgns, fontRenderContext);
+            textWrap(chunkACIs, chunkLayouts, rgns, fontRenderContext);
         }
+        
 
         node.setTextRuns(textRuns);
-        return textRuns;
+        return node.getTextRuns();
+    }
+
+    public static final char SOFT_HYPHEN       = 0x00AD;
+    public static final char ZERO_WIDTH_SPACE  = 0x200B;
+    public static final char ZERO_WIDTH_JOINER = 0x200D;
+    public static final char SPACE             = ' ';
+
+    public static final AttributedCharacterIterator.Attribute WORD_LIMIT =
+        TextLineBreaks.WORD_LIMIT;
+
+    public static final AttributedCharacterIterator.Attribute FLOW_REGIONS =
+        GVTAttributedCharacterIterator.TextAttribute.FLOW_REGIONS;
+
+    public static final AttributedCharacterIterator.Attribute FLOW_LINE_BREAK
+        = GVTAttributedCharacterIterator.TextAttribute.FLOW_LINE_BREAK;
+    public static final AttributedCharacterIterator.Attribute LINE_HEIGHT
+        = GVTAttributedCharacterIterator.TextAttribute.LINE_HEIGHT;
+
+    public static final AttributedCharacterIterator.Attribute GVT_FONT
+        = GVTAttributedCharacterIterator.TextAttribute.GVT_FONT;
+
+    static protected Set szAtts = new HashSet();
+
+    static {
+        szAtts.add(TextAttribute.SIZE);
+        szAtts.add(GVT_FONT);
+        szAtts.add(LINE_HEIGHT);
+    }
+
+    public static boolean textWrap(AttributedCharacterIterator [] acis,
+                                   List chunkLayouts,
+                                   List flowRects,
+                                   FontRenderContext frc) {
+
+        int numChunks = acis.length;
+        // System.out.println("Len: " + acis.length + " Size: " + 
+        //                     chunkLayouts.size());
+
+        // Make a list of the GlyphVectors so we can construct a
+        // multiGlyphVector that makes them all look like one big
+        // glyphVector
+        GVTGlyphVector [] gvs            = new GVTGlyphVector[acis.length];
+        WordInfo       [][] wordInfos    = new WordInfo[acis.length][];
+        Iterator clIter = chunkLayouts.iterator();
+
+        float prevBotMargin = 0;
+        int numWords = 0;
+        BlockInfo [] blockInfos = new BlockInfo[acis.length];
+        float      [] topSkip   = new float[acis.length];
+        for (int chunk=0; clIter.hasNext(); chunk++) {
+            // System.err.print("Chunk: " + chunk + " Str: '");
+            AttributedCharacterIterator aci = acis[chunk];
+            List gvl = new LinkedList();
+            List layouts = (List)clIter.next();
+            Iterator iter = layouts.iterator();
+            while (iter.hasNext()) {
+                GlyphLayout gl = (GlyphLayout)iter.next();
+                gvl.add(gl.getGlyphVector());
+            }
+            GVTGlyphVector gv = new MultiGlyphVector(gvl);
+            gvs[chunk] = gv;
+            wordInfos[chunk] = doWordAnalysis(gv, aci, numWords, frc);
+            aci.first();
+            BlockInfo bi = (BlockInfo)aci.getAttribute(FLOW_PARAGRAPH);
+            bi.initLineInfo(frc);
+            blockInfos[chunk] = bi;
+            if (prevBotMargin > bi.getTopMargin())
+                topSkip[chunk] = prevBotMargin;
+            else
+                topSkip[chunk] = bi.getTopMargin();
+            prevBotMargin = bi.getBottomMargin();
+            numWords += wordInfos[chunk].length;
+        }
+
+        Iterator frIter = flowRects.iterator();
+        RegionInfo currentRegion = null;
+        int currWord = 0;
+        int chunk = 0;
+        List lineInfos = new LinkedList();
+        while(frIter.hasNext()) {
+            currentRegion = (RegionInfo) frIter.next();
+            FlowRegions fr = new FlowRegions(currentRegion.getShape());
+
+            while (chunk < wordInfos.length) {
+                WordInfo [] chunkInfo = wordInfos[chunk];
+                BlockInfo bi = blockInfos[chunk];
+                WordInfo  wi = chunkInfo[currWord];
+                Object    flowLine = wi.getFlowLine();
+                double    lh = Math.max(wi.getLineHeight(),bi.getLineHeight());
+                LineInfo li = new LineInfo(fr, bi, true);
+                double newY = li.getCurrentY()+topSkip[chunk];
+                topSkip[chunk] = 0;
+                if (li.gotoY(newY)) break;
+
+                while (!li.addWord(wi)) {
+                    // step down 1/10 of a line height and try again.
+                    newY = li.getCurrentY()+lh*.1;
+                    if (li.gotoY(newY)) break;
+                }
+                if (fr.done()) break;
+
+                currWord++;
+                for (;currWord < chunkInfo.length;currWord++) {
+                    wi = chunkInfo[currWord];
+                    if ((wi.getFlowLine() == flowLine) && (li.addWord(wi))) 
+                        continue;
+
+                    // Word didn't fit or we hit end of flowLine elem,
+                    // go to a new line.
+                    li.layout();
+                    lineInfos.add(li);
+                    li = null;
+
+                    flowLine = wi.getFlowLine();
+                    lh  = Math.max(wi.getLineHeight(),bi.getLineHeight());
+                    if (!fr.newLine(lh)) break; // region is done
+
+                    li = new LineInfo(fr, bi, false);
+                    while (!li.addWord(wi)) {
+                        newY =li.getCurrentY()+lh*.1;
+                        if (li.gotoY(newY)) break; 
+                    }
+                    if (fr.done()) break;
+                }
+                if (li != null) {
+                    li.setParaEnd(true);
+                    li.layout();
+                }
+
+                if (fr.done()) break;
+
+                chunk++;
+                currWord = 0;
+
+                if (bi.isFlowRegionBreak()) 
+                    break;
+
+                if (!fr.newLine(lh)) // Region is done.
+                    break;
+            }
+            if (chunk == wordInfos.length)
+                break;
+        }
+
+        boolean overflow = (chunk < wordInfos.length);
+
+        while (chunk < wordInfos.length) {
+            WordInfo [] chunkInfo = wordInfos[chunk];
+            while (currWord < chunkInfo.length) {
+                WordInfo wi = chunkInfo[currWord];
+                int numGG = wi.getNumGlyphGroups();
+                for (int gg=0; gg<numGG; gg++) {
+                    GlyphGroupInfo ggi = wi.getGlyphGroup(gg);
+                    GVTGlyphVector gv = ggi.getGlyphVector();
+                    int end = ggi.getEnd();
+                    for (int g=ggi.getStart(); g <= end; g++) {
+                        gv.setGlyphVisible(g, false);
+                    }
+                }
+                currWord++;
+            }
+            chunk++;
+            currWord = 0;
+        }
+
+        return overflow;
+    }
+
+    static int [] allocWordMap(int [] wordMap, int sz) {
+        if (wordMap != null) {
+            if (sz <= wordMap.length)
+                return wordMap;
+            if (sz < wordMap.length*2)
+                sz = wordMap.length*2;
+        }
+
+        int [] ret = new int[sz];
+        int ext=0;
+        if (wordMap != null)
+            ext = wordMap.length;
+        if (sz < ext) ext = sz;
+        int i=0;
+        for (; i<ext; i++) {
+            ret[i] = wordMap[i];
+        }
+        for (; i<sz; i++) {
+            ret[i] = -1;
+        }
+        return ret;
+    }
+
+    /**
+     * This returns an array of glyphs numbers for each glyph
+     * group in each word: ret[word][glyphGroup][glyphNum].
+     */
+    static WordInfo[] doWordAnalysis(GVTGlyphVector gv, 
+                                    AttributedCharacterIterator aci,
+                                    int numWords,
+                                    FontRenderContext frc) {
+        int numGlyphs = gv.getNumGlyphs();
+        int [] glyphWords = new int[numGlyphs];
+        int [] wordMap = allocWordMap(null, 10);
+        int maxWord = 0;
+        int aciIdx = aci.getBeginIndex();
+        // First we go through the glyphs seeing if any two ajacent
+        // words need to be collapsed because of a ligature.  This
+        // would be an odd case.  If it happens we consider the
+        // two words to be one.
+        for (int i=0; i<numGlyphs; i++) {
+            int cnt = gv.getCharacterCount(i,i);
+            aci.setIndex(aciIdx);
+            Integer integer = (Integer)aci.getAttribute(WORD_LIMIT);
+            int minWord = integer.intValue()-numWords;
+            if (minWord > maxWord) {
+                maxWord = minWord;
+                wordMap = allocWordMap(wordMap, maxWord+1);
+            }
+            aciIdx++;
+            for (int c=1; c<cnt; c++) {
+                aci.setIndex(aciIdx);
+                integer = (Integer)aci.getAttribute(WORD_LIMIT);
+                int cWord = integer.intValue()-numWords;
+                if (cWord > maxWord) {
+                    maxWord = cWord;
+                    wordMap = allocWordMap(wordMap, maxWord+1);
+                }
+                // We always want to use the min word as the main
+                // index for the new composite word.
+                if (cWord < minWord) {
+                    wordMap[minWord] = cWord;
+                    minWord = cWord;
+                } else if (cWord > minWord) {
+                    wordMap[cWord] = minWord;
+                }
+                aciIdx++;
+            }
+            glyphWords[i] = minWord;
+        }
+        int words=0;
+        WordInfo [] cWordMap = new WordInfo[maxWord+1];
+        for (int i=0; i<=maxWord; i++) {
+            int nw = wordMap[i];
+            if (nw == -1) {
+                // new word so give it a number.
+                cWordMap[i] = new WordInfo(words++);
+            } else {
+                int word = nw;
+                nw = wordMap[i];
+                while (nw != -1) {
+                    word = nw;
+                    nw = wordMap[word];
+                }
+                wordMap[i] = word; // help the next guy out
+                cWordMap[i] = cWordMap[word];
+            }
+        }
+        wordMap = null;
+        WordInfo [] wordInfos = new WordInfo[words];
+        for (int i=0; i<=maxWord; i++) {
+            WordInfo wi = cWordMap[i];
+            wordInfos[wi.getIndex()] = cWordMap[i];
+        }
+        
+        aciIdx = aci.getBeginIndex();
+        int aciEnd = aci.getEndIndex();
+        char ch = aci.setIndex(aciIdx);
+        
+        int aciWordStart = aciIdx;
+        GVTFont gvtFont = (GVTFont)aci.getAttribute(GVT_FONT);
+        float lineHeight = 1.f;
+        Float lineHeightFloat = (Float)aci.getAttribute(LINE_HEIGHT);
+        if (lineHeightFloat != null) 
+            lineHeight = lineHeightFloat.floatValue();
+        int runLimit = aci.getRunLimit(szAtts);
+        WordInfo prevWI = null;
+        float   [] lastAdvAdj = new float  [numGlyphs];
+        float   [] advAdj     = new float  [numGlyphs];
+        boolean [] hideLast   = new boolean[numGlyphs];
+        boolean [] hide       = new boolean[numGlyphs];
+        boolean [] space      = new boolean[numGlyphs];
+        float   [] glyphPos = gv.getGlyphPositions(0, numGlyphs+1, null);
+        for (int i=0; i<numGlyphs; i++) {
+            char pch = ch;
+            ch = aci.setIndex(aciIdx);
+            Integer integer = (Integer)aci.getAttribute(WORD_LIMIT);
+            WordInfo theWI = cWordMap[integer.intValue()-numWords];
+            if (theWI.getFlowLine() == null)
+                theWI.setFlowLine(aci.getAttribute(FLOW_LINE_BREAK));
+
+            if (prevWI == null) {
+                prevWI = theWI;
+            } else if (prevWI != theWI) {
+                GVTLineMetrics lm = gvtFont.getLineMetrics
+                    (aci, aciWordStart, aciIdx, frc);
+                prevWI.addLineMetrics(gvtFont, lm);
+                prevWI.addLineHeight(lineHeight);
+                aciWordStart = aciIdx;
+                prevWI = theWI;
+            } 
+
+            int chCnt = gv.getCharacterCount(i,i);
+            if (chCnt == 1) {
+                char nch;
+                float kern;
+                switch(ch) {
+                case SOFT_HYPHEN:
+                    hideLast[i] = true;
+                    nch = aci.next(); aci.previous();
+                    kern = gvtFont.getHKern(pch, nch);
+                    advAdj[i] = -(glyphPos[2*i+2]-glyphPos[2*i]+kern);
+                    break;
+                case ZERO_WIDTH_JOINER:
+                    hide[i] = true;
+                    break;
+                case ZERO_WIDTH_SPACE:
+                    hide[i] = true;
+                    break;
+                case SPACE:
+                    space[i] = true;
+                    nch = aci.next(); aci.previous();
+                    kern = gvtFont.getHKern(pch, nch);
+                    lastAdvAdj[i] = -(glyphPos[2*i+2]-glyphPos[2*i]+kern);
+                default:
+                }
+            }
+
+            aciIdx += chCnt;
+            if ((aciIdx > runLimit) && (aciIdx < aciEnd)) {
+                // Possible font size/style change so record current
+                // line metrics and start fresh.
+                GVTLineMetrics lm = gvtFont.getLineMetrics
+                    (aci,aciWordStart, runLimit, frc);
+                prevWI.addLineMetrics(gvtFont, lm);
+                prevWI.addLineHeight(lineHeight);
+                prevWI = null;
+                aciWordStart = aciIdx;
+                aci.setIndex(aciIdx);
+                gvtFont = (GVTFont)aci.getAttribute(GVT_FONT);
+                Float f = (Float)aci.getAttribute(LINE_HEIGHT);
+                lineHeight = f.floatValue();
+                runLimit = aci.getRunLimit(szAtts);
+            }
+        }
+        GVTLineMetrics lm = gvtFont.getLineMetrics
+            (aci,aciWordStart, runLimit, frc);
+        prevWI.addLineMetrics(gvtFont, lm);
+        prevWI.addLineHeight(lineHeight);
+
+        int [] wordGlyphCounts = new int[words];
+        // Build a mapping from words to glyphs.
+        for (int i=0; i<numGlyphs; i++) {
+            int word = glyphWords[i];
+            int cWord = cWordMap[word].getIndex();
+            glyphWords[i] = cWord;
+            wordGlyphCounts[cWord]++;
+        }
+
+        cWordMap = null;
+        int [][]wordGlyphs = new int [words][];
+        int []wordGlyphGroupsCounts = new int [words];
+        for (int i=0; i<numGlyphs; i++) {
+            int cWord = glyphWords[i];
+            // System.err.println("CW: " + cWord);
+            int [] wgs = wordGlyphs[cWord];
+            if (wgs == null) {
+                wgs = wordGlyphs[cWord] 
+                    = new int[wordGlyphCounts[cWord]];
+                // We use this to track where the next
+                // glyph should go in wordGlyphs
+                // by the time we are done it should be correct again.
+                wordGlyphCounts[cWord] =0;
+            }
+            int cnt = wordGlyphCounts[cWord];
+            wgs[cnt] = i;
+            // Track the number of glyph groups in this word.
+            if (cnt==0) {
+                wordGlyphGroupsCounts[cWord]++;
+            } else {
+                if (wgs[cnt-1] != i-1)
+                    wordGlyphGroupsCounts[cWord]++;
+            }
+            wordGlyphCounts[cWord]++;
+        }
+
+        for (int i=0; i<words; i++) {
+            int cnt = wordGlyphGroupsCounts[i];
+            // System.err.println("WGGC: " + cnt);
+            GlyphGroupInfo []wordGlyphGroups = new GlyphGroupInfo[cnt];
+            if (cnt == 1) {
+                int [] glyphs = wordGlyphs[i];
+                int start  = glyphs[0];
+                int end    = glyphs[glyphs.length-1];
+                wordGlyphGroups[0] = new GlyphGroupInfo
+                    (gv, start, end, hide, hideLast[end], 
+                     glyphPos, advAdj, lastAdvAdj, space);
+            } else {
+                int glyphGroup = 0;
+                int []glyphs = wordGlyphs[i]; 
+                int prev = glyphs[0];
+                int start = prev;
+                for (int j=1; j<glyphs.length; j++) {
+                    if (prev+1 != glyphs[j]) {
+                        int end = glyphs[j-1];
+                        wordGlyphGroups[glyphGroup] = new GlyphGroupInfo
+                            (gv, start, end, hide, hideLast[end], 
+                             glyphPos, advAdj, lastAdvAdj, space);
+                        start = glyphs[j];
+                        glyphGroup++;
+                    }
+                    prev = glyphs[j];
+                }
+                int end = glyphs[glyphs.length-1];
+                wordGlyphGroups[glyphGroup] = new GlyphGroupInfo
+                    (gv, start, end, hide, hideLast[end], 
+                     glyphPos, advAdj, lastAdvAdj, space);
+            }
+            wordInfos[i].setGlyphGroups(wordGlyphGroups);
+        }
+        return wordInfos;
     }
+
 };

Modified: xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/TextLineBreaks.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/TextLineBreaks.java?rev=384062&r1=384061&r2=384062&view=diff
==============================================================================
--- xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/TextLineBreaks.java (original)
+++ xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/flow/TextLineBreaks.java Tue Mar  7 16:03:46 2006
@@ -68,6 +68,7 @@
             return;
         char ch = aci.current(), prevCh = (char)-1;
         byte         cls = getCharCharClass(ch);
+        if (cls == CHAR_CLASS_LF) cls = CHAR_CLASS_BK;
         byte      curCls = cls;
         byte     prevCls = cls;
         byte prevPrevCls = -1;
@@ -77,6 +78,7 @@
         int ich = wordBegin+1;
         int lineEnd = aci.getRunLimit(lineBrks);
 
+        // handle case where input starts with an LF
         if (cls >= CHAR_CLASS_CM) cls = CHAR_CLASS_AL;
 
         for (ch = aci.next();
@@ -97,7 +99,8 @@
                 lineEnd = aci.getRunLimit(lineBrks);
                 continue;
             }
-              // handle spaces
+
+            // handle spaces
             curCls = getCharCharClass(ch);
             if (curCls == CHAR_CLASS_SP) {
                 // pbrk[ich-1] = BREAK_ACTION_PROHIBITED;
@@ -121,6 +124,24 @@
             if ((ch == CHAR_ZERO_WIDTH_JOINER) ||
                 (prevCh == CHAR_ZERO_WIDTH_JOINER))
                 continue; // Don't allow break around JOINER.
+
+            if ((curCls == CHAR_CLASS_BK) || (curCls == CHAR_CLASS_LF)) {
+                as.addAttribute(WORD_LIMIT, new Integer(wordCnt++),
+                                wordBegin, ich);
+                wordBegin = ich;
+                cls = CHAR_CLASS_BK;
+                continue;
+            }
+            if (prevCls == CHAR_CLASS_CR) {
+                as.addAttribute(WORD_LIMIT, new Integer(wordCnt++),
+                                wordBegin, ich-1);
+                wordBegin = ich-1;
+                cls = CHAR_CLASS_BK;
+                continue;
+            }
+            if (curCls == CHAR_CLASS_CR) {
+                continue;
+            }
  
             // handle combining marks
             if (curCls == CHAR_CLASS_CM) {
@@ -142,6 +163,11 @@
                 continue;
             }
 
+            if (cls == CHAR_CLASS_BK) {
+                cls = curCls;
+                continue;
+            }
+
             // lookup pair table information
             byte brk = brkPairs[cls][curCls];
 
@@ -255,11 +281,11 @@
     final public static byte CHAR_CLASS_SA = 20;
     final public static byte CHAR_CLASS_SP = 21;
     final public static byte CHAR_CLASS_BK = 22;
-    final public static byte CHAR_CLASS_AI = 23;
-    final public static byte CHAR_CLASS_CR = 24;
-    final public static byte CHAR_CLASS_LF = 25;
-    final public static byte CHAR_CLASS_SG = 26;
-    final public static byte CHAR_CLASS_XX = 27;
+    final public static byte CHAR_CLASS_AI = CHAR_CLASS_AL; // 23;
+    final public static byte CHAR_CLASS_CR = 24; // Can't occur (space res)
+    final public static byte CHAR_CLASS_LF = 25; // Can't occur (space res)
+    final public static byte CHAR_CLASS_SG = CHAR_CLASS_AL; // 26;
+    final public static byte CHAR_CLASS_XX = CHAR_CLASS_AL; // 27;
     final public static byte CHAR_CLASS_CB = 28;
 
     final public static String [] clsStrs = {

Modified: xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/font/AWTGVTGlyphVector.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/font/AWTGVTGlyphVector.java?rev=384062&r1=384061&r2=384062&view=diff
==============================================================================
--- xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/font/AWTGVTGlyphVector.java (original)
+++ xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/font/AWTGVTGlyphVector.java Tue Mar  7 16:03:46 2006
@@ -799,11 +799,7 @@
         int end   = endGlyphIndex+ci.getBeginIndex();
 
         for (char c = ci.setIndex(start); ci.getIndex() <= end; c=ci.next()) {
-            if (ArabicTextHandler.isLigature(c)) {
-                charCount += ArabicTextHandler.getNumChars(c);
-            } else {
-                charCount++;
-            }
+            charCount += ArabicTextHandler.getNumChars(c);
         }
 
         return charCount;

Modified: xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/renderer/StrokingTextPainter.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/renderer/StrokingTextPainter.java?rev=384062&r1=384061&r2=384062&view=diff
==============================================================================
--- xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/renderer/StrokingTextPainter.java (original)
+++ xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/renderer/StrokingTextPainter.java Tue Mar  7 16:03:46 2006
@@ -204,7 +204,7 @@
         // System.out.println("Reorder: " + reorderTime + " FontMatching: " + fontMatchingTime + " Layout: " + layoutTime);
         // cache the textRuns so don't need to recalculate
         node.setTextRuns(textRuns);
-        return textRuns;
+        return node.getTextRuns();
    }
 
     public List computeTextRuns(TextNode node, 
@@ -1673,7 +1673,7 @@
             this.anchorType = TextNode.Anchor.ANCHOR_START;
 
             TextNode.Anchor anchor = (TextNode.Anchor) aci.getAttribute
-		(GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE);
+                (GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE);
             if (anchor != null) {
                 this.anchorType = anchor.getType();
             }

Modified: xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/text/ArabicTextHandler.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/text/ArabicTextHandler.java?rev=384062&r1=384061&r2=384062&view=diff
==============================================================================
--- xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/text/ArabicTextHandler.java (original)
+++ xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/text/ArabicTextHandler.java Tue Mar  7 16:03:46 2006
@@ -1,6 +1,6 @@
 /*
 
-   Copyright 2001,2003  The Apache Software Foundation 
+   Copyright 2001,2003,2006  The Apache Software Foundation
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -53,12 +53,19 @@
         GVTAttributedCharacterIterator.TextAttribute.ARABIC_MEDIAL;
 
     /**
+     * private ctor prevents unnecessary instantiation of this class.
+     */
+    private ArabicTextHandler() {
+
+    }
+
+    /*
      * If the AttributedString contains any arabic chars, assigns an
      * arabic form attribute, i&#x2e;e&#x2e; initial|medial|terminal|isolated,
      * to each arabic char.
      *
      * @param as The string to attach the arabic form attributes to.
-     * @return An attributed string with arabic form attributes.  
+     * @return An attributed string with arabic form attributes.
      */
     public static AttributedString assignArabicForms(AttributedString as) {
 
@@ -73,47 +80,54 @@
         // reorder that part of the string so that it becomes tAB
         // construct the reordered ACI
         AttributedCharacterIterator aci = as.getIterator();
-        boolean didSomeReordering = false;
         int numChars = aci.getEndIndex() - aci.getBeginIndex();
-        int charOrder[] = new int[numChars];
-        for (int i = 0; i < numChars; i++) {
-            charOrder[i] = i + aci.getBeginIndex();
-        }
-        for (int i = 1; i < numChars-1; i++) {
-            char c = aci.setIndex(aci.getBeginIndex() + i);
-            if (arabicCharTransparent(c)) {
-                char prevChar = aci.setIndex(aci.getBeginIndex() + i-1);
-                char nextChar = aci.setIndex(aci.getBeginIndex() + i+1);
-                if (charMap.get("" + prevChar + nextChar) != null) {
-                    // found a ligature, separated by a transparent char
-                    didSomeReordering = true;
-                    int temp = charOrder[i];
-                    charOrder[i] = charOrder[i-1];
-                    charOrder[i-1] = temp;
+        int charOrder[] = null;
+        if (numChars >= 3) {
+            char prevChar = aci.first();
+            char c        = aci.next(); 
+            int  i        = 1;
+            for (char nextChar = aci.next(); 
+                 nextChar != AttributedCharacterIterator.DONE; 
+                 prevChar = c, c = nextChar, nextChar = aci.next(), i++) {
+                if (arabicCharTransparent(c)) {
+                    if (hasSubstitute(prevChar, nextChar)) {
+                        // found a ligature, separated by a transparent char
+                        if (charOrder == null) {
+                            charOrder = new int[numChars];
+                            for (int j = 0; j < numChars; i++) {
+                                charOrder[i] = j + aci.getBeginIndex();
+                            }
+                        }
+                        int temp = charOrder[i];
+                        charOrder[i] = charOrder[i-1];
+                        charOrder[i-1] = temp;
+                    }
                 }
             }
         }
 
-        if (didSomeReordering) {
+        if (charOrder != null) {
             // need to reconstruct the reordered attributed string
-            String reorderedString = "";
+            StringBuffer reorderedString = new StringBuffer(numChars);
             char c;
             for (int i = 0; i < numChars; i++) {
                 c = aci.setIndex(charOrder[i]);
-                reorderedString += c;
+                reorderedString.append( c );
             }
-            AttributedString reorderedAS = new AttributedString(reorderedString);
+            AttributedString reorderedAS;
+            reorderedAS = new AttributedString(reorderedString.toString());
+
             for (int i = 0; i < numChars; i++) {
                 aci.setIndex(charOrder[i]);
                 Map attributes = aci.getAttributes();
                 reorderedAS.addAttributes(attributes, i, i+1);
             }
-            if ((charOrder[0] == (aci.getBeginIndex()+1)) && 
-                (charOrder[1] ==  aci.getBeginIndex())) {
-                // have swapped the first 2 chars, may need to move
+
+            if (charOrder[0] != aci.getBeginIndex()) {
+                // have swapped the first char. Need to move
                 // any position attributes
 
-                aci.first();
+                aci.setIndex(charOrder[0]);
                 Float x = (Float) aci.getAttribute(
                     GVTAttributedCharacterIterator.TextAttribute.X);
                 Float y = (Float) aci.getAttribute(
@@ -122,17 +136,17 @@
                 if (x != null && !x.isNaN()) {
                     reorderedAS.addAttribute
                         (GVTAttributedCharacterIterator.TextAttribute.X,
-                         new Float(Float.NaN), 1, 2);
+                         new Float(Float.NaN), charOrder[0], charOrder[0]+1);
                     reorderedAS.addAttribute
-                        (GVTAttributedCharacterIterator.TextAttribute.X, 
+                        (GVTAttributedCharacterIterator.TextAttribute.X,
                          x, 0, 1);
                 }
                 if (y != null && !y.isNaN()) {
                     reorderedAS.addAttribute
                         (GVTAttributedCharacterIterator.TextAttribute.Y,
-                         new Float(Float.NaN), 1, 2);
+                         new Float(Float.NaN), charOrder[0], charOrder[0]+1);
                     reorderedAS.addAttribute
-                        (GVTAttributedCharacterIterator.TextAttribute.Y, 
+                        (GVTAttributedCharacterIterator.TextAttribute.Y,
                          y, 0, 1);
                 }
             }
@@ -140,15 +154,23 @@
         }
 
         // first assign none to all arabic letters
-        int c;
         aci = as.getIterator();
-        for (int i = aci.getBeginIndex(); i < aci.getEndIndex(); i++) {
-            c = aci.setIndex(i);
+        int runStart = -1;
+        int idx = aci.getBeginIndex();
+        for (int c = aci.first(); 
+             c != AttributedCharacterIterator.DONE;
+             c = aci.next(), idx++) {
             if ((c >= arabicStart) && (c <= arabicEnd)) {
-                as.addAttribute(ARABIC_FORM, ARABIC_NONE,i, i+1);
+                if (runStart == -1)
+                    runStart = idx;
+            } else if (runStart != -1) {
+                as.addAttribute(ARABIC_FORM, ARABIC_NONE, runStart, idx);
+                runStart = -1;
             }
         }
-        
+        if (runStart != -1) 
+            as.addAttribute(ARABIC_FORM, ARABIC_NONE, runStart, idx);
+
         aci = as.getIterator();  // Make sure ACI tracks ARABIC_FORM
         int end   = aci.getBeginIndex();
 
@@ -162,16 +184,16 @@
 
             if (currentForm == null) {
                 // only modify if the chars in the run are arabic
-                continue; 
+                continue;
             }
-            
+
 
             int currentIndex = start;
             int prevCharIndex = start-1;
             while (currentIndex < end) {
                 char prevChar = currentChar;
                 currentChar=  aci.setIndex(currentIndex);
-                while (arabicCharTransparent(currentChar) && 
+                while (arabicCharTransparent(currentChar) &&
                        (currentIndex < end)) {
                     currentIndex++;
                     currentChar = aci.setIndex(currentIndex);
@@ -188,7 +210,7 @@
                         && arabicCharShapesLeft(currentChar)) {
                         // Increment the form of the previous char
                         prevForm = new Integer(prevForm.intValue()+1);
-                        as.addAttribute(ARABIC_FORM, prevForm, 
+                        as.addAttribute(ARABIC_FORM, prevForm,
                                         prevCharIndex, prevCharIndex+1);
 
                         // and set the form of the current char to INITIAL
@@ -245,9 +267,9 @@
      * @return True if at least one char is arabic, false otherwise.
      */
     public static boolean containsArabic(AttributedCharacterIterator aci) {
-        char c;
-        for (int i = aci.getBeginIndex(); i < aci.getEndIndex(); i++) {
-            c = aci.setIndex(i);
+        for (char c = aci.first(); 
+             c != AttributedCharacterIterator.DONE;
+             c = aci.next()) {
             if (arabicChar(c)) {
                 return true;
             }
@@ -263,11 +285,14 @@
      */
     public static boolean arabicCharTransparent(char c) {
         int charVal = c;
-        if ((charVal >= 0x064B && charVal <= 0x0655) ||
+        if ((charVal  < 0x064B) || (charVal > 0x06ED))
+            return false;
+
+        if ((charVal <= 0x0655)                      ||
             (charVal == 0x0670)                      ||
             (charVal >= 0x06D6 && charVal <= 0x06E4) ||
             (charVal >= 0x06E7 && charVal <= 0x06E8) ||
-            (charVal >= 0x06EA && charVal <= 0x06ED)) {
+            (charVal >= 0x06EA)) {
             return true;
         }
         return false;
@@ -350,6 +375,17 @@
         return arabicCharShapesRight(c);
     }
 
+    public static boolean hasSubstitute(char ch1, char ch2) {
+        if ((ch1 < doubleCharFirst) || (ch1 > doubleCharLast)) return false;
+
+        int [][]remaps = doubleCharRemappings[ch1-doubleCharFirst];
+        if (remaps == null) return false;
+        for (int i=0; i<remaps.length; i++) {
+            if (remaps[i][0] == ch2)
+                return true;
+        }
+        return false;
+    }
 
     /**
      * Will try and find a substitute character of the specified form.
@@ -362,16 +398,29 @@
      * @return The unicode value of the substutute char, or -1 if no susbtitue
      * exists.
      */
-    public static int getSubstituteChar(String unicode, int form) {
+    public static int getSubstituteChar(char ch1, char ch2, int form) {
         if (form == 0) return -1;
-        int chars[] = (int[])charMap.get(unicode);
-        if (chars == null) return -1;
+        if ((ch1 < doubleCharFirst) || (ch1 > doubleCharLast)) return -1;
 
-        if (chars[form-1] > 0)
-            return chars[form-1];
+        int [][]remaps = doubleCharRemappings[ch1-doubleCharFirst];
+        if (remaps == null) return -1;
+        for (int i=0; i<remaps.length; i++) {
+            if (remaps[i][0] == ch2)
+                return remaps[i][form];
+        }
         return -1;
     }
 
+    public static int getSubstituteChar(char ch, int form) {
+        if (form == 0) return -1;
+        if ((ch < singleCharFirst) || (ch > singleCharLast)) return -1;
+
+        int chars[] = singleCharRemappings[ch-singleCharFirst];
+        if (chars == null) return -1;
+
+        return chars[form-1];
+    }
+
     /**
      * Where possible substitues plain arabic glyphs with their shaped
      * forms.  This is needed when the arabic text is rendered using
@@ -385,66 +434,68 @@
      * @return A String containing the shaped versions of the arabic characters
      */
     public static String createSubstituteString(AttributedCharacterIterator aci) {
-
-        String substString = "";
-        for (int i = aci.getBeginIndex(); i < aci.getEndIndex(); i++) {
+        int start = aci.getBeginIndex();
+        int end   = aci.getEndIndex();
+        int numChar = end-start;
+        StringBuffer substString = new StringBuffer(numChar);
+        for (int i=start; i< end; i++) {
             char c = aci.setIndex(i);
-            if (arabicChar(c)) {
-                Integer form = (Integer)aci.getAttribute(ARABIC_FORM);
-                // see if the c is the start of a ligature
-                if (charStartsLigature(c) && i < aci.getEndIndex()) {
-                    char nextChar = aci.setIndex(i+1);
-                    Integer nextForm = (Integer)aci.getAttribute(ARABIC_FORM);
-                    if (form != null && nextForm != null) {
-                        if (form.equals(ARABIC_TERMINAL)
-                            && nextForm.equals(ARABIC_INITIAL)) {
-                            // look for an isolated ligature
-                            int substChar = ArabicTextHandler.getSubstituteChar
-                                ("" + c + nextChar,ARABIC_ISOLATED.intValue());
-                            if (substChar > -1) {
-                                substString += (char)substChar;
-                                i++;
-                                continue;
-                            }
-                        } else if (form.equals(ARABIC_TERMINAL)) {
-                            // look for a terminal ligature
-                            int substChar = ArabicTextHandler.getSubstituteChar
-                                ("" + c + nextChar,ARABIC_TERMINAL.intValue());
-                            if (substChar > -1) {
-                                substString += (char)substChar;
-                                i++;
-                                continue;
-                            }
-                        } else if (form.equals(ARABIC_MEDIAL)
-                                && nextForm.equals(ARABIC_MEDIAL)) {
-                            // look for a medial ligature
-                            int substChar = ArabicTextHandler.getSubstituteChar
-                                ("" + c + nextChar,ARABIC_MEDIAL.intValue());
-                            if (substChar > -1) {
-                                substString += (char)substChar;
-                                i++;
-                                continue;
-                            }
+            if (!arabicChar(c)) {
+                substString.append(c);
+                continue;
+            }
+
+            Integer form = (Integer)aci.getAttribute(ARABIC_FORM);
+            // see if the c is the start of a ligature
+            if (charStartsLigature(c) && (i+1 < end)) {
+                char nextChar = aci.setIndex(i+1);
+                Integer nextForm = (Integer)aci.getAttribute(ARABIC_FORM);
+                if (form != null && nextForm != null) {
+                    if (form.equals(ARABIC_TERMINAL)
+                        && nextForm.equals(ARABIC_INITIAL)) {
+                        // look for an isolated ligature
+                        int substChar = ArabicTextHandler.getSubstituteChar
+                            (c, nextChar,ARABIC_ISOLATED.intValue());
+                        if (substChar > -1) {
+                            substString.append((char)substChar);
+                            i++;
+                            continue;
+                        }
+                    } else if (form.equals(ARABIC_TERMINAL)) {
+                        // look for a terminal ligature
+                        int substChar = ArabicTextHandler.getSubstituteChar
+                            (c, nextChar,ARABIC_TERMINAL.intValue());
+                        if (substChar > -1) {
+                            substString.append((char)substChar);
+                            i++;
+                            continue;
+                        }
+                    } else if (form.equals(ARABIC_MEDIAL)
+                               && nextForm.equals(ARABIC_MEDIAL)) {
+                        // look for a medial ligature
+                        int substChar = ArabicTextHandler.getSubstituteChar
+                            (c, nextChar,ARABIC_MEDIAL.intValue());
+                        if (substChar > -1) {
+                            substString.append((char)substChar);
+                            i++;
+                            continue;
                         }
                     }
                 }
+            }
 
-                // couln't find a matching ligature so  just look for a simple substitution
-                if (form != null && form.intValue() > 0) {
-                    int substChar = ArabicTextHandler.getSubstituteChar(""+c, form.intValue());
-                    if (substChar > -1) {
-                        substString += (char)substChar;
-                    } else {
-                        substString += c;
-                    }
-                } else {
-                    substString += c;
+            // couldn't find a matching ligature so just look for a
+            // simple substitution
+            if (form != null && form.intValue() > 0) {
+                int substChar = getSubstituteChar(c, form.intValue());
+                if (substChar > -1) {
+                    c = (char)substChar;
                 }
-            } else {
-                substString += c;
             }
+            substString.append(c);
         }
-        return substString;
+
+        return substString.toString();
     }
 
     /**
@@ -466,209 +517,151 @@
     }
 
     /**
-     * Returns the number of characters the glyph for the specified character
-     * represents. If the glyph represents a ligature this will be 2, otherwise 1.
+     * Returns the number of characters the glyph for the specified
+     * character represents. If the glyph represents a ligature this
+     * will be 2, otherwise 1.
      *
      * @param c The character to test.
      * @return The number of characters the glyph for c represents.
      */
     public static int getNumChars(char c) {
         // if c is a ligature returns 2, else returns 1
-        if (isLigature(c)) {
+        if (isLigature(c))
             // at the moment only support ligatures with two chars
             return 2;
-        }
         return 1;
     }
 
     /**
-     * Returns true if the glyph for the specified character respresents a ligature.
+     * Returns true if the glyph for the specified character
+     * respresents a ligature.
      *
      * @param c The character to test.
      * @return True if c is a ligature, false otherwise.
      */
     public static boolean isLigature(char c) {
         int charVal = c;
-        if ((charVal >= 0xFE70 && charVal <= 0xFE72)
-            || (charVal == 0xFE74)
-            || (charVal >= 0xFE76 && charVal <= 0xFE7F)
-            || (charVal >= 0xFEF5 && charVal <= 0xFEFC)) {
+        if ((charVal < 0xFE70) || (charVal > 0xFEFC))
+            return false;
+
+        if ((charVal <= 0xFE72)                      ||
+            (charVal == 0xFE74)                      ||
+            (charVal >= 0xFE76 && charVal <= 0xFE7F) ||
+            (charVal >= 0xFEF5)) {
             return true;
         }
         return false;
     }
 
 
-    static {
-
-        // constructs the character map that maps arabic characters and
-        // ligature to their various forms
-        // NOTE: the unicode values for ligatures are stored here in
-        // visual order (not logical order)
-
-        int chars1[] = {0xFE70, -1, -1, -1};  //    isolated, final, initial, medial
-        charMap.put(new String("" + (char)0x064B + (char)0x0020), chars1);
-
-        int chars2[] = {-1, -1, -1, 0xFE71};
-        charMap.put(new String("" + (char)0x064B + (char)0x0640), chars2);
-
-        int chars3[] = {0xFE72, -1, -1, -1};
-        charMap.put(new String("" + (char)0x064C + (char)0x0020), chars3);
-
-        int chars4[] = {0xFE74, -1, -1, -1};
-        charMap.put(new String("" + (char)0x064D + (char)0x0020), chars4);
-
-        int chars5[] = {0xFE76, -1, -1, -1};
-        charMap.put(new String("" + (char)0x064E + (char)0x0020), chars5);
-
-        int chars6[] = {-1, -1, -1, 0xFE77};
-        charMap.put(new String("" + (char)0x064E + (char)0x0640), chars6);
-
-        int chars7[] = {0xFE78, -1, -1, -1};
-        charMap.put(new String("" + (char)0x064F + (char)0x0020), chars7);
-
-        int chars8[] = {-1, -1, -1, 0xFE79};
-        charMap.put(new String("" + (char)0x064F + (char)0x0640), chars8);
-
-        int chars9[] = {0xFE7A, -1, -1, -1};
-        charMap.put(new String("" + (char)0x0650 + (char)0x0020), chars9);
-
-        int chars10[] = {-1, -1, -1, 0xFE7B};
-        charMap.put(new String("" + (char)0x0650 + (char)0x0640), chars10);
-
-        int chars11[] = {0xFE7C, -1, -1, -1};
-        charMap.put(new String("" + (char)0x0651 + (char)0x0020), chars11);
-
-        int chars12[] = {-1, -1, -1, 0xFE7D};
-        charMap.put(new String("" + (char)0x0651 + (char)0x0640), chars12);
-
-        int chars13[] = {0xFE7E, -1, -1, -1};
-        charMap.put(new String("" + (char)0x0652 + (char)0x0020), chars13);
-
-        int chars14[] = {-1, -1, -1, 0xFE7F};
-        charMap.put(new String("" + (char)0x0652 + (char)0x0640), chars14);
-
-        int chars15[] = {0xFE80, -1, -1, -1};
-        charMap.put(new String("" + (char)0x0621), chars15);
-
-        int chars16[] = {0xFE81, 0xFE82, -1, -1};
-        charMap.put(new String("" + (char)0x0622), chars16);
-
-        int chars17[] = {0xFE83, 0xFE84, -1, -1};
-        charMap.put(new String("" + (char)0x0623), chars17);
-
-        int chars18[] = {0xFE85, 0xFE86, -1, -1};
-        charMap.put(new String("" + (char)0x0624), chars18);
-
-        int chars19[] = {0xFE87, 0xFE88, -1, -1};
-        charMap.put(new String("" + (char)0x0625), chars19);
-
-        int chars20[] = {0xFE89, 0xFE8A, 0xFE8B, 0xFE8C};
-        charMap.put(new String("" + (char)0x0626), chars20);
-
-        int chars21[] = {0xFE8D, 0xFE8E, -1, -1};
-        charMap.put(new String("" + (char)0x0627), chars21);
-
-        int chars22[] = {0xFE8F, 0xFE90, 0xFE91, 0xFE92};
-        charMap.put(new String("" + (char)0x0628), chars22);
-
-        int chars23[] = {0xFE93, 0xFE94, -1, -1};
-        charMap.put(new String("" + (char)0x0629), chars23);
-
-        int chars24[] = {0xFE95, 0xFE96, 0xFE97, 0xFE98};
-        charMap.put(new String("" + (char)0x062A), chars24);
-
-        int chars25[] = {0xFE99, 0xFE9A,  0xFE9B, 0xFE9C};
-        charMap.put(new String("" + (char)0x062B), chars25);
-
-        int chars26[] = {0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0};
-        charMap.put(new String("" + (char)0x062C), chars26);
-
-        int chars27[] = {0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4};
-        charMap.put(new String("" + (char)0x062D), chars27);
-
-        int chars28[] = {0xFEA5,  0xFEA6, 0xFEA7, 0xFEA8};
-        charMap.put(new String("" + (char)0x062E), chars28);
-
-        int chars29[] = {0xFEA9, 0xFEAA, -1, -1};
-        charMap.put(new String("" + (char)0x062F), chars29);
-
-        int chars30[] = {0xFEAB, 0xFEAC, -1, -1};
-        charMap.put(new String("" + (char)0x0630), chars30);
-
-        int chars31[] = {0xFEAD, 0xFEAE, -1, -1};
-        charMap.put(new String("" + (char)0x0631), chars31);
-
-        int chars32[] = {0xFEAF,  0xFEB0, -1, -1};
-        charMap.put(new String("" + (char)0x0632), chars32);
-
-        int chars33[] = {0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4};
-        charMap.put(new String("" + (char)0x0633), chars33);
-
-        int chars34[] = {0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8};
-        charMap.put(new String("" + (char)0x0634), chars34);
-
-        int chars35[] = {0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC};
-        charMap.put(new String("" + (char)0x0635), chars35);
-
-        int chars36[] = {0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0};
-        charMap.put(new String("" + (char)0x0636), chars36);
-
-        int chars37[] = {0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4};
-        charMap.put(new String("" + (char)0x0637), chars37);
-
-        int chars38[] = {0xFEC5,  0xFEC6, 0xFEC7, 0xFEC8};
-        charMap.put(new String("" + (char)0x0638), chars38);
-
-        int chars39[] = {0xFEC9,  0xFECA, 0xFECB, 0xFECC};
-        charMap.put(new String("" + (char)0x0639), chars39);
-
-        int chars40[] = { 0xFECD,  0xFECE, 0xFECF,  0xFED0};
-        charMap.put(new String("" + (char)0x063A), chars40);
-
-        int chars41[] = {0xFED1, 0xFED2, 0xFED3, 0xFED4};
-        charMap.put(new String("" + (char)0x0641), chars41);
-
-        int chars42[] = {0xFED5, 0xFED6, 0xFED7, 0xFED8};
-        charMap.put(new String("" + (char)0x0642), chars42);
-
-        int chars43[] = {0xFED9, 0xFEDA,  0xFEDB, 0xFEDC};
-        charMap.put(new String("" + (char)0x0643), chars43);
-
-        int chars44[] = {0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0};
-        charMap.put(new String("" + (char)0x0644), chars44);
-
-        int chars45[] = {0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4};
-        charMap.put(new String("" + (char)0x0645), chars45);
-
-        int chars46[] = {0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8};
-        charMap.put(new String("" + (char)0x0646), chars46);
-
-        int chars47[] = {0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC};
-        charMap.put(new String("" + (char)0x0647), chars47);
-
-        int chars48[] = {0xFEED, 0xFEEE, -1, -1};
-        charMap.put(new String("" + (char)0x0648), chars48);
-
-        int chars49[] = {0xFEEF, 0xFEF0, -1, -1};
-        charMap.put(new String("" + (char)0x0649), chars49);
-
-        int chars50[] = {0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4};
-        charMap.put(new String("" + (char)0x064A), chars50);
-
-         int chars51[] = {0xFEF5, 0xFEF6, -1, -1};
-        charMap.put(new String("" + (char)0x0622 + (char)0x0644), chars51);
-
-        int chars52[] = {0xFEF7, 0xFEF8, -1, -1};
-        charMap.put(new String("" + (char)0x0623 + (char)0x0644), chars52);
-
-        int chars53[] = {0xFEF9, 0xFEFA, -1, -1};
-        charMap.put(new String("" + (char)0x0625 + (char)0x0644), chars53);
-
-        int chars54[] = {0xFEFB,  0xFEFC, -1, -1};
-        charMap.put(new String("" + (char)0x0627 + (char)0x0644), chars54);
-
-    }
-
-
+    // constructs the character map that maps arabic characters and
+    // ligature to their various forms
+    // NOTE: the unicode values for ligatures are stored here in
+    // visual order (not logical order)
+    
+    // Single char remappings:
+    static int singleCharFirst=0x0621;
+    static int singleCharLast =0x064A;
+    static int [][] singleCharRemappings = {
+     // isolated, final, initial, medial
+        {0xFE80,     -1,     -1,     -1},  // 0x0621
+        {0xFE81, 0xFE82,     -1,     -1},  // 0x0622
+        {0xFE83, 0xFE84,     -1,     -1},  // 0x0623
+        {0xFE85, 0xFE86,     -1,     -1},  // 0x0624
+        {0xFE87, 0xFE88,     -1,     -1},  // 0x0625
+        {0xFE89, 0xFE8A, 0xFE8B, 0xFE8C},  // 0x0626
+        {0xFE8D, 0xFE8E,     -1,     -1},  // 0x0627
+        {0xFE8F, 0xFE90, 0xFE91, 0xFE92},  // 0x0628
+        {0xFE93, 0xFE94,     -1,     -1},  // 0x0629
+        {0xFE95, 0xFE96, 0xFE97, 0xFE98},  // 0x062A
+        {0xFE99, 0xFE9A, 0xFE9B, 0xFE9C},  // 0x062B
+        {0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0},  // 0x062C
+        {0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4},  // 0x062D
+        {0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8},  // 0x062E
+        {0xFEA9, 0xFEAA,     -1,     -1},  // 0x062F
+        {0xFEAB, 0xFEAC,     -1,     -1},  // 0x0630
+        {0xFEAD, 0xFEAE,     -1,     -1},  // 0x0631
+        {0xFEAF, 0xFEB0,     -1,     -1},  // 0x0632
+        {0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4},  // 0x0633
+        {0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8},  // 0x0634
+        {0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC},  // 0x0635
+        {0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0},  // 0x0636
+        {0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4},  // 0x0637
+        {0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8},  // 0x0638
+        {0xFEC9, 0xFECA, 0xFECB, 0xFECC},  // 0x0639
+        {0xFECD, 0xFECE, 0xFECF, 0xFED0},  // 0x063A
+
+        null,  // 0x063B
+        null,  // 0x063C
+        null,  // 0x063D
+        null,  // 0x063E
+        null,  // 0x063F
+        null,  // 0x0640
+
+        {0xFED1, 0xFED2, 0xFED3, 0xFED4},  // 0x0641
+        {0xFED5, 0xFED6, 0xFED7, 0xFED8},  // 0x0642
+        {0xFED9, 0xFEDA, 0xFEDB, 0xFEDC},  // 0x0643
+        {0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0},  // 0x0644
+        {0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4},  // 0x0645
+        {0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8},  // 0x0646
+        {0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC},  // 0x0647
+        {0xFEED, 0xFEEE,     -1,     -1},  // 0x0648
+        {0xFEEF, 0xFEF0,     -1,     -1},  // 0x0649
+        {0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4}}; // 0x064A
+
+    static int doubleCharFirst=0x0622;
+    static int doubleCharLast =0x0652;
+    static int [][][] doubleCharRemappings = {
+      // 2nd Char, isolated, final, initial, medial
+        {{0x0644,   0xFEF5, 0xFEF6,     -1,     -1}},  // 0x0622
+        {{0x0644,   0xFEF7, 0xFEF8,     -1,     -1}},  // 0x0623
+        null,                                          // 0x0624
+        {{0x0644,   0xFEF9, 0xFEFA,     -1,     -1}},  // 0x0625
+        null,                                          // 0x0626
+        {{0x0644,   0xFEFB, 0xFEFC,     -1,     -1}},  // 0x0627
+
+        null,                                          // 0x0628
+        null,                                          // 0x0629
+        null,                                          // 0x0630
+        null,                                          // 0x0631
+        null,                                          // 0x0632
+        null,                                          // 0x0633
+        null,                                          // 0x0634
+        null,                                          // 0x0635
+        null,                                          // 0x0636
+        null,                                          // 0x0637
+        null,                                          // 0x0638
+        null,                                          // 0x0639
+        null,                                          // 0x063A
+        null,                                          // 0x063B
+        null,                                          // 0x063C
+        null,                                          // 0x063D
+        null,                                          // 0x063E
+        null,                                          // 0x063F
+        null,                                          // 0x0640
+        null,                                          // 0x0641
+        null,                                          // 0x0642
+        null,                                          // 0x0643
+        null,                                          // 0x0644
+        null,                                          // 0x0645
+        null,                                          // 0x0646
+        null,                                          // 0x0647
+        null,                                          // 0x0648
+        null,                                          // 0x0649
+        null,                                          // 0x064A
+
+        {{0x0020,   0xFE70,     -1,     -1,     -1},   // 0x064B
+         {0x0640,       -1,     -1,     -1, 0xFE71}},
+        {{0x0020,   0xFE72,     -1,     -1,     -1}},  // 0x064C
+        {{0x0020,   0xFE74,     -1,     -1,     -1}},  // 0x064D
+        {{0x0020,   0xFE76,     -1,     -1,     -1},   // 0x064E
+         {0x0640,       -1,     -1,     -1, 0xFE77}},
+        {{0x0020,   0xFE78,     -1,     -1,     -1},   // 0x064F
+         {0x0640,       -1,     -1,     -1, 0xFE79}},
+        {{0x0020,   0xFE7A,     -1,     -1,     -1},   // 0x0650
+         {0x0640,       -1,     -1,     -1, 0xFE7B}},
+        {{0x0020,   0xFE7C,     -1,     -1,     -1},   // 0x0651
+         {0x0640,       -1,     -1,     -1, 0xFE7D}},
+        {{0x0020,   0xFE7E,     -1,     -1,     -1},   // 0x0652
+         {0x0640,       -1,     -1,     -1, 0xFE7F}}};
 }

Modified: xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/text/GlyphLayout.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/text/GlyphLayout.java?rev=384062&r1=384061&r2=384062&view=diff
==============================================================================
--- xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/text/GlyphLayout.java (original)
+++ xmlgraphics/batik/branches/anim/sources/org/apache/batik/gvt/text/GlyphLayout.java Tue Mar  7 16:03:46 2006
@@ -55,11 +55,6 @@
  */
 public class GlyphLayout implements TextSpanLayout {
 
-    public static final char SOFT_HYPHEN       = 0x00AD;
-    public static final char ZERO_WIDTH_SPACE  = 0x200B;
-    public static final char ZERO_WIDTH_JOINER = 0x200D;
-    public static final char SPACE             = ' ';
-
     private GVTGlyphVector gv;
     private GVTFont font;
     private GVTLineMetrics metrics;

Modified: xmlgraphics/batik/branches/anim/sources/org/apache/batik/script/rhino/RhinoClassLoader.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/batik/branches/anim/sources/org/apache/batik/script/rhino/RhinoClassLoader.java?rev=384062&r1=384061&r2=384062&view=diff
==============================================================================
--- xmlgraphics/batik/branches/anim/sources/org/apache/batik/script/rhino/RhinoClassLoader.java (original)
+++ xmlgraphics/batik/branches/anim/sources/org/apache/batik/script/rhino/RhinoClassLoader.java Tue Mar  7 16:03:46 2006
@@ -164,4 +164,3 @@
         return perms;
     }
 }
-