Hello,

> WDYT?
That's cool!

I was stick to 0.20.5 but now I once have adapted 0.90svn it's working
great.

Just wanted to ask if the upcoming release will have anything to do with
 FOray fonts or not yet ?

If NO I would like to ask maybe those 2 patches will be then useful for
upcoming beta:

fop-0.90-trunk-toUnicodeCMap.patch (attached, also one that is in
bugzilla) - embedding ToUnicode maps (previously did one for 0.20.5, but
this one works nice with SVN head)

fop-0.90-trunk-tspan-pdf-text.patch (attached to some previous mail) -
this one also renders PDF text for tspan without stroking, I adapted
code from 0.20.5. Does work nicely, only have problems when text has
some style="stroke..." those are ignored (not implemented).

Also wish to point to
http://issues.apache.org/bugzilla/show_bug.cgi?id=37877 discussion.. if
it will be possible to count dimensions for viewBox less SVGs like Batik
Squiggle does for upcoming beta ??

Ahh ... one last thing... this message:
"Some content could not fit into a line/page after 50 attempts."

Would it be hard to write what is this "some content actually". Because
it might be hard to guess if you have plenty of embedded images in FO
file :)

Anyway great work guys,

Best wishes,
-- 
Adam Strzelecki |: nanoant.com :|
Index: java/org/apache/fop/fonts/CIDFont.java
===================================================================
--- java/org/apache/fop/fonts/CIDFont.java      (revision 356250)
+++ java/org/apache/fop/fonts/CIDFont.java      (working copy)
@@ -1,12 +1,12 @@
 /*
  * Copyright 1999-2004 The Apache Software Foundation.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -37,6 +37,11 @@
     public Map usedGlyphsIndex = new java.util.HashMap();
     public int usedGlyphsCount = 0;
 
+    /**
+     * usedCharsIndex contains new glyph, original char
+     */
+    public Map usedCharsIndex = new java.util.HashMap();
+
     //private PDFWArray warray = new PDFWArray();
     public int width[] = null;
 
@@ -90,4 +95,8 @@
         return true;
     }
 
+    /**
+     * Returns char[] array .
+     */
+    public abstract char[] getCharsUsed();
 }
\ No newline at end of file
Index: java/org/apache/fop/fonts/MultiByteFont.java
===================================================================
--- java/org/apache/fop/fonts/MultiByteFont.java        (revision 356250)
+++ java/org/apache/fop/fonts/MultiByteFont.java        (working copy)
@@ -1,12 +1,12 @@
 /*
  * Copyright 1999-2004 The Apache Software Foundation.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -125,7 +125,7 @@
      * @see org.apache.fop.fonts.FontDescriptor#isEmbeddable()
      */
     public boolean isEmbeddable() {
-        return !(getEmbedFileName() == null && embedResourceName == null); 
+        return !(getEmbedFileName() == null && embedResourceName == null);
     }
 
     /**
@@ -198,8 +198,8 @@
         for (int i = 0; (i < bfentries.length) && retIdx == 0; i++) {
             if (bfentries[i].getUnicodeStart() <= idx
                     && bfentries[i].getUnicodeEnd() >= idx) {
-                        
-                retIdx = bfentries[i].getGlyphStartIndex() 
+
+                retIdx = bfentries[i].getGlyphStartIndex()
                     + idx
                     - bfentries[i].getUnicodeStart();
             }
@@ -222,6 +222,8 @@
                                new Integer(usedGlyphsCount));
                 usedGlyphsIndex.put(new Integer(usedGlyphsCount),
                                     new Integer(retIdx));
+                usedCharsIndex.put(new Integer(usedGlyphsCount),
+                                    new Integer((int) c));
                 retIdx = usedGlyphsCount;
                 usedGlyphsCount++;
             } else {
@@ -299,5 +301,26 @@
         return usedGlyphs;
     }
 
+    /** The invalid Unicode character, suitable as a return value in methods
+     * that need to return an invalid character. */
+    public static final char INVALID_UNICODE_CHAR = 0xFFFF;
+
+    public char[] getCharsUsed() {
+        if (! isEmbeddable()) {
+            return null;
+        }
+        char[] charArray = new char[usedGlyphsCount];
+        for (int i = 0; i < usedGlyphsCount; i++) {
+            Integer mapValue = (Integer)usedCharsIndex.get(new Integer(i));
+            if(mapValue != null) {
+                char arrayItem = (char) mapValue.intValue();
+                charArray[i] = arrayItem;
+            }
+            else {
+                charArray[i] = INVALID_UNICODE_CHAR;
+            }
+        }
+        return charArray;
+    }
 }
 
