You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by vh...@apache.org on 2013/07/29 23:45:23 UTC

svn commit: r1508208 [7/10] - in /xmlgraphics/fop/branches/Temp_FopFontsForSVG: ./ lib/ src/codegen/fonts/ src/java/org/apache/fop/afp/ src/java/org/apache/fop/afp/fonts/ src/java/org/apache/fop/afp/goca/ src/java/org/apache/fop/afp/svg/ src/java/org/a...

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/MultiByteFont.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/MultiByteFont.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/MultiByteFont.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/MultiByteFont.java Mon Jul 29 21:45:20 2013
@@ -19,6 +19,7 @@
 
 package org.apache.fop.fonts;
 
+import java.awt.Rectangle;
 import java.nio.CharBuffer;
 import java.nio.IntBuffer;
 import java.util.BitSet;
@@ -67,6 +68,9 @@ public class MultiByteFont extends CIDFo
     private int firstUnmapped;
     private int lastUnmapped;
 
+    /** Contains the character bounding boxes for all characters in the font */
+    protected Rectangle[] boundingBoxes;
+
     /**
      * Default constructor
      */
@@ -170,6 +174,12 @@ public class MultiByteFont extends CIDFo
         return arr;
     }
 
+    public Rectangle getBoundingBox(int glyphIndex, int size) {
+        int index = isEmbeddable() ? cidSet.getOriginalGlyphIndex(glyphIndex) : glyphIndex;
+        Rectangle bbox = boundingBoxes[index];
+        return new Rectangle(bbox.x * size, bbox.y * size, bbox.width * size, bbox.height * size);
+    }
+
     /**
      * Returns the glyph index for a Unicode character. The method returns 0 if there's no
      * such glyph in the character map.
@@ -366,6 +376,14 @@ public class MultiByteFont extends CIDFo
     }
 
     /**
+     * Sets the bounding boxes array.
+     * @param boundingBoxes array of bounding boxes.
+     */
+    public void setBBoxArray(Rectangle[] boundingBoxes) {
+        this.boundingBoxes = boundingBoxes;
+    }
+
+    /**
      * Returns a Map of used Glyphs.
      * @return Map Map of used Glyphs
      */

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/SingleByteFont.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/SingleByteFont.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/SingleByteFont.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/SingleByteFont.java Mon Jul 29 21:45:20 2013
@@ -19,6 +19,7 @@
 
 package org.apache.fop.fonts;
 
+import java.awt.Rectangle;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -47,6 +48,8 @@ public class SingleByteFont extends Cust
 
     private int[] width = null;
 
+    private Rectangle[] boundingBoxes;
+
     private Map<Character, UnencodedCharacter> unencodedCharacters;
     private List<SimpleSingleByteEncoding> additionalEncodings;
     private Map<Character, Character> alternativeCodes;
@@ -111,6 +114,24 @@ public class SingleByteFont extends Cust
         return arr;
     }
 
+    public Rectangle getBoundingBox(int glyphIndex, int size) {
+        Rectangle bbox = null;
+        if (glyphIndex < 256) {
+            int idx = glyphIndex - getFirstChar();
+            if (idx >= 0 && idx < boundingBoxes.length) {
+                bbox =  boundingBoxes[idx];
+            }
+        } else if (this.additionalEncodings != null) {
+            int encodingIndex = (glyphIndex / 256) - 1;
+            SimpleSingleByteEncoding encoding = getAdditionalEncoding(encodingIndex);
+            int codePoint = glyphIndex % 256;
+            NamedCharacter nc = encoding.getCharacterForIndex(codePoint);
+            UnencodedCharacter uc = this.unencodedCharacters.get(Character.valueOf(nc.getSingleUnicodeValue()));
+            bbox = uc.getBBox();
+        }
+        return bbox == null ? null : new Rectangle(bbox.x * size, bbox.y * size, bbox.width * size, bbox.height * size);
+    }
+
     /**
      * Lookup a character using its alternative names. If found, cache it so we
      * can speed up lookups.
@@ -292,17 +313,24 @@ public class SingleByteFont extends Cust
         this.width[index - getFirstChar()] = w;
     }
 
+    public void setBoundingBox(int index, Rectangle bbox) {
+        if (this.boundingBoxes == null) {
+            this.boundingBoxes = new Rectangle[getLastChar() - getFirstChar() + 1];
+        }
+        this.boundingBoxes[index - getFirstChar()] = bbox;
+    }
+
     /**
      * Adds an unencoded character (one that is not supported by the primary encoding).
      * @param ch the named character
      * @param width the width of the character
      */