Index: java/org/apache/fop/fonts/SingleByteFont.java
===================================================================
--- java/org/apache/fop/fonts/SingleByteFont.java       (revision 356250)
+++ java/org/apache/fop/fonts/SingleByteFont.java       (working copy)
@@ -1,12 +1,12 @@
 /*
  * Copyright 1999-2004 The Apache Software Foundation.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -77,7 +77,7 @@
             return '#';
         }
     }
-    
+
     /**
      * @see org.apache.fop.fonts.Typeface#hasChar(char)
      */
@@ -99,5 +99,8 @@
         this.width[index] = width;
     }
 
+    public char[] getCharsUsed() {
+        return null;
+    }
 }
 
Index: java/org/apache/fop/pdf/PDFCMap.java
===================================================================
--- java/org/apache/fop/pdf/PDFCMap.java        (revision 356250)
+++ java/org/apache/fop/pdf/PDFCMap.java        (working copy)
@@ -1,12 +1,12 @@
 /*
  * Copyright 1999-2004 The Apache Software Foundation.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,9 +15,13 @@
  */
 
 /* $Id$ */
- 
+
 package org.apache.fop.pdf;
 
+// Java
+import java.io.IOException;
+import java.io.OutputStream;
+
 /**
  * Class representing the CMap encodings.
  *
@@ -423,53 +427,91 @@
      * @param p the string buffer to add the pdf data to
      */
     public void fillInPDF(StringBuffer p) {
+        writePreStream(p);
+        writeStreamComments(p);
+        writeCIDInit(p);
+        writeCIDSystemInfo(p);
+        writeVersionTypeName(p);
+        writeCodeSpaceRange(p);
+        writeCIDRange(p);
+        writeBFEntries(p);
+        writeWrapUp(p);
+        writeStreamAfterComments(p);
+        writeUseCMap(p);
+        add(p.toString());
+    }
+
+    protected void writePreStream(StringBuffer p) {
         // p.append("/Type /CMap\n");
         // p.append(sysInfo.toPDFString());
-        // p.append("/CMapName /" + name);
-        // p.append("\n");
+        // p.append("/CMapName /" + name + EOL);
+    }
+
+    protected void writeStreamComments(StringBuffer p) {
         p.append("%!PS-Adobe-3.0 Resource-CMap\n");
         p.append("%%DocumentNeededResources: ProcSet (CIDInit)\n");
         p.append("%%IncludeResource: ProcSet (CIDInit)\n");
         p.append("%%BeginResource: CMap (" + name + ")\n");
         p.append("%%EndComments\n");
+    }
 
+    protected void writeCIDInit(StringBuffer p) {
         p.append("/CIDInit /ProcSet findresource begin\n");
         p.append("12 dict begin\n");
         p.append("begincmap\n");
+    }
 
+    protected void writeCIDSystemInfo(StringBuffer p) {
         p.append("/CIDSystemInfo 3 dict dup begin\n");
         p.append("  /Registry (Adobe) def\n");
         p.append("  /Ordering (Identity) def\n");
         p.append("  /Supplement 0 def\n");
         p.append("end def\n");
+    }
 
+    protected void writeVersionTypeName(StringBuffer p) {
         p.append("/CMapVersion 1 def\n");
         p.append("/CMapType 1 def\n");
         p.append("/CMapName /" + name + " def\n");
+    }
 
+    protected void writeCodeSpaceRange(StringBuffer p) {
         p.append("1 begincodespacerange\n");
         p.append("<0000> <FFFF>\n");
         p.append("endcodespacerange\n");
+    }
+
+    protected void writeCIDRange(StringBuffer p) {
         p.append("1 begincidrange\n");
         p.append("<0000> <FFFF> 0\n");
         p.append("endcidrange\n");
+    }
 
+    protected void writeBFEntries(StringBuffer p) {
         // p.append("1 beginbfrange\n");
         // p.append("<0020> <0100> <0000>\n");
         // p.append("endbfrange\n");
+    }
 
+    protected void writeWrapUp(StringBuffer p) {
         p.append("endcmap\n");
         p.append("CMapName currentdict /CMap defineresource pop\n");
         p.append("end\n");
         p.append("end\n");
+    }
+
+    protected void writeStreamAfterComments(StringBuffer p) {
         p.append("%%EndResource\n");
         p.append("%%EOF\n");
+    }
+
+    protected void writeUseCMap(StringBuffer p) {
         /*
-         * p.append(" /Type /CMap\n/CMapName /" + name);
-         * p.append("\n");
-         * p.append("\n/WMode "); p.append(wMode);
+         * p.append(" /Type /CMap");
+         * p.append("/CMapName /" + name + EOL);
+         * p.append("/WMode " + wMode + EOL);
          * if (base != null) {
-         * p.append("\n/UseCMap ");
+         *     p.append("/UseCMap ");
          * if (base instanceof String) {
          * p.append("/"+base);
          * } else {// base instanceof PDFStream
@@ -479,4 +521,8 @@
          */
     }
 
+    protected int output(OutputStream stream) throws IOException {
+        fillInPDF(new StringBuffer());
+        return super.output(stream);
+    }
 }
Index: java/org/apache/fop/pdf/PDFFactory.java
===================================================================
--- java/org/apache/fop/pdf/PDFFactory.java     (revision 356250)
+++ java/org/apache/fop/pdf/PDFFactory.java     (working copy)
@@ -1,12 +1,12 @@
 /*
  * Copyright 1999-2005 The Apache Software Foundation.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -43,6 +43,8 @@
 import org.apache.fop.fonts.truetype.TTFSubSetFile;
 import org.apache.fop.fonts.type1.PFBData;
 import org.apache.fop.fonts.type1.PFBParser;
+import org.apache.fop.pdf.PDFCMap;
+import org.apache.fop.pdf.PDFToUnicodeCMap;
 
 /**
  * This class provides method to create and register PDF objects.
@@ -918,7 +920,7 @@
      * @return the new PDF outline object
      */
     public PDFOutline makeOutline(PDFOutline parent, String label,
-                                  String destination, float yoffset, 
+                                  String destination, float yoffset,
                                   boolean showSubItems) {
 
         String goToRef = getGoToReference(destination, yoffset);
@@ -1021,6 +1023,12 @@
                                    (PDFCIDFontDescriptor)pdfdesc);
                 getDocument().registerObject(cidFont);
 