-    public void addUnencodedCharacter(NamedCharacter ch, int width) {
+    public void addUnencodedCharacter(NamedCharacter ch, int width, Rectangle bbox) {
         if (this.unencodedCharacters == null) {
             this.unencodedCharacters = new HashMap<Character, UnencodedCharacter>();
         }
         if (ch.hasSingleUnicodeValue()) {
-            UnencodedCharacter uc = new UnencodedCharacter(ch, width);
+            UnencodedCharacter uc = new UnencodedCharacter(ch, width, bbox);
             this.unencodedCharacters.put(Character.valueOf(ch.getSingleUnicodeValue()), uc);
         } else {
             //Cannot deal with unicode sequences, so ignore this character
@@ -381,10 +409,12 @@ public class SingleByteFont extends Cust
 
         private final NamedCharacter character;
         private final int width;
+        private final Rectangle bbox;
 
-        public UnencodedCharacter(NamedCharacter character, int width) {
+        public UnencodedCharacter(NamedCharacter character, int width, Rectangle bbox) {
             this.character = character;
             this.width = width;
+            this.bbox = bbox;
         }
 
         public NamedCharacter getCharacter() {
@@ -395,6 +425,10 @@ public class SingleByteFont extends Cust
             return this.width;
         }
 
+        public Rectangle getBBox() {
+            return bbox;
+        }
+
         /** {@inheritDoc} */
         @Override
         public String toString() {

Added: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/TextFragment.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/TextFragment.java?rev=1508208&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/TextFragment.java (added)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/TextFragment.java Mon Jul 29 21:45:20 2013
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fonts;
+
+public interface TextFragment {
+
+    String getScript();
+
+    String getLanguage();
+
+    char charAt(int index);
+
+    CharSequence subSequence(int startIndex, int endIndex);
+}

Propchange: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/TextFragment.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/TextFragment.java
------------------------------------------------------------------------------
    svn:keywords = Revision Id

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/truetype/TTFFile.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/truetype/TTFFile.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/truetype/TTFFile.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/truetype/TTFFile.java Mon Jul 29 21:45:20 2013
@@ -19,6 +19,7 @@
 
 package org.apache.fop.fonts.truetype;
 
+import java.awt.Rectangle;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -199,6 +200,8 @@ public class TTFFile {
     private int os2CapHeight = 0;
     private int underlinePosition = 0;
     private int underlineThickness = 0;
+    private int strikeoutPosition;
+    private int strikeoutThickness;
     private int xHeight = 0;
     private int os2xHeight = 0;
     //Effective ascender/descender
@@ -976,10 +979,22 @@ public class TTFFile {
         for (int i = 0; i < wx.length; i++) {
             wx[i] = convertTTFUnit2PDFUnit(mtxTab[i].getWx());
         }
-
         return wx;
     }
 
+    public Rectangle[] getBoundingBoxes() {
+        Rectangle[] boundingBoxes = new Rectangle[mtxTab.length];
+        for (int i = 0; i < boundingBoxes.length; i++) {
+            int[] boundingBox = mtxTab[i].getBoundingBox();
+            boundingBoxes[i] = new Rectangle(
+                    convertTTFUnit2PDFUnit(boundingBox[0]),
+                    convertTTFUnit2PDFUnit(boundingBox[1]),
+                    convertTTFUnit2PDFUnit(boundingBox[2] - boundingBox[0]),
+                    convertTTFUnit2PDFUnit(boundingBox[3] - boundingBox[1]));
+        }
+        return boundingBoxes;
+    }
+
     /**
      * Returns an array (xMin, yMin, xMax, yMax) for a glyph.
      *
@@ -1020,6 +1035,22 @@ public class TTFFile {
         return ansiKerningTab;
     }
 
+    public int getUnderlinePosition() {
+        return convertTTFUnit2PDFUnit(underlinePosition);
+    }
+
+    public int getUnderlineThickness() {
+        return convertTTFUnit2PDFUnit(underlineThickness);
+    }
+
+    public int getStrikeoutPosition() {
+        return convertTTFUnit2PDFUnit(strikeoutPosition);
+    }
+
+    public int getStrikeoutThickness() {
+        return convertTTFUnit2PDFUnit(strikeoutThickness);
+    }
+
     /**
      * Indicates if the font may be embedded.
      * @return boolean True if it may be embedded
@@ -1301,7 +1332,10 @@ public class TTFFile {
             } else {
                 isEmbeddable = true;
             }
-            fontFile.skip(11 * 2);
+            fontFile.skip(8 * 2);
+            strikeoutThickness = fontFile.readTTFShort();
+            strikeoutPosition = fontFile.readTTFShort();
+            fontFile.skip(2);
             fontFile.skip(10); //panose array
             fontFile.skip(4 * 4); //unicode ranges
             fontFile.skip(4);

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java Mon Jul 29 21:45:20 2013
@@ -19,6 +19,7 @@
 
 package org.apache.fop.fonts.truetype;
 
+import java.awt.Rectangle;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
@@ -144,6 +145,10 @@ public class TTFFontLoader extends FontL
         returnFont.setAscender(ttf.getLowerCaseAscent());
         returnFont.setDescender(ttf.getLowerCaseDescent());
         returnFont.setFontBBox(ttf.getFontBBox());
+        returnFont.setUnderlinePosition(ttf.getUnderlinePosition() - ttf.getUnderlineThickness() / 2);
+        returnFont.setUnderlineThickness(ttf.getUnderlineThickness());
+        returnFont.setStrikeoutPosition(ttf.getStrikeoutPosition() - ttf.getStrikeoutThickness() / 2);
+        returnFont.setStrikeoutThickness(ttf.getStrikeoutThickness());
         returnFont.setFlags(ttf.getFlags());
         returnFont.setStemV(Integer.parseInt(ttf.getStemV())); //not used for TTF
         returnFont.setItalicAngle(Integer.parseInt(ttf.getItalicAngle()));
@@ -152,15 +157,15 @@ public class TTFFontLoader extends FontL
         returnFont.setEmbeddingMode(this.embeddingMode);
         if (isCid) {
             multiFont.setCIDType(CIDFontType.CIDTYPE2);
-            int[] wx = ttf.getWidths();
-            multiFont.setWidthArray(wx);
+            multiFont.setWidthArray(ttf.getWidths());
+            multiFont.setBBoxArray(ttf.getBoundingBoxes());
         } else {
             singleFont.setFontType(FontType.TRUETYPE);
             singleFont.setEncoding(ttf.getCharSetName());
             returnFont.setFirstChar(ttf.getFirstChar());
             returnFont.setLastChar(ttf.getLastChar());
             singleFont.setTrueTypePostScriptVersion(ttf.getPostScriptVersion());
-            copyWidthsSingleByte(ttf);
+            copyGlyphMetricsSingleByte(ttf);
         }
         returnFont.setCMap(getCMap(ttf));
 
@@ -186,12 +191,15 @@ public class TTFFontLoader extends FontL
         return ttf.getCMaps().toArray(array);
     }
 
-    private void copyWidthsSingleByte(TTFFile ttf) {
+    private void copyGlyphMetricsSingleByte(TTFFile ttf) {
         int[] wx = ttf.getWidths();
+        Rectangle[] bboxes = ttf.getBoundingBoxes();
         for (int i = singleFont.getFirstChar(); i <= singleFont.getLastChar(); i++) {
             singleFont.setWidth(i, ttf.getCharWidth(i));
+            int[] bbox = ttf.getBBox(i);
+            singleFont.setBoundingBox(i,
+                    new Rectangle(bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1]));
         }
-
         for (CMapSegment segment : ttf.getCMaps()) {
             if (segment.getUnicodeStart() < 0xFFFE) {
                 for (char u = (char)segment.getUnicodeStart(); u <= segment.getUnicodeEnd(); u++) {
@@ -205,7 +213,7 @@ public class TTFFontLoader extends FontL
                         if (glyphName.length() > 0) {
                             String unicode = Character.toString(u);
                             NamedCharacter nc = new NamedCharacter(glyphName, unicode);
-                            singleFont.addUnencodedCharacter(nc, wx[glyphIndex]);
+                            singleFont.addUnencodedCharacter(nc, wx[glyphIndex], bboxes[glyphIndex]);
                         }
                     }
                 }

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/type1/AFMCharMetrics.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/type1/AFMCharMetrics.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/type1/AFMCharMetrics.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/type1/AFMCharMetrics.java Mon Jul 29 21:45:20 2013
@@ -19,7 +19,7 @@
 
 package org.apache.fop.fonts.type1;
 
-import java.awt.geom.RectangularShape;
+import java.awt.Rectangle;
 
 import org.apache.fop.fonts.NamedCharacter;
 
@@ -33,7 +33,7 @@ public class AFMCharMetrics {
     private NamedCharacter character;
     private double widthX;
     private double widthY;
-    private RectangularShape bBox;
+    private Rectangle bBox;
 
     /**
      * Returns the character code.
@@ -137,7 +137,7 @@ public class AFMCharMetrics {
      * Returns the character's bounding box.
      * @return the bounding box (or null if it isn't available)
      */
-    public RectangularShape getBBox() {
+    public Rectangle getBBox() {
         return bBox;
     }
 
@@ -145,7 +145,7 @@ public class AFMCharMetrics {
      * Sets the character's bounding box.
      * @param box the bounding box
      */
-    public void setBBox(RectangularShape box) {
+    public void setBBox(Rectangle box) {
         bBox = box;
     }
 

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/fonts/type1/Type1FontLoader.java Mon Jul 29 21:45:20 2013
@@ -203,12 +203,16 @@ public class Type1FontLoader extends Fon
         for (AFMCharMetrics metrics : charMetrics) {
             String charName = metrics.getCharName();
             if (charName != null && !glyphNames.contains(charName)) {
-                singleFont.addUnencodedCharacter(metrics.getCharacter(),
-                        (int)Math.round(metrics.getWidthX()));
+                addUnencodedCharacter(singleFont, metrics);
             }
         }
     }
 
+    private static void addUnencodedCharacter(SingleByteFont font, AFMCharMetrics metrics) {
+        font.addUnencodedCharacter(metrics.getCharacter(),
+                (int) Math.round(metrics.getWidthX()), metrics.getBBox());
+    }
+
     /**
      * Adds characters not encoded in the font's primary encoding. This method is used when
      * the primary encoding is built based on the character codes in the AFM rather than
@@ -220,8 +224,7 @@ public class Type1FontLoader extends Fon
         for (int i = 0, c = afm.getCharCount(); i < c; i++) {
             AFMCharMetrics metrics = (AFMCharMetrics)charMetrics.get(i);
             if (!metrics.hasCharCode() && metrics.getCharacter() != null) {
-                singleFont.addUnencodedCharacter(metrics.getCharacter(),
-                        (int)Math.round(metrics.getWidthX()));
+                addUnencodedCharacter(singleFont, metrics);
             }
         }
     }
@@ -267,7 +270,10 @@ public class Type1FontLoader extends Fon
             } else {
                 returnFont.setStemV(80); // Arbitrary value
             }
-            returnFont.setItalicAngle((int) afm.getWritingDirectionMetrics(0).getItalicAngle());
+            AFMWritingDirectionMetrics metrics = afm.getWritingDirectionMetrics(0);
+            returnFont.setItalicAngle((int) metrics.getItalicAngle());
+            returnFont.setUnderlinePosition(metrics.getUnderlinePosition().intValue());
+            returnFont.setUnderlineThickness(metrics.getUnderlineThickness().intValue());
         } else {
             returnFont.setFontBBox(pfm.getFontBBox());
             returnFont.setStemV(pfm.getStemV());
@@ -369,6 +375,7 @@ public class Type1FontLoader extends Fon
             for (AFMCharMetrics chm : afm.getCharMetrics()) {
                 if (chm.hasCharCode()) {
                     singleFont.setWidth(chm.getCharCode(), (int) Math.round(chm.getWidthX()));
+                    singleFont.setBoundingBox(chm.getCharCode(), chm.getBBox());
                 }
             }
             if (useKerning) {

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java Mon Jul 29 21:45:20 2013
@@ -33,6 +33,7 @@ import org.apache.batik.bridge.GVTBuilde
 import org.apache.batik.bridge.UserAgent;
 import org.apache.batik.dom.svg.SVGDOMImplementation;
 import org.apache.batik.gvt.GraphicsNode;
+import org.apache.batik.gvt.font.DefaultFontFamilyResolver;
 
 import org.apache.xmlgraphics.image.GraphicsConstants;
 import org.apache.xmlgraphics.image.loader.Image;
@@ -123,10 +124,8 @@ public class ImageConverterSVG2G2D exten
      * @return the newly created user agent
      */
     protected SimpleSVGUserAgent createBatikUserAgent(float pxToMillimeter) {
-        return new SimpleSVGUserAgent(
-                pxToMillimeter,
-                new AffineTransform()) {
-
+        return new SimpleSVGUserAgent(pxToMillimeter, new AffineTransform(),
+                DefaultFontFamilyResolver.SINGLETON) {
             /** {@inheritDoc} */
             public void displayMessage(String message) {
                 //TODO Refine and pipe through to caller

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java Mon Jul 29 21:45:20 2013
@@ -38,6 +38,7 @@ import org.apache.batik.bridge.UnitProce
 import org.apache.batik.bridge.UserAgent;
 import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
 import org.apache.batik.dom.svg.SVGOMDocument;
+import org.apache.batik.gvt.font.DefaultFontFamilyResolver;
 
 import org.apache.xmlgraphics.image.loader.ImageContext;
 import org.apache.xmlgraphics.image.loader.ImageInfo;
@@ -162,7 +163,7 @@ public class PreloaderSVG extends Abstra
             Element e = doc.getRootElement();
             float pxUnitToMillimeter = UnitConv.IN2MM / context.getSourceResolution();
             UserAgent userAg = new SimpleSVGUserAgent(pxUnitToMillimeter,
-                        new AffineTransform()) {
+                        new AffineTransform(), DefaultFontFamilyResolver.SINGLETON) {
 
                 /** {@inheritDoc} */
                 public void displayMessage(String message) {

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java Mon Jul 29 21:45:20 2013
@@ -30,12 +30,11 @@ import org.apache.commons.logging.LogFac
 
 import org.apache.fop.area.Trait;
 import org.apache.fop.area.inline.TextArea;
-import org.apache.fop.complexscripts.fonts.GlyphPositioningTable;
-import org.apache.fop.complexscripts.util.CharScript;
 import org.apache.fop.fo.Constants;
 import org.apache.fop.fo.FOText;
 import org.apache.fop.fonts.Font;
 import org.apache.fop.fonts.FontSelector;
+import org.apache.fop.fonts.GlyphMapping;
 import org.apache.fop.layoutmgr.InlineKnuthSequence;
 import org.apache.fop.layoutmgr.KnuthBox;
 import org.apache.fop.layoutmgr.KnuthElement;
@@ -65,91 +64,15 @@ public class TextLayoutManager extends L
     private static final int SOFT_HYPHEN_PENALTY = 1;
 
     /**
-     * Store information about each potential text area.
-     * Index of character which ends the area, IPD of area, including
-     * any word-space and letter-space.
-     * Number of word-spaces?
-     */
-    private class AreaInfo {
-
-        private final int startIndex;
-        private final int breakIndex;
-        private int wordCharLength;
-        private final int wordSpaceCount;
-        private int letterSpaceCount;
-        private MinOptMax areaIPD;
-        private final boolean isHyphenated;
-        private final boolean isSpace;
-        private boolean breakOppAfter;
-        private final Font font;
-        private final int level;
-        private final int[][] gposAdjustments;
-
-        AreaInfo(
-            int startIndex, int breakIndex, int wordSpaceCount, int letterSpaceCount,
-             MinOptMax areaIPD, boolean isHyphenated, boolean isSpace, boolean breakOppAfter,
-             Font font, int level, int[][] gposAdjustments) {
-            assert startIndex <= breakIndex;
-            this.startIndex = startIndex;
-            this.breakIndex = breakIndex;
-            this.wordCharLength = -1;
-            this.wordSpaceCount = wordSpaceCount;
-            this.letterSpaceCount = letterSpaceCount;
-            this.areaIPD = areaIPD;
-            this.isHyphenated = isHyphenated;
-            this.isSpace = isSpace;
-            this.breakOppAfter = breakOppAfter;
-            this.font = font;
-            this.level = level;
-            this.gposAdjustments = gposAdjustments;
-        }
-
-        /**
-         * Obtain number of 'characters' contained in word. If word
-         * is mapped, then this number may be less than or greater than the
-         * original length (breakIndex - startIndex). We compute and
-         * memoize thius length upon first invocation of this method.
-         */
-        private int getWordLength() {
-            if (wordCharLength == -1) {
-                if (foText.hasMapping(startIndex, breakIndex)) {
-                    wordCharLength = foText.getMapping(startIndex, breakIndex).length();
-                } else {
-                    assert breakIndex >= startIndex;
-                    wordCharLength = breakIndex - startIndex;
-                }
-            }
-            return wordCharLength;
-        }
-
-        private void addToAreaIPD(MinOptMax idp) {
-            areaIPD = areaIPD.plus(idp);
-        }
-
-        public String toString() {
-            return super.toString() + "{"
-                    + "interval = [" + startIndex + "," + breakIndex + "]"
-                    + ", isSpace = " + isSpace
-                    + ", level = " + level
-                    + ", areaIPD = " + areaIPD
-                    + ", letterSpaceCount = " + letterSpaceCount
-                    + ", wordSpaceCount = " + wordSpaceCount
-                    + ", isHyphenated = " + isHyphenated
-                    + ", font = " + font
-                    + "}";
-        }
-    }
-
-    /**
      * this class stores information about changes in vecAreaInfo which are not yet applied
      */
     private final class PendingChange {
 
-        private final AreaInfo areaInfo;
+        private final GlyphMapping mapping;
         private final int index;
 
-        private PendingChange(final AreaInfo areaInfo, final int index) {
-            this.areaInfo = areaInfo;
+        private PendingChange(final GlyphMapping mapping, final int index) {
+            this.mapping = mapping;
             this.index = index;
         }
     }
@@ -160,7 +83,7 @@ public class TextLayoutManager extends L
     private static final Log LOG = LogFactory.getLog(TextLayoutManager.class);
 
     // Hold all possible breaks for the text in this LM's FO.
-    private final List areaInfos;
+    private final List<GlyphMapping> mappings;
 
     /** Non-space characters on which we can end a line. */
     private static final String BREAK_CHARS = "-/";
@@ -216,7 +139,7 @@ public class TextLayoutManager extends L
     public TextLayoutManager(FOText node) {
         foText = node;
         letterSpaceAdjustArray = new MinOptMax[node.length() + 1];
-        areaInfos = new ArrayList();
+        mappings = new ArrayList<GlyphMapping>();
     }
 
     private KnuthPenalty makeZeroWidthPenalty(int penaltyValue) {
@@ -274,61 +197,61 @@ public class TextLayoutManager extends L
     public void addAreas(final PositionIterator posIter, final LayoutContext context) {
 
         // Add word areas
-        AreaInfo areaInfo;
+        GlyphMapping mapping;
         int wordSpaceCount = 0;
         int letterSpaceCount = 0;
-        int firstAreaInfoIndex = -1;
-        int lastAreaInfoIndex = 0;
+        int firstMappingIndex = -1;
+        int lastMappingIndex = 0;
         MinOptMax realWidth = MinOptMax.ZERO;
 
         /* On first area created, add any leading space.
          * Calculate word-space stretch value.
          */
-        AreaInfo lastAreaInfo = null;
+        GlyphMapping lastMapping = null;
         while (posIter.hasNext()) {
             final LeafPosition tbpNext = (LeafPosition) posIter.next();
             if (tbpNext == null) {
                 continue; //Ignore elements without Positions
             }
             if (tbpNext.getLeafPos() != -1) {
-                areaInfo = (AreaInfo) areaInfos.get(tbpNext.getLeafPos());
-                if (lastAreaInfo == null
-                    || (areaInfo.font != lastAreaInfo.font)
-                    || (areaInfo.level != lastAreaInfo.level)) {
-                    if (lastAreaInfo != null) {
-                        addAreaInfoAreas(lastAreaInfo, wordSpaceCount,
-                                letterSpaceCount, firstAreaInfoIndex,
-                                lastAreaInfoIndex, realWidth, context);
+                mapping = mappings.get(tbpNext.getLeafPos());
+                if (lastMapping == null
+                    || (mapping.font != lastMapping.font)
+                    || (mapping.level != lastMapping.level)) {
+                    if (lastMapping != null) {
+                        addMappingAreas(lastMapping, wordSpaceCount,
+                                letterSpaceCount, firstMappingIndex,
+                                lastMappingIndex, realWidth, context);
                     }
-                    firstAreaInfoIndex = tbpNext.getLeafPos();
+                    firstMappingIndex = tbpNext.getLeafPos();
                     wordSpaceCount = 0;
                     letterSpaceCount = 0;
                     realWidth = MinOptMax.ZERO;
                 }
-                wordSpaceCount += areaInfo.wordSpaceCount;
-                letterSpaceCount += areaInfo.letterSpaceCount;
-                realWidth = realWidth.plus(areaInfo.areaIPD);
-                lastAreaInfoIndex = tbpNext.getLeafPos();
-                lastAreaInfo = areaInfo;
+                wordSpaceCount += mapping.wordSpaceCount;
+                letterSpaceCount += mapping.letterSpaceCount;
+                realWidth = realWidth.plus(mapping.areaIPD);
+                lastMappingIndex = tbpNext.getLeafPos();
+                lastMapping = mapping;
             }
         }
-        if (lastAreaInfo != null) {
-            addAreaInfoAreas(lastAreaInfo, wordSpaceCount, letterSpaceCount, firstAreaInfoIndex,
-                    lastAreaInfoIndex, realWidth, context);
+        if (lastMapping != null) {
+            addMappingAreas(lastMapping, wordSpaceCount, letterSpaceCount, firstMappingIndex,
+                    lastMappingIndex, realWidth, context);
         }
 
     }
 
-    private void addAreaInfoAreas(AreaInfo areaInfo, int wordSpaceCount, int letterSpaceCount,
-                                  int firstAreaInfoIndex, int lastAreaInfoIndex,
+    private void addMappingAreas(GlyphMapping mapping, int wordSpaceCount, int letterSpaceCount,
+                                  int firstMappingIndex, int lastMappingIndex,
                                   MinOptMax realWidth, LayoutContext context) {
 
         // TODO: These two statements (if, for) were like this before my recent
-        // changes. However, it seems as if they should use the AreaInfo from
-        // firstAreaInfoIndex.. lastAreaInfoIndex rather than just the last areaInfo.
+        // changes. However, it seems as if they should use the GlyphMapping from
+        // firstMappingIndex.. lastMappingIndex rather than just the last mapping.
         // This needs to be checked.
-        int textLength = areaInfo.getWordLength();
-        if (areaInfo.letterSpaceCount == textLength && !areaInfo.isHyphenated
+        int textLength = mapping.getWordLength();
+        if (mapping.letterSpaceCount == textLength && !mapping.isHyphenated
                 && context.isLastArea()) {
             // the line ends at a character like "/" or "-";
             // remove the letter space after the last character
@@ -336,7 +259,7 @@ public class TextLayoutManager extends L
             letterSpaceCount--;
         }
 
-        for (int i = areaInfo.startIndex; i < areaInfo.breakIndex; i++) {
+        for (int i = mapping.startIndex; i < mapping.endIndex; i++) {
             MinOptMax letterSpaceAdjustment = letterSpaceAdjustArray[i + 1];
             if (letterSpaceAdjustment != null && letterSpaceAdjustment.isElastic()) {
                 letterSpaceCount++;
@@ -344,7 +267,7 @@ public class TextLayoutManager extends L
         }
 
         // add hyphenation character if the last word is hyphenated
-        if (context.isLastArea() && areaInfo.isHyphenated) {
+        if (context.isLastArea() && mapping.isHyphenated) {
             realWidth = realWidth.plus(hyphIPD);
         }
 
@@ -385,8 +308,8 @@ public class TextLayoutManager extends L
             totalAdjust = difference;
         }
 
-        TextArea textArea = new TextAreaBuilder(realWidth, totalAdjust, context, firstAreaInfoIndex,
-                lastAreaInfoIndex, context.isLastArea(), areaInfo.font).build();
+        TextArea textArea = new TextAreaBuilder(realWidth, totalAdjust, context, firstMappingIndex,
+                lastMappingIndex, context.isLastArea(), mapping.font).build();
 
         // wordSpaceDim is computed in relation to wordSpaceIPD.opt
         // but the renderer needs to know the adjustment in relation
@@ -417,15 +340,15 @@ public class TextLayoutManager extends L
         private final MinOptMax width;          // content ipd
         private final int adjust;               // content ipd adjustment
         private final LayoutContext context;    // layout context
-        private final int firstIndex;           // index of first AreaInfo
-        private final int lastIndex;            // index of last AreaInfo
+        private final int firstIndex;           // index of first GlyphMapping
+        private final int lastIndex;            // index of last GlyphMapping
         private final boolean isLastArea;       // true if last inline area in line area
         private final Font font;                // applicable font
 
         // other, non-constructor state
         private TextArea textArea;              // text area being constructed
         private int blockProgressionDimension;  // calculated bpd
-        private AreaInfo areaInfo;              // current area info when iterating over words
+        private GlyphMapping mapping;           // current mapping when iterating over words
         private StringBuffer wordChars;         // current word's character buffer
         private int[] letterSpaceAdjust;        // current word's letter space adjustments
         private int letterSpaceAdjustIndex;     // last written letter space adjustment index
@@ -442,8 +365,8 @@ public class TextLayoutManager extends L
          * @param width      the MinOptMax width of the content
          * @param adjust     the total ipd adjustment with respect to the optimal width
          * @param context    the layout context
-         * @param firstIndex the index of the first AreaInfo used for the TextArea
-         * @param lastIndex  the index of the last AreaInfo used for the TextArea
+         * @param firstIndex the index of the first GlyphMapping used for the TextArea
+         * @param lastIndex  the index of the last GlyphMapping used for the TextArea
          * @param isLastArea is this TextArea the last in a line?
          * @param font       Font to be used in this particular TextArea
          */
@@ -516,30 +439,30 @@ public class TextLayoutManager extends L
          * Sets the text of the TextArea, split into words and spaces.
          */
         private void setText() {
-            int areaInfoIndex = -1;
+            int mappingIndex = -1;
             int wordCharLength = 0;
             for (int wordIndex = firstIndex; wordIndex <= lastIndex; wordIndex++) {
-                areaInfo = getAreaInfo(wordIndex);
-                if (areaInfo.isSpace) {
+                mapping = getGlyphMapping(wordIndex);
+                if (mapping.isSpace) {
                     addSpaces();
                 } else {
-                    // areaInfo stores information about a word fragment
-                    if (areaInfoIndex == -1) {
+                    // mapping stores information about a word fragment
+                    if (mappingIndex == -1) {
                         // here starts a new word
-                        areaInfoIndex = wordIndex;
+                        mappingIndex = wordIndex;
                         wordCharLength = 0;
                     }
-                    wordCharLength += areaInfo.getWordLength();
+                    wordCharLength += mapping.getWordLength();
                     if (isWordEnd(wordIndex)) {
-                        addWord(areaInfoIndex, wordIndex, wordCharLength);
-                        areaInfoIndex = -1;
+                        addWord(mappingIndex, wordIndex, wordCharLength);
+                        mappingIndex = -1;
                     }
                 }
             }
         }
 
-        private boolean isWordEnd(int areaInfoIndex) {
-            return areaInfoIndex == lastIndex || getAreaInfo(areaInfoIndex + 1).isSpace;
+        private boolean isWordEnd(int mappingIndex) {
+            return mappingIndex == lastIndex || getGlyphMapping(mappingIndex + 1).isSpace;
         }
 
         /**
@@ -564,10 +487,10 @@ public class TextLayoutManager extends L
             // iterate over word's fragments, adding word chars (with bidi
             // levels), letter space adjustments, and glyph position adjustments
             for (int i = startIndex; i <= endIndex; i++) {
-                AreaInfo wordAreaInfo = getAreaInfo(i);
-                addWordChars(wordAreaInfo);
-                addLetterAdjust(wordAreaInfo);
-                if (addGlyphPositionAdjustments(wordAreaInfo)) {
+                GlyphMapping wordMapping = getGlyphMapping(i);
+                addWordChars(wordMapping);
+                addLetterAdjust(wordMapping);
+                if (addGlyphPositionAdjustments(wordMapping)) {
                     gposAdjusted = true;
                 }
             }
@@ -617,7 +540,7 @@ public class TextLayoutManager extends L
         }
 
         private boolean isHyphenated(int endIndex) {
-            return isLastArea && endIndex == lastIndex && areaInfo.isHyphenated;
+            return isLastArea && endIndex == lastIndex && mapping.isHyphenated;
         }
 
         private void addHyphenationChar() {
@@ -632,21 +555,54 @@ public class TextLayoutManager extends L
          * (1) concatenate (possibly mapped) word characters to word character buffer;
          * (2) concatenante (possibly mapped) word bidi levels to levels buffer;
          * (3) update word's IPD with optimal IPD of fragment.
-         * @param wordAreaInfo fragment info
+         * @param wordMapping fragment info
          */
-        private void addWordChars(AreaInfo wordAreaInfo) {
-            int s = wordAreaInfo.startIndex;
-            int e = wordAreaInfo.breakIndex;
-            if (foText.hasMapping(s, e)) {
-                wordChars.append(foText.getMapping(s, e));
-                addWordLevels(foText.getMappingBidiLevels(s, e));
+        private void addWordChars(GlyphMapping wordMapping) {
+            int s = wordMapping.startIndex;
+            int e = wordMapping.endIndex;
+            if (wordMapping.mapping != null) {
+                wordChars.append(wordMapping.mapping);
+                addWordLevels(getMappingBidiLevels(wordMapping));
             } else {
                 for (int i = s; i < e; i++) {
                     wordChars.append(foText.charAt(i));
                 }
                 addWordLevels(foText.getBidiLevels(s, e));
             }
-            wordIPD += wordAreaInfo.areaIPD.getOpt();
+            wordIPD += wordMapping.areaIPD.getOpt();
+        }
+
+        /**
+         * Obtain bidirectional levels of mapping of characters over specific interval.
+         * @param start index in character buffer
+         * @param end index in character buffer
+         * @return a (possibly empty) array of bidi levels or null
+         * in case no bidi levels have been assigned
+         */
+        private int[] getMappingBidiLevels(GlyphMapping mapping) {
+            if (mapping.mapping != null) {
+                int nc = mapping.endIndex - mapping.startIndex;
+                int nm = mapping.mapping.length();
+                int[] la = foText.getBidiLevels(mapping.startIndex, mapping.endIndex);
+                if (la == null) {
+                    return null;
+                } else if (nm == nc) { // mapping is same length as mapped range
+                    return la;
+                } else if (nm > nc) { // mapping is longer than mapped range
+                    int[] ma = new int[nm];
+                    System.arraycopy(la, 0, ma, 0, la.length);
+                    for (int i = la.length, n = ma.length, l = (i > 0) ? la[i - 1] : 0; i < n; i++) {
+                        ma[i] = l;
+                    }
+                    return ma;
+                } else { // mapping is shorter than mapped range
+                    int[] ma = new int[nm];
+                    System.arraycopy(la, 0, ma, 0, ma.length);
+                    return ma;
+                }
+            } else {
+                return foText.getBidiLevels(mapping.startIndex, mapping.endIndex);
+            }
         }
 
         /**
@@ -672,16 +628,16 @@ public class TextLayoutManager extends L
         /**
          * Given a word area info associated with a word fragment,
          * concatenate letter space adjustments for each (possibly mapped) character.
-         * @param wordAreaInfo fragment info
+         * @param wordMapping fragment info
          */
-        private void addLetterAdjust(AreaInfo wordAreaInfo) {
-            int letterSpaceCount = wordAreaInfo.letterSpaceCount;
-            int wordLength = wordAreaInfo.getWordLength();
+        private void addLetterAdjust(GlyphMapping wordMapping) {
+            int letterSpaceCount = wordMapping.letterSpaceCount;
+            int wordLength = wordMapping.getWordLength();
             int taAdjust = textArea.getTextLetterSpaceAdjust();
             for (int i = 0, n = wordLength; i < n; i++) {
                 int j = letterSpaceAdjustIndex + i;
                 if (j > 0) {
-                    int k = wordAreaInfo.startIndex + i;
+                    int k = wordMapping.startIndex + i;
                     MinOptMax adj = (k < letterSpaceAdjustArray.length)
                         ? letterSpaceAdjustArray [ k ] : null;
                     letterSpaceAdjust [ j ] = (adj == null) ? 0 : adj.getOpt();
@@ -697,14 +653,14 @@ public class TextLayoutManager extends L
         /**
          * Given a word area info associated with a word fragment,
          * concatenate glyph position adjustments for each (possibly mapped) character.
-         * @param wordAreaInfo fragment info
+         * @param wordMapping fragment info
          * @return true if an adjustment was non-zero
          */
-        private boolean addGlyphPositionAdjustments(AreaInfo wordAreaInfo) {
+        private boolean addGlyphPositionAdjustments(GlyphMapping wordMapping) {
             boolean adjusted = false;
-            int[][] gpa = wordAreaInfo.gposAdjustments;
+            int[][] gpa = wordMapping.gposAdjustments;
             int numAdjusts = (gpa != null) ? gpa.length : 0;
-            int wordLength = wordAreaInfo.getWordLength();
+            int wordLength = wordMapping.getWordLength();
             if (numAdjusts > 0) {
                 int need = gposAdjustmentsIndex + numAdjusts;
                 if (need <= gposAdjustments.length) {
@@ -733,7 +689,7 @@ public class TextLayoutManager extends L
         }
 
         /**
-         * The <code>AreaInfo</code> stores information about spaces.
+         * The <code>GlyphMapping</code> stores information about spaces.
          * <p/>
          * Add the spaces - except zero-width spaces - to the TextArea.
          */
@@ -743,16 +699,16 @@ public class TextLayoutManager extends L
             // divide the area info's allocated IPD evenly among the
             // non-zero-width space characters
             int numZeroWidthSpaces = 0;
-            for (int i = areaInfo.startIndex; i < areaInfo.breakIndex; i++) {
+            for (int i = mapping.startIndex; i < mapping.endIndex; i++) {
                 char spaceChar = foText.charAt(i);
                 if (CharUtilities.isZeroWidthSpace(spaceChar)) {
                     numZeroWidthSpaces++;
                 }
             }
-            int numSpaces = areaInfo.breakIndex - areaInfo.startIndex - numZeroWidthSpaces;
-            int spaceIPD = areaInfo.areaIPD.getOpt() / ((numSpaces > 0) ? numSpaces : 1);
+            int numSpaces = mapping.endIndex - mapping.startIndex - numZeroWidthSpaces;
+            int spaceIPD = mapping.areaIPD.getOpt() / ((numSpaces > 0) ? numSpaces : 1);
             // add space area children, one for each non-zero-width space character
-            for (int i = areaInfo.startIndex; i < areaInfo.breakIndex; i++) {
+            for (int i = mapping.startIndex; i < mapping.endIndex; i++) {
                 char spaceChar = foText.charAt(i);
                 int level = foText.bidiLevelAt(i);
                 if (!CharUtilities.isZeroWidthSpace(spaceChar)) {
@@ -766,39 +722,20 @@ public class TextLayoutManager extends L
 
     }
 
-    private void addAreaInfo(AreaInfo ai) {
-        addAreaInfo(areaInfos.size(), ai);
-    }
-
-    private void addAreaInfo(int index, AreaInfo ai) {
-        areaInfos.add(index, ai);
+    private void addGlyphMapping(GlyphMapping mapping) {
+        addGlyphMapping(mappings.size(), mapping);
     }
 
-    private void removeAreaInfo(int index) {
-        areaInfos.remove(index);
+    private void addGlyphMapping(int index, GlyphMapping mapping) {
+        mappings.add(index, mapping);
     }
 
-    private AreaInfo getAreaInfo(int index) {
-        return (AreaInfo) areaInfos.get(index);
+    private void removeGlyphMapping(int index) {
+        mappings.remove(index);
     }
 
-    private void addToLetterAdjust(int index, int width) {
-        if (letterSpaceAdjustArray[index] == null) {
-            letterSpaceAdjustArray[index] = MinOptMax.getInstance(width);
-        } else {
-            letterSpaceAdjustArray[index] = letterSpaceAdjustArray[index].plus(width);
-        }
-    }
-
-    /**
-     * Indicates whether a character is a space in terms of this layout manager.
-     * @param ch the character
-     * @return true if it's a space
-     */
-    private static boolean isSpace(final char ch) {
-        return ch == CharUtilities.SPACE
-                || CharUtilities.isNonBreakableSpace(ch)
-                || CharUtilities.isFixedWidthSpace(ch);
+    private GlyphMapping getGlyphMapping(int index) {
+        return mappings.get(index);
     }
 
     /** {@inheritDoc} */
@@ -810,8 +747,8 @@ public class TextLayoutManager extends L
 
         final List returnList = new LinkedList();
         KnuthSequence sequence = new InlineKnuthSequence();
-        AreaInfo areaInfo = null;
-        AreaInfo prevAreaInfo = null;
+        GlyphMapping mapping = null;
+        GlyphMapping prevMapping = null;
         returnList.add(sequence);
 
         if (LOG.isDebugEnabled()) {
@@ -857,24 +794,24 @@ public class TextLayoutManager extends L
             }
             if (inWord) {
                 if (breakOpportunity
-                     || TextLayoutManager.isSpace(ch)
+                     || GlyphMapping.isSpace(ch)
                      || CharUtilities.isExplicitBreak(ch)
                      || ((prevLevel != -1) && (level != prevLevel))) {
                     // this.foText.charAt(lastIndex) == CharUtilities.SOFT_HYPHEN
-                    prevAreaInfo = processWord(alignment, sequence, prevAreaInfo, ch,
+                    prevMapping = processWord(alignment, sequence, prevMapping, ch,
                             breakOpportunity, true, prevLevel);
                 }
             } else if (inWhitespace) {
                 if (ch != CharUtilities.SPACE || breakOpportunity) {
-                    prevAreaInfo = processWhitespace(alignment, sequence,
+                    prevMapping = processWhitespace(alignment, sequence,
                                                      breakOpportunity, prevLevel);
                 }
             } else {
-                if (areaInfo != null) {
-                    prevAreaInfo = areaInfo;
-                    processLeftoverAreaInfo(alignment, sequence, areaInfo,
+                if (mapping != null) {
+                    prevMapping = mapping;
+                    processLeftoverGlyphMapping(alignment, sequence, mapping,
                             ch == CharUtilities.SPACE || breakOpportunity);
-                    areaInfo = null;
+                    mapping = null;
                 }
                 if (breakAction == LineBreakStatus.EXPLICIT_BREAK) {
                     sequence = processLinebreak(returnList, sequence);
@@ -888,15 +825,15 @@ public class TextLayoutManager extends L
                         this.foText, this);
                 font.mapChar(ch);
                 // preserved space or non-breaking space:
-                // create the AreaInfo object
-                areaInfo = new AreaInfo(nextStart, nextStart + 1, 1, 0, wordSpaceIPD, false, true,
+                // create the GlyphMapping object
+                mapping = new GlyphMapping(nextStart, nextStart + 1, 1, 0, wordSpaceIPD, false, true,
                                         breakOpportunity, spaceFont, level, null);
                 thisStart = nextStart + 1;
             } else if (CharUtilities.isFixedWidthSpace(ch) || CharUtilities.isZeroWidthSpace(ch)) {
-                // create the AreaInfo object
+                // create the GlyphMapping object
                 Font font = FontSelector.selectFontForCharacterInText(ch, foText, this);
                 MinOptMax ipd = MinOptMax.getInstance(font.getCharWidth(ch));
-                areaInfo = new AreaInfo(nextStart, nextStart + 1, 0, 0, ipd, false, true,
+                mapping = new GlyphMapping(nextStart, nextStart + 1, 0, 0, ipd, false, true,
                                         breakOpportunity, font, level, null);
                 thisStart = nextStart + 1;
             } else if (CharUtilities.isExplicitBreak(ch)) {
@@ -904,7 +841,7 @@ public class TextLayoutManager extends L
                 thisStart = nextStart + 1;
             }
 
-            inWord = !TextLayoutManager.isSpace(ch) && !CharUtilities.isExplicitBreak(ch);
+            inWord = !GlyphMapping.isSpace(ch) && !CharUtilities.isExplicitBreak(ch);
             inWhitespace = ch == CharUtilities.SPACE
                     && foText.getWhitespaceTreatment() != Constants.EN_PRESERVE;
             prevLevel = level;
@@ -913,11 +850,11 @@ public class TextLayoutManager extends L
 
         // Process any last elements
         if (inWord) {
-            processWord(alignment, sequence, prevAreaInfo, ch, false, false, prevLevel);
+            processWord(alignment, sequence, prevMapping, ch, false, false, prevLevel);
         } else if (inWhitespace) {
             processWhitespace(alignment, sequence, !keepTogether, prevLevel);
-        } else if (areaInfo != null) {
-            processLeftoverAreaInfo(alignment, sequence, areaInfo,
+        } else if (mapping != null) {
+            processLeftoverGlyphMapping(alignment, sequence, mapping,
                     ch == CharUtilities.ZERO_WIDTH_SPACE);
         } else if (CharUtilities.isExplicitBreak(ch)) {
             this.processLinebreak(returnList, sequence);
@@ -948,15 +885,14 @@ public class TextLayoutManager extends L
         return sequence;
     }
 
-    private void processLeftoverAreaInfo(int alignment,
-                                         KnuthSequence sequence, AreaInfo areaInfo,
-                                         boolean breakOpportunityAfter) {
-        addAreaInfo(areaInfo);
-        areaInfo.breakOppAfter = breakOpportunityAfter;
-        addElementsForASpace(sequence, alignment, areaInfo, areaInfos.size() - 1);
+    private void processLeftoverGlyphMapping(int alignment, KnuthSequence sequence,
+            GlyphMapping mapping, boolean breakOpportunityAfter) {
+        addGlyphMapping(mapping);
+        mapping.breakOppAfter = breakOpportunityAfter;
+        addElementsForASpace(sequence, alignment, mapping, mappings.size() - 1);
     }
 
-    private AreaInfo processWhitespace(final int alignment,
+    private GlyphMapping processWhitespace(final int alignment,
             final KnuthSequence sequence, final boolean breakOpportunity, int level) {
 
         if (LOG.isDebugEnabled()) {
@@ -964,209 +900,24 @@ public class TextLayoutManager extends L
         }
 
         // End of whitespace
-        // create the AreaInfo object
+        // create the GlyphMapping object
         assert nextStart >= thisStart;
-        AreaInfo areaInfo = new AreaInfo(
-            thisStart, nextStart, nextStart - thisStart, 0,
+        GlyphMapping mapping = new GlyphMapping(
+              thisStart, nextStart, nextStart - thisStart, 0,
               wordSpaceIPD.mult(nextStart - thisStart),
               false, true, breakOpportunity, spaceFont, level, null);
 
-        addAreaInfo(areaInfo);
+        addGlyphMapping(mapping);
 
         // create the elements
-        addElementsForASpace(sequence, alignment, areaInfo, areaInfos.size() - 1);
+        addElementsForASpace(sequence, alignment, mapping, mappings.size() - 1);
 
         thisStart = nextStart;
-        return areaInfo;
+        return mapping;
     }
 
-    private AreaInfo processWordMapping(
-        int lastIndex, final Font font, AreaInfo prevAreaInfo, final char breakOpportunityChar,
-          final boolean endsWithHyphen, int level) {
-        int s = this.thisStart; // start index of word in FOText character buffer
-        int e = lastIndex;      // end index of word in FOText character buffer
-        int nLS = 0;            // # of letter spaces
-        String script = foText.getScript();
-        String language = foText.getLanguage();
-
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("PW: [" + thisStart + "," + lastIndex + "]: {"
-                        + " +M"
-                        + ", level = " + level
-                        + " }");
-        }
-
-        // 1. extract unmapped character sequence
-        CharSequence ics = foText.subSequence(s, e);
-
-        // 2. if script is not specified (by FO property) or it is specified as 'auto',
-        // then compute dominant script
-        if ((script == null) || "auto".equals(script)) {
-            script = CharScript.scriptTagFromCode(CharScript.dominantScript(ics));
-        }
-        if ((language == null) || "none".equals(language)) {
-            language = "dflt";
-        }
-
-        // 3. perform mapping of chars to glyphs ... to glyphs ... to chars
-        CharSequence mcs = font.performSubstitution(ics, script, language);
-
-        // 4. compute glyph position adjustments on (substituted) characters
-        int[][] gpa;
-        if (font.performsPositioning()) {
-            // handle GPOS adjustments
-            gpa = font.performPositioning(mcs, script, language);
-        } else if (font.hasKerning()) {
-            // handle standard (non-GPOS) kerning adjustments
-            gpa = getKerningAdjustments(mcs, font);
-        } else {
-            gpa = null;
-        }
-
-        // 5. reorder combining marks so that they precede (within the mapped char sequence) the
-        // base to which they are applied; N.B. position adjustments (gpa) are reordered in place
-        mcs = font.reorderCombiningMarks(mcs, gpa, script, language);
-
-        // 6. if mapped sequence differs from input sequence, then memoize mapped sequence
-        if (!CharUtilities.isSameSequence(mcs, ics)) {
-            foText.addMapping(s, e, mcs);
-        }
-
-        // 7. compute word ipd based on final position adjustments
-        MinOptMax ipd = MinOptMax.ZERO;
-        for (int i = 0, n = mcs.length(); i < n; i++) {
-            int c = mcs.charAt(i);
-            // TODO !BMP
-            int  w = font.getCharWidth(c);
-            if (w < 0) {
-                w = 0;
-            }
-            if (gpa != null) {
-                w += gpa [ i ] [ GlyphPositioningTable.Value.IDX_X_ADVANCE ];
-            }
-            ipd = ipd.plus(w);
-        }
-
-        // [TBD] - handle letter spacing
-
-        return new AreaInfo(
-            s, e, 0, nLS, ipd, endsWithHyphen, false,
-              breakOpportunityChar != 0, font, level, gpa);
-    }
-
-    /**
-     * Given a mapped character sequence MCS, obtain glyph position adjustments
-     * from the font's kerning data.
-     * @param mcs mapped character sequence
-     * @param font applicable font
-     * @return glyph position adjustments (or null if no kerning)
-     */
-    private int[][] getKerningAdjustments(CharSequence mcs, final Font font) {
-        int nc = mcs.length();
-        // extract kerning array
-        int[] ka = new int [ nc ]; // kerning array
-        for (int i = 0, n = nc, cPrev = -1; i < n; i++) {
-            int c = mcs.charAt(i);
-            // TODO !BMP
-            if (cPrev >= 0) {
-                ka[i] = font.getKernValue(cPrev, c);
-            }
-            cPrev = c;
-        }
-        // was there a non-zero kerning?
-        boolean hasKerning = false;
-        for (int i = 0, n = nc; i < n; i++) {
-            if (ka[i] != 0) {
-                hasKerning = true;
-                break;
-            }
-        }
-        // if non-zero kerning, then create and return glyph position adjustment array
-        if (hasKerning) {
-            int[][] gpa = new int [ nc ] [ 4 ];
-            for (int i = 0, n = nc; i < n; i++) {
-                if (i > 0) {
-                    gpa [ i - 1 ] [ GlyphPositioningTable.Value.IDX_X_ADVANCE ] = ka [ i ];
-                }
-            }
-            return gpa;
-        } else {
-            return null;
-        }
-    }
-
-    private AreaInfo processWordNoMapping(int lastIndex, final Font font, AreaInfo prevAreaInfo,
-            final char breakOpportunityChar, final boolean endsWithHyphen, int level) {
-        boolean kerning = font.hasKerning();
-        MinOptMax wordIPD = MinOptMax.ZERO;
-
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("PW: [" + thisStart + "," + lastIndex + "]: {"
-                        + " -M"
-                        + ", level = " + level
-                        + " }");
-        }
-
-        for (int i = thisStart; i < lastIndex; i++) {
-            char currentChar = foText.charAt(i);
-
-            //character width
-            int charWidth = font.getCharWidth(currentChar);
-            wordIPD = wordIPD.plus(charWidth);
-
-            //kerning
-            if (kerning) {
-                int kern = 0;
-                if (i > thisStart) {
-                    char previousChar = foText.charAt(i - 1);
-                    kern = font.getKernValue(previousChar, currentChar);
-                } else if (prevAreaInfo != null
-                           && !prevAreaInfo.isSpace && prevAreaInfo.breakIndex > 0) {
-                    char previousChar = foText.charAt(prevAreaInfo.breakIndex - 1);
-                    kern = font.getKernValue(previousChar, currentChar);
-                }
-                if (kern != 0) {
-                    addToLetterAdjust(i, kern);
-                    wordIPD = wordIPD.plus(kern);
-                }
-            }
-        }
-        if (kerning
-                && (breakOpportunityChar != 0)
-                && !TextLayoutManager.isSpace(breakOpportunityChar)
-                && lastIndex > 0
-                && endsWithHyphen) {
-            int kern = font.getKernValue(foText.charAt(lastIndex - 1), breakOpportunityChar);
-            if (kern != 0) {
-                addToLetterAdjust(lastIndex, kern);
-                //TODO: add kern to wordIPD?
-            }
-        }
-        // shy+chars at start of word: wordLength == 0 && breakOpportunity
-        // shy only characters in word: wordLength == 0 && !breakOpportunity
-        int wordLength = lastIndex - thisStart;
-        int letterSpaces = 0;
-        if (wordLength != 0) {
-            letterSpaces = wordLength - 1;
-            // if there is a break opportunity and the next one (break character)
-            // is not a space, it could be used as a line end;
-            // add one more letter space, in case other text follows
-            if ((breakOpportunityChar != 0) && !TextLayoutManager.isSpace(breakOpportunityChar)) {
-                  letterSpaces++;
-            }
-        }
-        assert letterSpaces >= 0;
-        wordIPD = wordIPD.plus(letterSpaceIPD.mult(letterSpaces));
-
-        // create and return the AreaInfo object
-        return new AreaInfo(thisStart, lastIndex, 0,
-                            letterSpaces, wordIPD,
-                            endsWithHyphen,
-                            false, breakOpportunityChar != 0, font, level, null);
-    }
-
-    private AreaInfo processWord(final int alignment, final KnuthSequence sequence,
-            AreaInfo prevAreaInfo, final char ch, final boolean breakOpportunity,
+    private GlyphMapping processWord(final int alignment, final KnuthSequence sequence,
+            GlyphMapping prevMapping, final char ch, final boolean breakOpportunity,
             final boolean checkEndsWithHyphen, int level) {
 
         //Word boundary found, process widths and kerning
@@ -1178,23 +929,20 @@ public class TextLayoutManager extends L
                 && foText.charAt(lastIndex) == CharUtilities.SOFT_HYPHEN;
         Font font = FontSelector.selectFontForCharactersInText(
             foText, thisStart, lastIndex, foText, this);
-        AreaInfo areaInfo;
-        if (font.performsSubstitution() || font.performsPositioning()) {
-            areaInfo = processWordMapping(
-                lastIndex, font, prevAreaInfo, breakOpportunity ? ch : 0, endsWithHyphen, level);
-        } else {
-            areaInfo = processWordNoMapping(
-                lastIndex, font, prevAreaInfo, breakOpportunity ? ch : 0, endsWithHyphen, level);
-        }
-        prevAreaInfo = areaInfo;
-        addAreaInfo(areaInfo);
+        char breakOpportunityChar = breakOpportunity ? ch : 0;
+        char precedingChar = prevMapping != null && !prevMapping.isSpace
+                && prevMapping.endIndex > 0 ? foText.charAt(prevMapping.endIndex - 1) : 0;
+        GlyphMapping mapping = GlyphMapping.doGlyphMapping(foText, thisStart, lastIndex, font,
+                letterSpaceIPD, letterSpaceAdjustArray, precedingChar, breakOpportunityChar, endsWithHyphen, level);
+        prevMapping = mapping;
+        addGlyphMapping(mapping);
         tempStart = nextStart;
 
         //add the elements
-        addElementsForAWordFragment(sequence, alignment, areaInfo, areaInfos.size() - 1);
+        addElementsForAWordFragment(sequence, alignment, mapping, mappings.size() - 1);
         thisStart = nextStart;
 
-        return prevAreaInfo;
+        return prevMapping;
     }
 
     /** {@inheritDoc} */
@@ -1214,9 +962,9 @@ public class TextLayoutManager extends L
         int index = leafPos.getLeafPos();
         //element could refer to '-1' position, for non-collapsed spaces (?)
         if (index > -1) {
-            AreaInfo areaInfo = getAreaInfo(index);
-            areaInfo.letterSpaceCount++;
-            areaInfo.addToAreaIPD(letterSpaceIPD);
+            GlyphMapping mapping = getGlyphMapping(index);
+            mapping.letterSpaceCount++;
+            mapping.addToAreaIPD(letterSpaceIPD);
             if (TextLayoutManager.BREAK_CHARS.indexOf(foText.charAt(tempStart - 1)) >= 0) {
                 // the last character could be used as a line break
                 // append new elements to oldList
@@ -1227,13 +975,13 @@ public class TextLayoutManager extends L
             } else if (letterSpaceIPD.isStiff()) {
                 // constant letter space: replace the box
                 // give it the unwrapped position of the replaced element
-                oldListIterator.set(new KnuthInlineBox(areaInfo.areaIPD.getOpt(),
+                oldListIterator.set(new KnuthInlineBox(mapping.areaIPD.getOpt(),
                         alignmentContext, pos, false));
             } else {
                 // adjustable letter space: replace the glue
                 oldListIterator.next(); // this would return the penalty element
                 oldListIterator.next(); // this would return the glue element
-                oldListIterator.set(new KnuthGlue(letterSpaceIPD.mult(areaInfo.letterSpaceCount),
+                oldListIterator.set(new KnuthGlue(letterSpaceIPD.mult(mapping.letterSpaceCount),
                         auxiliaryPosition, true));
             }
         }
@@ -1242,26 +990,26 @@ public class TextLayoutManager extends L
 
     /** {@inheritDoc} */
     public void hyphenate(Position pos, HyphContext hyphContext) {
-        AreaInfo areaInfo = getAreaInfo(((LeafPosition) pos).getLeafPos() + changeOffset);
-        int startIndex = areaInfo.startIndex;
+        GlyphMapping mapping = getGlyphMapping(((LeafPosition) pos).getLeafPos() + changeOffset);
+        int startIndex = mapping.startIndex;
         int stopIndex;
         boolean nothingChanged = true;
-        Font font = areaInfo.font;
+        Font font = mapping.font;
 
-        while (startIndex < areaInfo.breakIndex) {
+        while (startIndex < mapping.endIndex) {
             MinOptMax newIPD = MinOptMax.ZERO;
             boolean hyphenFollows;
 
             stopIndex = startIndex + hyphContext.getNextHyphPoint();
-            if (hyphContext.hasMoreHyphPoints() && stopIndex <= areaInfo.breakIndex) {
+            if (hyphContext.hasMoreHyphPoints() && stopIndex <= mapping.endIndex) {
                 // stopIndex is the index of the first character
                 // after a hyphenation point
                 hyphenFollows = true;
             } else {
                 // there are no more hyphenation points,
-                // or the next one is after areaInfo.breakIndex
+                // or the next one is after mapping.breakIndex
                 hyphenFollows = false;
-                stopIndex = areaInfo.breakIndex;
+                stopIndex = mapping.endIndex;
             }
 
             hyphContext.updateOffset(stopIndex - startIndex);
@@ -1286,18 +1034,18 @@ public class TextLayoutManager extends L
 
             // add letter spaces
             boolean isWordEnd
-                = (stopIndex == areaInfo.breakIndex)
-                && (areaInfo.letterSpaceCount < areaInfo.getWordLength());
+                = (stopIndex == mapping.endIndex)
+                && (mapping.letterSpaceCount < mapping.getWordLength());
             int letterSpaceCount = isWordEnd ? stopIndex - startIndex - 1 : stopIndex - startIndex;
 
             assert letterSpaceCount >= 0;
             newIPD = newIPD.plus(letterSpaceIPD.mult(letterSpaceCount));
 
-            if (!(nothingChanged && stopIndex == areaInfo.breakIndex && !hyphenFollows)) {
-                // the new AreaInfo object is not equal to the old one
+            if (!(nothingChanged && stopIndex == mapping.endIndex && !hyphenFollows)) {
+                // the new GlyphMapping object is not equal to the old one
                 changeList.add(
                     new PendingChange(
-                      new AreaInfo(startIndex, stopIndex, 0,
+                      new GlyphMapping(startIndex, stopIndex, 0,
                                      letterSpaceCount, newIPD, hyphenFollows,
                                      false, false, font, -1, null),
                         ((LeafPosition) pos).getLeafPos() + changeOffset));
@@ -1324,7 +1072,7 @@ public class TextLayoutManager extends L
             return false;
         }
 
-        // Find the first and last positions in oldList that point to an AreaInfo
+        // Find the first and last positions in oldList that point to a GlyphMapping
         // (i.e. getLeafPos() != -1)
         LeafPosition startPos = null;
         LeafPosition endPos = null;
@@ -1349,8 +1097,8 @@ public class TextLayoutManager extends L
         returnedIndices[0] = (startPos != null ? startPos.getLeafPos() : -1) + changeOffset;
         returnedIndices[1] = (endPos != null ? endPos.getLeafPos() : -1) + changeOffset;
 
-        int areaInfosAdded = 0;
-        int areaInfosRemoved = 0;
+        int mappingsAdded = 0;
+        int mappingsRemoved = 0;
 
         if (!changeList.isEmpty()) {
             int oldIndex = -1;
@@ -1360,24 +1108,24 @@ public class TextLayoutManager extends L
             while (changeListIterator.hasNext()) {
                 currChange = (PendingChange) changeListIterator.next();
                 if (currChange.index == oldIndex) {
-                    areaInfosAdded++;
-                    changeIndex = currChange.index + areaInfosAdded - areaInfosRemoved;
+                    mappingsAdded++;
+                    changeIndex = currChange.index + mappingsAdded - mappingsRemoved;
                 } else {
-                    areaInfosRemoved++;
-                    areaInfosAdded++;
+                    mappingsRemoved++;
+                    mappingsAdded++;
                     oldIndex = currChange.index;
-                    changeIndex = currChange.index + areaInfosAdded - areaInfosRemoved;
-                    removeAreaInfo(changeIndex);
+                    changeIndex = currChange.index + mappingsAdded - mappingsRemoved;
+                    removeGlyphMapping(changeIndex);
                 }
-                addAreaInfo(changeIndex, currChange.areaInfo);
+                addGlyphMapping(changeIndex, currChange.mapping);
             }
             changeList.clear();
         }
 
         // increase the end index for getChangedKnuthElements()
-        returnedIndices[1] += (areaInfosAdded - areaInfosRemoved);
+        returnedIndices[1] += (mappingsAdded - mappingsRemoved);
         // increase offset to use for subsequent paragraphs
-        changeOffset += (areaInfosAdded - areaInfosRemoved);
+        changeOffset += (mappingsAdded - mappingsRemoved);
 
         return hasChanged;
     }
@@ -1391,16 +1139,16 @@ public class TextLayoutManager extends L
         final LinkedList returnList = new LinkedList();
 
         for (; returnedIndices[0] <= returnedIndices[1]; returnedIndices[0]++) {
-            AreaInfo areaInfo = getAreaInfo(returnedIndices[0]);
-            if (areaInfo.wordSpaceCount == 0) {
-                // areaInfo refers either to a word or a word fragment
-                addElementsForAWordFragment(returnList, alignment, areaInfo, returnedIndices[0]);
+            GlyphMapping mapping = getGlyphMapping(returnedIndices[0]);
+            if (mapping.wordSpaceCount == 0) {
+                // mapping refers either to a word or a word fragment
+                addElementsForAWordFragment(returnList, alignment, mapping, returnedIndices[0]);
             } else {
-                // areaInfo refers to a space
-                addElementsForASpace(returnList, alignment, areaInfo, returnedIndices[0]);
+                // mapping refers to a space
+                addElementsForASpace(returnList, alignment, mapping, returnedIndices[0]);
             }
         }
-        setFinished(returnedIndices[0] == areaInfos.size() - 1);
+        setFinished(returnedIndices[0] == mappings.size() - 1);
         //ElementListObserver.observe(returnList, "text-changed", null);
         return returnList;
     }
@@ -1409,9 +1157,9 @@ public class TextLayoutManager extends L
     public String getWordChars(Position pos) {
         int leafValue = ((LeafPosition) pos).getLeafPos() + changeOffset;
         if (leafValue != -1) {
-            AreaInfo areaInfo = getAreaInfo(leafValue);
-            StringBuffer buffer = new StringBuffer(areaInfo.getWordLength());
-            for (int i = areaInfo.startIndex; i < areaInfo.breakIndex; i++) {
+            GlyphMapping mapping = getGlyphMapping(leafValue);
+            StringBuffer buffer = new StringBuffer(mapping.getWordLength());
+            for (int i = mapping.startIndex; i < mapping.endIndex; i++) {
                 buffer.append(foText.charAt(i));
             }
             return buffer.toString();
@@ -1420,41 +1168,39 @@ public class TextLayoutManager extends L
         }
     }
 
-    private void addElementsForASpace(List baseList, int alignment, AreaInfo areaInfo,
+    private void addElementsForASpace(List baseList, int alignment, GlyphMapping mapping,
                                       int leafValue) {
         LeafPosition mainPosition = new LeafPosition(this, leafValue);
 
-        if (!areaInfo.breakOppAfter) {
+        if (!mapping.breakOppAfter) {
             // a non-breaking space
             if (alignment == Constants.EN_JUSTIFY) {
                 // the space can stretch and shrink, and must be preserved
                 // when starting a line
                 baseList.add(makeAuxiliaryZeroWidthBox());
                 baseList.add(makeZeroWidthPenalty(KnuthElement.INFINITE));
-                baseList.add(new KnuthGlue(areaInfo.areaIPD, mainPosition, false));
+                baseList.add(new KnuthGlue(mapping.areaIPD, mainPosition, false));
             } else {
                 // the space does not need to stretch or shrink, and must be
                 // preserved when starting a line
-                baseList.add(new KnuthInlineBox(areaInfo.areaIPD.getOpt(), null, mainPosition,
+                baseList.add(new KnuthInlineBox(mapping.areaIPD.getOpt(), null, mainPosition,
                         true));
             }
         } else {
-            if (foText.charAt(areaInfo.startIndex) != CharUtilities.SPACE
+            if (foText.charAt(mapping.startIndex) != CharUtilities.SPACE
                     || foText.getWhitespaceTreatment() == Constants.EN_PRESERVE) {
                 // a breaking space that needs to be preserved
-                baseList
-                    .addAll(getElementsForBreakingSpace(alignment, areaInfo, auxiliaryPosition, 0,
-                        mainPosition, areaInfo.areaIPD.getOpt(), true));
+                baseList.addAll(getElementsForBreakingSpace(alignment, mapping, auxiliaryPosition, 0,
+                        mainPosition, mapping.areaIPD.getOpt(), true));
             } else {
                 // a (possible block) of breaking spaces
-                baseList
-                    .addAll(getElementsForBreakingSpace(alignment, areaInfo, mainPosition,
-                        areaInfo.areaIPD.getOpt(), auxiliaryPosition, 0, false));
+                baseList.addAll(getElementsForBreakingSpace(alignment, mapping, mainPosition,
+                        mapping.areaIPD.getOpt(), auxiliaryPosition, 0, false));
             }
         }
     }
 
-    private List getElementsForBreakingSpace(int alignment, AreaInfo areaInfo, Position pos2,
+    private List getElementsForBreakingSpace(int alignment, GlyphMapping mapping, Position pos2,
                                              int p2WidthOffset, Position pos3,
                                              int p3WidthOffset, boolean skipZeroCheck) {
         List elements = new ArrayList();
@@ -1504,7 +1250,7 @@ public class TextLayoutManager extends L
                 elements.add(g);
                 elements.add(makeZeroWidthPenalty(0));
                 g = new KnuthGlue(
-                    areaInfo.areaIPD.getOpt(),
+                    mapping.areaIPD.getOpt(),
                      -3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0, pos2, false);
                 elements.add(g);
             }
@@ -1513,25 +1259,24 @@ public class TextLayoutManager extends L
         case EN_JUSTIFY:
             // justified text:
             // the stretch and shrink depends on the space width
-            elements.addAll(getElementsForJustifiedText(areaInfo, pos2, p2WidthOffset, pos3,
-                    p3WidthOffset, skipZeroCheck, areaInfo.areaIPD.getShrink()));
+            elements.addAll(getElementsForJustifiedText(mapping, pos2, p2WidthOffset, pos3,
+                    p3WidthOffset, skipZeroCheck, mapping.areaIPD.getShrink()));
             break;
 
         default:
             // last line justified, the other lines unjustified:
             // use only the space stretch
-            elements.addAll(getElementsForJustifiedText(areaInfo, pos2, p2WidthOffset, pos3,
+            elements.addAll(getElementsForJustifiedText(mapping, pos2, p2WidthOffset, pos3,
                     p3WidthOffset, skipZeroCheck, 0));
         }
         return elements;
     }
 
-    private List getElementsForJustifiedText(
-        AreaInfo areaInfo, Position pos2, int p2WidthOffset,
-         Position pos3, int p3WidthOffset, boolean skipZeroCheck,
-         int shrinkability) {
+    private List getElementsForJustifiedText(GlyphMapping mapping, Position pos2, int p2WidthOffset,
+                                             Position pos3, int p3WidthOffset, boolean skipZeroCheck,
+                                             int shrinkability) {
 
-        int stretchability = areaInfo.areaIPD.getStretch();
+        int stretchability = mapping.areaIPD.getStretch();
 
         List elements = new ArrayList();
         if (skipZeroCheck || lineStartBAP != 0 || lineEndBAP != 0) {
@@ -1543,34 +1288,34 @@ public class TextLayoutManager extends L
             elements.add(makeZeroWidthPenalty(KnuthElement.INFINITE));
             elements.add(new KnuthGlue(lineStartBAP + p3WidthOffset, 0, 0, pos3, false));
         } else {
-            elements.add(new KnuthGlue(areaInfo.areaIPD.getOpt(), stretchability, shrinkability,
+            elements.add(new KnuthGlue(mapping.areaIPD.getOpt(), stretchability, shrinkability,
                     pos2, false));
         }
         return elements;
     }
 
-    private void addElementsForAWordFragment(List baseList, int alignment, AreaInfo areaInfo,
+    private void addElementsForAWordFragment(List baseList, int alignment, GlyphMapping mapping,
                                              int leafValue) {
         LeafPosition mainPosition = new LeafPosition(this, leafValue);
 
         // if the last character of the word fragment is '-' or '/',
         // the fragment could end a line; in this case, it loses one
         // of its letter spaces;
-        boolean suppressibleLetterSpace = areaInfo.breakOppAfter && !areaInfo.isHyphenated;
+        boolean suppressibleLetterSpace = mapping.breakOppAfter && !mapping.isHyphenated;
 
         if (letterSpaceIPD.isStiff()) {
             // constant letter spacing
             baseList.add(new KnuthInlineBox(suppressibleLetterSpace
-                    ? areaInfo.areaIPD.getOpt() - letterSpaceIPD.getOpt()
-                    : areaInfo.areaIPD.getOpt(),
+                    ? mapping.areaIPD.getOpt() - letterSpaceIPD.getOpt()
+                    : mapping.areaIPD.getOpt(),
                     alignmentContext, notifyPos(mainPosition), false));
         } else {
             // adjustable letter spacing
             int unsuppressibleLetterSpaces = suppressibleLetterSpace
-                    ? areaInfo.letterSpaceCount - 1
-                    : areaInfo.letterSpaceCount;
-            baseList.add(new KnuthInlineBox(areaInfo.areaIPD.getOpt()
-                    - areaInfo.letterSpaceCount * letterSpaceIPD.getOpt(),
+                    ? mapping.letterSpaceCount - 1
+                    : mapping.letterSpaceCount;
+            baseList.add(new KnuthInlineBox(mapping.areaIPD.getOpt()
+                    - mapping.letterSpaceCount * letterSpaceIPD.getOpt(),
                             alignmentContext, notifyPos(mainPosition), false));
             baseList.add(makeZeroWidthPenalty(KnuthElement.INFINITE));
             baseList.add(new KnuthGlue(letterSpaceIPD.mult(unsuppressibleLetterSpaces),
@@ -1580,19 +1325,19 @@ public class TextLayoutManager extends L
 
         // extra-elements if the word fragment is the end of a syllable,
         // or it ends with a character that can be used as a line break
-        if (areaInfo.isHyphenated) {
+        if (mapping.isHyphenated) {
             MinOptMax widthIfNoBreakOccurs = null;
-            if (areaInfo.breakIndex < foText.length()) {
+            if (mapping.endIndex < foText.length()) {
                 //Add in kerning in no-break condition
-                widthIfNoBreakOccurs = letterSpaceAdjustArray[areaInfo.breakIndex];
+                widthIfNoBreakOccurs = letterSpaceAdjustArray[mapping.endIndex];
             }
-            //if (areaInfo.breakIndex)
+            //if (mapping.breakIndex)
 
             // the word fragment ends at the end of a syllable:
             // if a break occurs the content width increases,
             // otherwise nothing happens
             addElementsForAHyphen(baseList, alignment, hyphIPD, widthIfNoBreakOccurs,
-                    areaInfo.breakOppAfter && areaInfo.isHyphenated);
+                    mapping.breakOppAfter && mapping.isHyphenated);
         } else if (suppressibleLetterSpace) {
             // the word fragment ends with a character that acts as a hyphen
             // if a break occurs the width does not increase,

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/AbstractGenericSVGHandler.java Mon Jul 29 21:45:20 2013
@@ -31,6 +31,7 @@ import org.apache.batik.bridge.GVTBuilde
 import org.apache.batik.dom.AbstractDocument;
 import org.apache.batik.dom.svg.SVGDOMImplementation;
 import org.apache.batik.gvt.GraphicsNode;
+import org.apache.batik.gvt.font.DefaultFontFamilyResolver;
 
 import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
 
@@ -122,7 +123,8 @@ public abstract class AbstractGenericSVG
 
         //Prepare
         FOUserAgent userAgent = rendererContext.getUserAgent();
-        SVGUserAgent svgUserAgent = new SVGUserAgent(userAgent, new AffineTransform());
+        SVGUserAgent svgUserAgent = new SVGUserAgent(userAgent, DefaultFontFamilyResolver.SINGLETON,
+                new AffineTransform());
 
         //Create Batik BridgeContext
         final BridgeContext bridgeContext = new BridgeContext(svgUserAgent);

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/afp/AFPSVGHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/afp/AFPSVGHandler.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/afp/AFPSVGHandler.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/afp/AFPSVGHandler.java Mon Jul 29 21:45:20 2013
@@ -29,6 +29,7 @@ import org.w3c.dom.Document;
 import org.apache.batik.bridge.BridgeContext;
 import org.apache.batik.dom.svg.SVGDOMImplementation;
 import org.apache.batik.gvt.GraphicsNode;
+import org.apache.batik.gvt.font.DefaultFontFamilyResolver;
 
 import org.apache.xmlgraphics.image.loader.ImageManager;
 import org.apache.xmlgraphics.image.loader.ImageSessionContext;
@@ -43,6 +44,7 @@ import org.apache.fop.afp.AFPResourceInf
 import org.apache.fop.afp.AFPResourceManager;
 import org.apache.fop.afp.AFPUnitConverter;
 import org.apache.fop.afp.svg.AFPBridgeContext;
+import org.apache.fop.afp.svg.AFPFontFamilyResolver;
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.fonts.FontInfo;
 import org.apache.fop.image.loader.batik.BatikUtil;
@@ -53,6 +55,7 @@ import org.apache.fop.render.RendererCon
 import org.apache.fop.render.RendererContext.RendererContextWrapper;
 import org.apache.fop.svg.SVGEventProducer;
 import org.apache.fop.svg.SVGUserAgent;
+import org.apache.fop.svg.font.AggregatingFontFamilyResolver;
 
 /**
  * AFP XML handler for SVG. Uses Apache Batik for SVG processing.
@@ -196,15 +199,13 @@ public class AFPSVGHandler extends Abstr
      */
     public static BridgeContext createBridgeContext(FOUserAgent userAgent, AFPGraphics2D g2d) {
         ImageManager imageManager = userAgent.getImageManager();
-
-        SVGUserAgent svgUserAgent
-            = new SVGUserAgent(userAgent, new AffineTransform());
-
-        ImageSessionContext imageSessionContext = userAgent.getImageSessionContext();
-
         FontInfo fontInfo = g2d.getFontInfo();
+        SVGUserAgent svgUserAgent = new SVGUserAgent(userAgent, new AggregatingFontFamilyResolver(
+                new AFPFontFamilyResolver(fontInfo, userAgent.getEventBroadcaster()), DefaultFontFamilyResolver.SINGLETON),
+                new AffineTransform());
+        ImageSessionContext imageSessionContext = userAgent.getImageSessionContext();
         return new AFPBridgeContext(svgUserAgent, fontInfo, imageManager, imageSessionContext,
-                new AffineTransform(), g2d);
+                new AffineTransform(), g2d, userAgent.getEventBroadcaster());
     }
 
     /** {@inheritDoc} */

Modified: xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java?rev=1508208&r1=1508207&r2=1508208&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java (original)
+++ xmlgraphics/fop/branches/Temp_FopFontsForSVG/src/java/org/apache/fop/render/java2d/CustomFontMetricsMapper.java Mon Jul 29 21:45:20 2013
@@ -21,6 +21,7 @@ package org.apache.fop.render.java2d;
 
 import java.awt.Font;
 import java.awt.FontFormatException;
+import java.awt.Rectangle;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Map;
@@ -183,11 +184,31 @@ public class CustomFontMetricsMapper ext
         return typeface.getWidths();
     }
 
+    public Rectangle getBoundingBox(int glyphIndex, int size) {
+        return typeface.getBoundingBox(glyphIndex, size);
+    }
+
     /** {@inheritDoc} */
     public final int getXHeight(final int size) {
         return typeface.getXHeight(size);
     }
 
+    public int getUnderlinePosition(int size) {
+        return typeface.getUnderlinePosition(size);
+    }
+
+    public int getUnderlineThickness(int size) {
+        return typeface.getUnderlineThickness(size);
+    }
+
+    public int getStrikeoutPosition(int size) {
+        return typeface.getStrikeoutPosition(size);
+    }
+
+    public int getStrikeoutThickness(int size) {
+        return typeface.getStrikeoutThickness(size);
+    }
+
     /** {@inheritDoc} */
     public final boolean hasKerningInfo() {
         return typeface.hasKerningInfo();



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