+                PDFCMap cmap = new PDFToUnicodeCMap(cidMetrics, "fop-ucs-H",
+                    new PDFCIDSystemInfo("Adobe",
+                        "Identity",
+                        0));
+                getDocument().registerObject(cmap);
+                ((PDFFontType0)font).setCMAP(cmap);
                 ((PDFFontType0)font).setDescendantFonts(cidFont);
             } else {
                 int firstChar = 0;
Index: java/org/apache/fop/pdf/PDFToUnicodeCMap.java
===================================================================
--- java/org/apache/fop/pdf/PDFToUnicodeCMap.java       (revision 0)
+++ java/org/apache/fop/pdf/PDFToUnicodeCMap.java       (revision 0)
@@ -0,0 +1,322 @@
+/*
+ * $Id: PDFToUnicodeCMap.java,v 1.3.2.1 2005/12/01 12:00:00 ono Exp $
+ * ============================================================================
+ *                    The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ *    include the following acknowledgment: "This product includes software
+ *    developed by the Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself, if
+ *    and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "FOP" and "Apache Software Foundation" must not be used to
+ *    endorse or promote products derived from this software without prior
+ *    written permission. For written permission, please contact
+ *    [EMAIL PROTECTED]
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ *    "Apache" appear in their name, without prior written permission of the
+ *    Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ============================================================================
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation and was originally created by
+ * James Tauber <[EMAIL PROTECTED]>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.pdf;
+
+/**
+ * Class representing ToUnicode CMaps.
+ * Here are some documentation resources:
+ * <ul>
+ * <li>PDF Reference, Second Edition, Section 5.6.4, for general information
+ * about CMaps in PDF Files.</li>
+ * <li>PDF Reference, Second Edition, Section 5.9, for specific information
+ * about ToUnicodeCMaps in PDF Files.</li>
+ * <li>
+ * <a 
href="http://partners.adobe.com/asn/developer/pdfs/tn/5411.ToUnicode.pdf";>
+ * Adobe Technical Note #5411, "ToUnicode Mapping File Tutorial"</a>.
+ * </ul>
+ */
+import org.apache.fop.fonts.CIDFont;
+
+public class PDFToUnicodeCMap extends PDFCMap {
+
+    /**
+     * handle to read font
+     */
+    protected CIDFont cidFont;
+
+    /**
+     * Constructor.
+     *
+     * @param name One of the registered names found in Table 5.14 in PDF
+     * Reference, Second Edition.
+     * @param sysInfo The attributes of the character collection of the 
CIDFont.
+     */
+    public PDFToUnicodeCMap(CIDFont cidMetrics, String name, PDFCIDSystemInfo 
sysInfo) {
+        super(name, sysInfo);
+        cidFont = cidMetrics;
+    }
+
+    public void fillInPDF(StringBuffer p) {
+        writeCIDInit(p);
+        writeCIDSystemInfo(p);
+        writeVersionTypeName(p);
+        writeCodeSpaceRange(p);
+        writeBFEntries(p);
+        writeWrapUp(p);
+        add(p.toString());
+    }
+
+    protected void writeCIDSystemInfo(StringBuffer p) {
+        p.append("/CIDSystemInfo\n");
+        p.append("<< /Registry (Adobe)\n");
+        p.append("/Ordering (UCS)\n");
+        p.append("/Supplement 0\n");
+        p.append(">> def\n");
+    }
+
+    protected void writeVersionTypeName(StringBuffer p) {
+        p.append("/CMapName /Adobe-Identity-UCS def\n");
+        p.append("/CMapType 2 def\n");
+    }
+
+    /**
+     * Writes the character mappings for this font.
+     */
+    protected void writeBFEntries(StringBuffer p) {
+        if(cidFont == null) return;
+
+        char[] charArray = cidFont.getCharsUsed();
+
+        if(charArray != null) {
+            writeBFCharEntries(p, charArray);
+            writeBFRangeEntries(p, charArray);
+        }
+    }
+
+    protected void writeBFCharEntries(StringBuffer p, char[] charArray) {
+        int completedEntries = 0;
+        int totalEntries = 0;
+        for (int i = 0; i < charArray.length; i++) {
+            if (! partOfRange(charArray, i)) {
+                totalEntries ++;
+            }
+        }
+        if (totalEntries < 1) {
+            return;
+        }
+        int remainingEntries = totalEntries;
+        /* Limited to 100 entries in each section */
+        int entriesThisSection = Math.min(remainingEntries, 100);
+        int remainingEntriesThisSection = entriesThisSection;
+        p.append(entriesThisSection + " beginbfchar\n");
+        for (int i = 0; i < charArray.length; i++) {
+            if (partOfRange(charArray, i)) {
+                continue;
+            }
+            p.append("<" + padHexString(Integer.toHexString(i), 4)
+                    + "> ");
+            p.append("<" + padHexString(Integer.toHexString(charArray[i]), 4)
+                    + ">\n");
+            /* Compute the statistics. */
+            completedEntries ++;
+            remainingEntries = totalEntries - completedEntries;
+            remainingEntriesThisSection --;
+            if (remainingEntriesThisSection < 1) {
+                if (remainingEntries > 0) {
+                    p.append("endbfchar\n");
+                    entriesThisSection = Math.min(remainingEntries, 100);
+                    remainingEntriesThisSection = entriesThisSection;
+                    p.append(entriesThisSection + " beginbfchar\n");
+                }
+            }
+        }
+        p.append("endbfchar\n");
+    }
+
+    protected void writeBFRangeEntries(StringBuffer p, char[] charArray) {
+        int completedEntries = 0;
+        int totalEntries = 0;
+        for (int i = 0; i < charArray.length; i++) {
+            if (startOfRange(charArray, i)) {
+                totalEntries ++;
+            }
+        }
+        if (totalEntries < 1) {
+            return;
+        }
+        int remainingEntries = totalEntries;
+        int entriesThisSection = Math.min(remainingEntries, 100);
+        int remainingEntriesThisSection = entriesThisSection;
+        p.append(entriesThisSection + " beginbfrange\n");
+        for (int i = 0; i < charArray.length; i++) {
+            if (! startOfRange(charArray, i)) {
+                continue;
+            }
+            p.append("<"
+                    + padHexString(Integer.toHexString(i), 4)
+                    + "> ");
+            p.append("<"
+                    + padHexString(Integer.toHexString
+                            (endOfRange(charArray, i)), 4)
+                    + "> ");
+            p.append("<"
+                    + padHexString(Integer.toHexString(charArray[i]), 4)
+                    + ">\n");
+            /* Compute the statistics. */
+            completedEntries ++;
+            remainingEntries = totalEntries - completedEntries;
+            if (remainingEntriesThisSection < 1) {
+                if (remainingEntries > 0) {
+                    p.append("endbfrange\n");
+                    entriesThisSection = Math.min(remainingEntries, 100);
+                    remainingEntriesThisSection = entriesThisSection;
+                    p.append(entriesThisSection + " beginbfrange\n");
+                }
+            }
+        }
+        p.append("endbfrange\n");
+    }
+
+    /**
+     * Find the end of the current range.
+     * @param charArray The array which is being tested.
+     * @param startOfRange The index to the array element that is the start of
+     * the range.
+     * @return The index to the element that is the end of the range.
+     */
+    private int endOfRange(char[] charArray, int startOfRange) {
+        int endOfRange = -1;
+        for (int i = startOfRange; i < charArray.length - 1 && endOfRange < 0;
+                i++) {
+            if (! sameRangeEntryAsNext(charArray, i)) {
+                endOfRange = i;
+            }
+        }
+        return endOfRange;
+    }
+
+    /**
+     * Determine whether this array element should be part of a bfchar entry or
+     * a bfrange entry.
+     * @param charArray The array to be tested.
+     * @param arrayIndex The index to the array element to be tested.
+     * @return True if this array element should be included in a range.
+     */
+    private boolean partOfRange(char[] charArray, int arrayIndex) {
+        if (charArray.length < 2) {
+            return false;
+        }
+        if (arrayIndex == 0) {
+            return sameRangeEntryAsNext(charArray, 0);
+        }
+        if (arrayIndex == charArray.length - 1) {
+            return sameRangeEntryAsNext(charArray, arrayIndex - 1);
+        }
+        if (sameRangeEntryAsNext(charArray, arrayIndex - 1)) {
+            return true;
+        }
+        if (sameRangeEntryAsNext(charArray, arrayIndex)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Determine whether two bytes can be written in the same bfrange entry.
+     * @param charArray The array to be tested.
+     * @param firstItem The first of the two items in the array to be tested.
+     * The second item is firstItem + 1.
+     * @return True if both 1) the next item in the array is sequential with
+     * this one, and 2) the first byte of the character in the first position
+     * is equal to the first byte of the character in the second position.
+     */
+    private boolean sameRangeEntryAsNext(char[] charArray, int firstItem) {
+        if (charArray[firstItem] + 1 != charArray[firstItem + 1]) {
+            return false;
+        }
+        if (firstItem / 256 != (firstItem + 1) / 256) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Determine whether this array element should be the start of a bfrange
+     * entry.
+     * @param charArray The array to be tested.
+     * @param arrayIndex The index to the array element to be tested.
+     * @return True if this array element is the beginning of a range.
+     */
+    private boolean startOfRange(char[] charArray, int arrayIndex) {
+        // Can't be the start of a range if not part of a range.
+        if (! partOfRange(charArray, arrayIndex)) {
+            return false;
+        }
+        // If first element in the array, must be start of a range
+        if (arrayIndex == 0) {
+            return true;
+        }
+        // If last element in the array, cannot be start of a range
+        if (arrayIndex == charArray.length - 1) {
+            return false;
+        }
+        /*
+         * If part of same range as the previous element is, cannot be start
+         * of range.
+         */
+        if (sameRangeEntryAsNext(charArray, arrayIndex - 1)) {
+            return false;
+        }
+        // Otherwise, this is start of a range.
+        return true;
+    }
+
+    /**
+     * Prepends the input string with a sufficient number of "0" characters to
+     * get the returned string to be numChars length.
+     * @param input The input string.
+     * @param numChars The minimum characters in the output string.
+     * @return The padded string.
+     */
+    public static String padHexString(String input, int numChars) {
+        int length = input.length();
+        if (length >= numChars) {
+            return input;
+        }
+        StringBuffer returnString = new StringBuffer();
+        for (int i = 1; i <= numChars - length; i++) {
+            returnString.append("0");
+        }
+        returnString.append(input);
+        return returnString.toString();
+    }
+
+}
Index: PDFTextElementBridge.java
===================================================================
--- PDFTextElementBridge.java   (revision 356302)
+++ PDFTextElementBridge.java   (working copy)
@@ -1,12 +1,12 @@
 /*
  * Copyright 1999-2004 The Apache Software Foundation.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -56,7 +56,7 @@
      */
     public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) {
         GraphicsNode node = super.createGraphicsNode(ctx, e);
-        if (node != null && isSimple(ctx, e, node)) {
+        if (node != null /*&& isSimple(ctx, e, node)*/) {
             ((TextNode)node).setTextPainter(getTextPainter());
         }
         return node;
@@ -80,6 +80,7 @@
      * @return true if this text is simple of false if it cannot be
      *         easily rendered using normal drawString on the PDFGraphics2D
      */
+    /*
     private boolean isSimple(BridgeContext ctx, Element element, GraphicsNode 
node) {
         // Font size, in user space units.
         float fs = TextUtilities.convertFontSize(element).floatValue();
@@ -111,12 +112,13 @@
             case Node.CDATA_SECTION_NODE:
             }
         }
-
+    */
         /*if (CSSUtilities.convertFilter(element, node, ctx) != null) {
             return false;
         }*/
-
+    /*
         return true;
     }
+    */
 }
 
Index: PDFTextPainter.java
===================================================================
--- PDFTextPainter.java (revision 356302)
+++ PDFTextPainter.java (working copy)
@@ -1,12 +1,12 @@
 /*
  * Copyright 1999-2004 The Apache Software Foundation.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -82,84 +82,109 @@
      * specified Graphics2D and context and font context.
      * @param node the TextNode to paint
      * @param g2d the Graphics2D to use
+     * @param context the rendering context.
      */
     public void paint(TextNode node, Graphics2D g2d) {
+        // System.out.println("PDFText paint");
         String txt = node.getText();
         Point2D loc = node.getLocation();
-        
+        /*
+
         AttributedCharacterIterator aci =
-          node.getAttributedCharacterIterator();
-        // reset position to start of char iterator
+            node.getAttributedCharacterIterator();
         if (aci.getBeginIndex() == aci.getEndIndex()) {
             return;
         }
+        // reset position to start of char iterator
         char ch = aci.first();
         if (ch == AttributedCharacterIterator.DONE) {
             return;
         }
-        TextNode.Anchor anchor;
-        anchor = (TextNode.Anchor) aci.getAttribute(
-                      
GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE);
+        */
+        TextNode.Anchor anchor =
+            
(TextNode.Anchor)node.getAttributedCharacterIterator().getAttribute(GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE);
+        if (anchor != null) {
+        }
+        /*
+        System.out.println("-----"+txt);
+        printAttrs(node.getAttributedCharacterIterator());
+        */
+        paintTextRuns(node.getTextRuns(), g2d, loc);
 
-        List gvtFonts;
-        gvtFonts = (List) aci.getAttribute(
-            GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES);
+    }
 
+
+    protected void paintTextRuns(List textRuns, Graphics2D g2d, Point2D loc) {
+        Point2D currentloc = loc;
+        Iterator i = textRuns.iterator();
+        while (i.hasNext()) {
+            StrokingTextPainter.TextRun run =
+                    (StrokingTextPainter.TextRun)i.next();
+            currentloc = paintTextRun(run, g2d, currentloc);
+        }
+    }
+
+
+    protected Point2D paintTextRun(StrokingTextPainter.TextRun run, Graphics2D 
g2d, Point2D loc) {
+        AttributedCharacterIterator aci = run.getACI();
+        return paintACI(aci, g2d, loc);
+    }
+
+
+    protected String getText(AttributedCharacterIterator aci) {
+        StringBuffer sb = new 
StringBuffer(aci.getEndIndex()-aci.getBeginIndex());
+        for (char c = aci.first(); c != AttributedCharacterIterator.DONE; c = 
aci.next()) {
+            sb.append(c);
+        }
+        return sb.toString();
+    }
+
+
+    protected Point2D paintACI(AttributedCharacterIterator aci, Graphics2D 
g2d, Point2D loc) {
+        aci.first();
+
+        TextNode.Anchor anchor =
+            
(TextNode.Anchor)aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE);
+
+        //Adjust position of span
+        Float xpos =
+            
(Float)aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.X);
+        Float ypos =
+            
(Float)aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.Y);
+        Float dxpos =
+            
(Float)aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.DX);
+        Float dypos =
+            
(Float)aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.DY);
+        if (xpos != null) loc.setLocation(xpos.doubleValue(), loc.getY());
+        if (ypos != null) loc.setLocation(loc.getX(), ypos.doubleValue());
+        if (dxpos != null) loc.setLocation(loc.getX()+dxpos.doubleValue(), 
loc.getY());
+        if (dypos != null) loc.setLocation(loc.getX(), 
loc.getY()+dypos.doubleValue());
+
+        //Set up font
+        List gvtFonts =
+            
(List)aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES);
         TextPaintInfo tpi = (TextPaintInfo) aci.getAttribute(
             GVTAttributedCharacterIterator.TextAttribute.PAINT_INFO);
-        
-        if (tpi == null) {
-            return;
-        }        
-        
-        Paint forg = tpi.fillPaint;
-        Paint strokePaint = tpi.strokePaint;
-        Float size = (Float) aci.getAttribute(TextAttribute.SIZE);
+        Paint forg = tpi.fillPaint;;
+        Float size = (Float)aci.getAttribute(TextAttribute.SIZE);
         if (size == null) {
-            return;
+            return loc;
         }
         Stroke stroke = tpi.strokeStroke;
-        /*
-        Float xpos = (Float) aci.getAttribute(
-                       GVTAttributedCharacterIterator.TextAttribute.X);
-        Float ypos = (Float) aci.getAttribute(
-                       GVTAttributedCharacterIterator.TextAttribute.Y);
-        */
 
-        Float posture = (Float) aci.getAttribute(TextAttribute.POSTURE);
-        Float taWeight = (Float) aci.getAttribute(TextAttribute.WEIGHT);
+        Float posture = (Float)aci.getAttribute(TextAttribute.POSTURE);
+        Float taWeight = (Float)aci.getAttribute(TextAttribute.WEIGHT);
 
-        boolean useStrokePainter = false;
-
         if (forg instanceof Color) {
-            Color col = (Color) forg;
-            if (col.getAlpha() != 255) {
-                useStrokePainter = true;
-            }
-            g2d.setColor(col);
+            g2d.setColor((Color)forg);
         }
         g2d.setPaint(forg);
         g2d.setStroke(stroke);
 
-        if (strokePaint != null) {
-            // need to draw using AttributedCharacterIterator
-            useStrokePainter = true;
-        }
-
-        if (hasUnsupportedAttributes(aci)) {
-            useStrokePainter = true;
-        }
-
-        // text contains unsupported information
-        if (useStrokePainter) {
-            PROXY_PAINTER.paint(node, g2d);
-            return;
-        }
-
         String style = ((posture != null) && (posture.floatValue() > 0.0))
                        ? "italic" : "normal";
         int weight = ((taWeight != null)
-                       &&  (taWeight.floatValue() > 1.0)) ? Font.BOLD
+                       &&  (taWeight.floatValue() > 1.0)) ? java.awt.Font.BOLD
                        : Font.NORMAL;
 
         Font fontState = null;
@@ -170,10 +195,6 @@
             Iterator i = gvtFonts.iterator();
             while (i.hasNext()) {
                 GVTFontFamily fam = (GVTFontFamily) i.next();
-                if (fam instanceof SVGFontFamily) {
-                    PROXY_PAINTER.paint(node, g2d);
-                    return;
-                }
                 fontFamily = fam.getFamilyName();
                 if (fi.hasFont(fontFamily, style, weight)) {
                     String fname = fontInfo.fontLookup(fontFamily, style,
@@ -216,51 +237,24 @@
 
         g2d.setFont(font);
 
+        //Get text and paint
+        String txt = getText(aci);
         float advance = getStringWidth(txt, fontState);
         float tx = 0;
         if (anchor != null) {
             switch (anchor.getType()) {
-                case TextNode.Anchor.ANCHOR_MIDDLE:
-                    tx = -advance / 2;
-                    break;
-                case TextNode.Anchor.ANCHOR_END:
-                    tx = -advance;
+            case TextNode.Anchor.ANCHOR_MIDDLE:
+                tx = -advance / 2;
+                break;
+            case TextNode.Anchor.ANCHOR_END:
+                tx = -advance;
             }
         }
-        g2d.drawString(txt, (float)(loc.getX() + tx), (float)(loc.getY()));
+        g2d.drawString(txt, (float)(loc.getX() + tx), (float)loc.getY());
+        loc.setLocation(loc.getX()+(double)advance, loc.getY());
+        return loc;
     }
 
-    private boolean hasUnsupportedAttributes(AttributedCharacterIterator aci) {
-        boolean hasunsupported = false;
-        Object letSpace = aci.getAttribute(
-                            
GVTAttributedCharacterIterator.TextAttribute.LETTER_SPACING);
-        if (letSpace != null) {
-            hasunsupported = true;
-        }
-
-        Object wordSpace = aci.getAttribute(
-                             
GVTAttributedCharacterIterator.TextAttribute.WORD_SPACING);
-        if (wordSpace != null) {
-            hasunsupported = true;
-        }
-
-        AttributedCharacterIterator.Attribute key;
-        key = GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE;
-        Object writeMod = aci.getAttribute(key);
-        if 
(!GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE_LTR.equals(
-                  writeMod)) {
-            hasunsupported = true;
-        }
-
-        Object vertOr = aci.getAttribute(
-                          
GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION);
-        if 
(GVTAttributedCharacterIterator.TextAttribute.ORIENTATION_ANGLE.equals(
-                  vertOr)) {
-            hasunsupported = true;
-        }
-        return hasunsupported;
-    }
-
     private float getStringWidth(String str, Font fontState) {
         float wordWidth = 0;
         float whitespaceWidth = fontState.getWidth(fontState.mapChar(' '));
@@ -281,120 +275,61 @@
         return wordWidth / 1000f;
     }
 
-    /**
-     * Get the outline shape of the text characters.
-     * This uses the StrokingTextPainter to get the outline
-     * shape since in theory it should be the same.
-     *
-     * @param node the text node
-     * @return the outline shape of the text characters
-     */
-    public Shape getOutline(TextNode node) {
-        return PROXY_PAINTER.getOutline(node);
-    }
-
-    /**
-     * Get the bounds.
-     * This uses the StrokingTextPainter to get the bounds
-     * since in theory it should be the same.
-     *
-     * @param node the text node
-     * @return the bounds of the text
-     */
-    public Rectangle2D getBounds2D(TextNode node) {
-        return PROXY_PAINTER.getBounds2D(node);
-    }
-
-    /**
-     * Get the geometry bounds.
-     * This uses the StrokingTextPainter to get the bounds
-     * since in theory it should be the same.
-     * @param node the text node
-     * @return the bounds of the text
-     */
-    public Rectangle2D getGeometryBounds(TextNode node) {
-        return PROXY_PAINTER.getGeometryBounds(node);
-    }
-
-    // Methods that have no purpose for PDF
-
-    /**
-     * Get the mark.
-     * This does nothing since the output is pdf and not interactive.
-     * @param node the text node
-     * @param pos the position
-     * @param all select all
-     * @return null
-     */
     public Mark getMark(TextNode node, int pos, boolean all) {
+        System.out.println("PDFText getMark");
         return null;
     }
 
-    /**
-     * Select at.
-     * This does nothing since the output is pdf and not interactive.
-     * @param x the x position
-     * @param y the y position
-     * @param node the text node
-     * @return null
-     */
-    public Mark selectAt(double x, double y, TextNode node) {
+    public Mark selectAt(double x, double y,
+                         TextNode node) {
+        System.out.println("PDFText selectAt");
         return null;
     }
 
-    /**
-     * Select to.
-     * This does nothing since the output is pdf and not interactive.
-     * @param x the x position
-     * @param y the y position
-     * @param beginMark the start mark
-     * @return null
-     */
     public Mark selectTo(double x, double y, Mark beginMark) {
+        System.out.println("PDFText selectTo");
         return null;
     }
 
-    /**
-     * Selec first.
-     * This does nothing since the output is pdf and not interactive.
-     * @param node the text node
-     * @return null
-     */
+    public Mark selectAll(double x, double y,
+                          TextNode node) {
+        System.out.println("PDFText selectAll");
+        return null;
+    }
+
     public Mark selectFirst(TextNode node) {
+        System.out.println("PDFText selectFirst");
         return null;
     }
 
-    /**
-     * Select last.
-     * This does nothing since the output is pdf and not interactive.
-     * @param node the text node
-     * @return null
-     */
     public Mark selectLast(TextNode node) {
+        System.out.println("PDFText selectLast");
         return null;
     }
 
-    /**
-     * Get selected.
-     * This does nothing since the output is pdf and not interactive.
-     * @param start the start mark
-     * @param finish the finish mark
-     * @return null
-     */
-    public int[] getSelected(Mark start, Mark finish) {
+    public int[] getSelected(Mark start,
+                             Mark finish) {
+        System.out.println("PDFText getSelected");
         return null;
     }
 
-    /**
-     * Get the highlighted shape.
-     * This does nothing since the output is pdf and not interactive.
-     * @param beginMark the start mark
-     * @param endMark the end mark
-     * @return null
-     */
     public Shape getHighlightShape(Mark beginMark, Mark endMark) {
+        System.out.println("PDFText getHighlightShape");
         return null;
     }
 
+    public Rectangle2D getBounds2D(TextNode node) {
+        return PROXY_PAINTER.getBounds2D(node);
+    }
+
+    public Rectangle2D getGeometryBounds(TextNode node) {
+        return PROXY_PAINTER.getGeometryBounds(node);
+    }
+
+    public Shape getOutline(TextNode node) {
+        return PROXY_PAINTER.getOutline(node);
+    }
+
+
 }
 

Reply via email to