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 je...@apache.org on 2003/01/08 14:54:05 UTC

cvs commit: xml-fop/src/org/apache/fop/fonts/truetype FontFileReader.java TTFCmapEntry.java TTFDirTabEntry.java TTFFile.java TTFMtxEntry.java TTFSubSetFile.java

jeremias    2003/01/08 05:54:05

  Modified:    src/org/apache/fop/fonts/apps TTFReader.java
  Added:       src/org/apache/fop/fonts BFEntry.java CIDFont.java
                        CIDFontType.java CustomFont.java Font.java
                        FontDescriptor.java FontMetrics.java FontType.java
                        LazyFont.java MultiByteFont.java MutableFont.java
                        SingleByteFont.java package.html
               src/org/apache/fop/fonts/truetype FontFileReader.java
                        TTFCmapEntry.java TTFDirTabEntry.java TTFFile.java
                        TTFMtxEntry.java TTFSubSetFile.java
  Removed:     src/org/apache/fop/fonts FontFileReader.java
                        TTFCmapEntry.java TTFDirTabEntry.java TTFFile.java
                        TTFMtxEntry.java TTFSubSetFile.java
  Log:
  First part of my refactoring of fonts.
  TrueType font classes have moved to subpackage (like Type1 before)
  Lots of Javadocs
  Fixed Checkstyle errors
  
  Revision  Changes    Path
  1.1                  xml-fop/src/org/apache/fop/fonts/BFEntry.java
  
  Index: BFEntry.java
  ===================================================================
  /*
   * $Id: BFEntry.java,v 1.1 2003/01/08 13:54:03 jeremias Exp $
   * Copyright (C) 2001-2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts;
  
  /**
   * This is just a holder class for bfentries.
   */
  public class BFEntry {
      
      private int unicodeStart;
      private int unicodeEnd;
      private int glyphStartIndex;
  
      /**
       * Main constructor.
       * @param unicodeStart Unicode start index
       * @param unicodeEnd Unicode end index
       * @param glyphStartIndex glyph start index
       */
      public BFEntry(int unicodeStart, int unicodeEnd, int glyphStartIndex) {
          this.unicodeStart = unicodeStart;
          this.unicodeEnd = unicodeEnd;
          this.glyphStartIndex = glyphStartIndex;
      }
  
      /**
       * Returns the unicodeStart.
       * @return the Unicode start index
       */
      public int getUnicodeStart() {
          return unicodeStart;
      }
  
      /**
       * Returns the unicodeEnd.
       * @return the Unicode end index
       */
      public int getUnicodeEnd() {
          return unicodeEnd;
      }
  
      /**
       * Returns the glyphStartIndex.
       * @return the glyph start index
       */
      public int getGlyphStartIndex() {
          return glyphStartIndex;
      }
  
  }
  
  
  
  1.1                  xml-fop/src/org/apache/fop/fonts/CIDFont.java
  
  Index: CIDFont.java
  ===================================================================
  /*
   * $Id: CIDFont.java,v 1.1 2003/01/08 13:54:03 jeremias Exp $
   * Copyright (C) 2001-2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts;
  
  /**
   * Abstract base class for CID fonts.
   */
  public abstract class CIDFont extends CustomFont {
  
      // ---- Required ----
      /**
       * Returns the name of the base font.
       * @return the name of the base font
       */
      public abstract String getCidBaseFont();
      
      /**
       * Returns the type of the CID font.
       * @return the type of the CID font
       */
      public abstract CIDFontType getCIDType();
      
      /**
       * Returns the name of the issuer of the font.
       * @return a String identifying an issuer of character collections � 
       * for example, Adobe
       */
      public abstract String getRegistry();
      
      /**
       * Returns a font name for use within a registry.
       * @return a String that uniquely names a character collection issued by 
       * a specific registry � for example, Japan1.
       */
      public abstract String getOrdering();
      
      /**
       * Returns the supplement number of the character collection.
       * @return the supplement number
       */
      public abstract int getSupplement();
      
  
      // ---- Optional ----
      /**
       * Returns the default width for this font.
       * @return the default width
       */
      public int getDefaultWidth() {
          return 0;
      }
  
      /**
       * @see org.apache.fop.fonts.Font#isMultiByte()
       */
      public boolean isMultiByte() {
          return true;
      }
  }
  
  
  
  1.1                  xml-fop/src/org/apache/fop/fonts/CIDFontType.java
  
  Index: CIDFontType.java
  ===================================================================
  /*
   * $Id: CIDFontType.java,v 1.1 2003/01/08 13:54:03 jeremias Exp $
   * Copyright (C) 2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts;
  
  import org.apache.avalon.framework.ValuedEnum;
  
  /**
   * This class enumerates all supported CID font types.
   */
  public class CIDFontType extends ValuedEnum {
  
      /**
       * CID Font Type 0
       */
      public static final CIDFontType CIDTYPE0 = new CIDFontType("CIDFontType0", 0);
  
      /**
       * CID Font Type 2
       */
      public static final CIDFontType CIDTYPE2 = new CIDFontType("CIDFontType2", 1);
  
  
      /**
       * @see org.apache.avalon.framework.Enum#Enum(String)
       */
      protected CIDFontType(String name, int value) {
          super(name, value);
      }
  
  
      /**
       * Returns the CIDFontType by name.
       * @param name Name of the CID font type to look up
       * @return FontType the CID font type
       */
      public static CIDFontType byName(String name) {
          if (name.equalsIgnoreCase(CIDFontType.CIDTYPE0.getName())) {
              return CIDFontType.CIDTYPE0;
          } else if (name.equalsIgnoreCase(CIDFontType.CIDTYPE2.getName())) {
              return CIDFontType.CIDTYPE2;
          } else {
              throw new IllegalArgumentException("Invalid CID font type: " + name);
          }
      }
      
      
      /**
       * Returns the CID FontType by value.
       * @param value Value of the CID font type to look up
       * @return FontType the CID font type
       */
      public static CIDFontType byValue(int value) {
          if (value == CIDFontType.CIDTYPE0.getValue()) {
              return CIDFontType.CIDTYPE0;
          } else if (value == CIDFontType.CIDTYPE2.getValue()) {
              return CIDFontType.CIDTYPE2;
          } else {
              throw new IllegalArgumentException("Invalid CID font type: " + value);
          }
      }
      
  }
  
  
  
  1.1                  xml-fop/src/org/apache/fop/fonts/CustomFont.java
  
  Index: CustomFont.java
  ===================================================================
  /*
   * $Id: CustomFont.java,v 1.1 2003/01/08 13:54:03 jeremias Exp $
   * Copyright (C) 2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts;
  
  import java.util.Map;
  
  
  /**
   * Abstract base class for custom fonts loaded from files, for example.
   */
  public abstract class CustomFont extends Font 
              implements FontDescriptor, MutableFont {
  
      private String fontName = null;
      private String embedFileName = null;
      private String embedResourceName = null;
  
      private int capHeight = 0;
      private int xHeight = 0;
      private int ascender = 0;
      private int descender = 0;
      private int[] fontBBox = {0, 0, 0, 0};
      private int flags = 4;
      private int stemV = 0;
      private int italicAngle = 0;
      private int missingWidth = 0;
      private FontType fontType = FontType.TYPE1;
      private int firstChar = 0;
      private int lastChar = 255;
      
      private Map kerning = new java.util.HashMap();
     
  
      private boolean useKerning = true;
  
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getFontName()
       */
      public String getFontName() {
          return fontName;
      }
  
      /**
       * Returns an URI representing an embeddable font file. The URI will often
       * be a filename or an URL.
       * @return URI to an embeddable font file or null if not available.
       */
      public String getEmbedFileName() {
          return embedFileName;
      }
  
      /**
       * Returns the lookup name to an embeddable font file available as a 
       * resource.
       * @todo Remove this method, this should be done using a resource: URI.
       * @return the lookup name
       */
      public String getEmbedResourceName() {
          return embedResourceName;
      }
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#getAscender()
       */
      public int getAscender() {
          return ascender;
      }
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#getDescender()
       */
      public int getDescender() {
          return descender;
      }
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#getCapHeight()
       */
      public int getCapHeight() {
          return capHeight;
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getAscender(int)
       */
      public int getAscender(int size) {
          return size * ascender;
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getDescender(int)
       */
      public int getDescender(int size) {
          return size * descender;
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getCapHeight(int)
       */
      public int getCapHeight(int size) {
          return size * capHeight;
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getXHeight(int)
       */
      public int getXHeight(int size) {
          return size * xHeight;
      }
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#getFontBBox()
       */
      public int[] getFontBBox() {
          return fontBBox;
      }
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#getFlags()
       */
      public int getFlags() {
          return flags;
      }
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#getStemV()
       */
      public int getStemV() {
          return stemV;
      }
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#getItalicAngle()
       */
      public int getItalicAngle() {
          return italicAngle;
      }
  
      /**
       * Returns the width to be used when no width is available.
       * @return a character width 
       */
      public int getMissingWidth() {
          return missingWidth;
      }
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#getFontType()
       */
      public FontType getFontType() {
          return fontType;
      }
      
      /**
       * Returns the index of the first character defined in this font.
       * @return the index of the first character
       */
      public int getFirstChar() {
          return 0;
          // return firstChar;
          /**@todo Why is this hardcoded??? This code was in SingleByteFont.java */
      }
  
      /**
       * Returns the index of the last character defined in this font.
       * @return the index of the last character
       */
      public int getLastChar() {
          return lastChar;
      }
  
      /**
       * Used to determine if kerning is enabled.
       * @return True if kerning is enabled.
       */
      public boolean isKerningEnabled() {
          return useKerning;
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#hasKerningInfo()
       */
      public final boolean hasKerningInfo() {
          return (isKerningEnabled() & kerning.isEmpty());
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getKerningInfo()
       */
      public final Map getKerningInfo() {
          if (isKerningEnabled()) {
              return kerning;
          } else {
              return java.util.Collections.EMPTY_MAP;
          }
      }
  
  
      /* ---- MutableFont interface ---- */
      
      /**
       * @see org.apache.fop.fonts.MutableFont#setFontName(String)
       */
      public void setFontName(String name) {
          this.fontName = name;
      }
      
      /**
       * @see org.apache.fop.fonts.MutableFont#setEmbedFileName(String)
       */
      public void setEmbedFileName(String path) {
          this.embedFileName = path;
      }
          
      /**
       * @see org.apache.fop.fonts.MutableFont#setEmbedResourceName(String)
       */
      public void setEmbedResourceName(String name) {
          this.embedResourceName = name;
      }
          
      /**
       * @see org.apache.fop.fonts.MutableFont#setCapHeight(int)
       */
      public void setCapHeight(int capHeight) {
          this.capHeight = capHeight;
      }
      
      /**
       * Returns the XHeight value of the font.
       * @param xHeight the XHeight value
       */
      public void setXHeight(int xHeight) {
          this.xHeight = xHeight;
      }
      
      /**
       * @see org.apache.fop.fonts.MutableFont#setAscender(int)
       */
      public void setAscender(int ascender) {
          this.ascender = ascender;
      }
      
      /**
       * @see org.apache.fop.fonts.MutableFont#setDescender(int)
       */
      public void setDescender(int descender) {
          this.descender = descender;
      }
      
      /**
       * @see org.apache.fop.fonts.MutableFont#setFontBBox(int[])
       */
      public void setFontBBox(int[] bbox) {
          this.fontBBox = bbox;
      }
      
      /**
       * @see org.apache.fop.fonts.MutableFont#setFlags(int)
       */
      public void setFlags(int flags) {
          this.flags = flags;
      }
      
      /**
       * @see org.apache.fop.fonts.MutableFont#setStemV(int)
       */
      public void setStemV(int stemV) {
          this.stemV = stemV;
      }
      
      /**
       * @see org.apache.fop.fonts.MutableFont#setItalicAngle(int)
       */
      public void setItalicAngle(int italicAngle) {
          this.italicAngle = italicAngle;
      }
      
      /**
       * @see org.apache.fop.fonts.MutableFont#setMissingWidth(int)
       */
      public void setMissingWidth(int width) {
          this.missingWidth = width;
      }
   
      /**
       * @see org.apache.fop.fonts.MutableFont#setFontType(FontType)
       */
      public void setFontType(FontType fontType) {
          this.fontType = fontType;
      }
  
      /**
       * @see org.apache.fop.fonts.MutableFont#setFirstChar(int)
       */
      public void setFirstChar(int index) {
          this.firstChar = index;
      }
      
      /**
       * @see org.apache.fop.fonts.MutableFont#setLastChar(int)
       */
      public void setLastChar(int index) {
          this.lastChar = index;
      }
      
      /**
       * @see org.apache.fop.fonts.MutableFont#setKerningEnabled(boolean)
       */
      public void setKerningEnabled(boolean enabled) {
          this.useKerning = enabled;
      }
  
      /**
       * @see org.apache.fop.fonts.MutableFont#putKerningEntry(Integer, Map)
       */
      public void putKerningEntry(Integer key, Map value) {
          this.kerning.put(key, value);
      }
  
  }
  
  
  
  1.1                  xml-fop/src/org/apache/fop/fonts/Font.java
  
  Index: Font.java
  ===================================================================
  /*
   * $Id: Font.java,v 1.1 2003/01/08 13:54:03 jeremias Exp $
   * Copyright (C) 2001-2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts;
  
  // FOP
  
  
  /**
   * Base class for PDF font classes
   */
  public abstract class Font implements FontMetrics {
  
      /**
       * Get the encoding of the font.
       * @return the encoding
       */
      public abstract String getEncoding();
  
      /**
       * Map a Unicode character to a code point in the font.
       * @param c character to map
       * @return the mapped character
       */
      public abstract char mapChar(char c);
  
      /**
       * Determines whether the font is a multibyte font.
       * @return True if it is multibyte
       */
      public boolean isMultiByte() {
          return false;
      }
  
  }
  
  
  
  
  1.1                  xml-fop/src/org/apache/fop/fonts/FontDescriptor.java
  
  Index: FontDescriptor.java
  ===================================================================
  /*
   * $Id: FontDescriptor.java,v 1.1 2003/01/08 13:54:03 jeremias Exp $
   * Copyright (C) 2001-2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts;
  
  /**
   * This interface enhances the font metrics interface with access methods to
   * value needed to register fonts in various target formats like PDF or 
   * PostScript.
   */
  public interface FontDescriptor extends FontMetrics {
  
      /**
       * Returns the ascender value of the font. (Ascent in pdf spec)
       * @return the ascender
       */
      int getAscender();
      
      
      /**
       * Returns the capital height of the font.
       * @return the capiptal height
       */
      int getCapHeight();
      
      
      /**
       * Returns the descender value of the font. (Descent in pdf spec)
       * @return the descender value
       */
      int getDescender();
      
      
      /**
       * Returns the flags for the font. (See pdf spec)
       * @return the flags
       */
      int getFlags();
      
      
      /**
       * Returns the font's bounding box.
       * @return the bounding box
       */
      int[] getFontBBox();
      
      
      /**
       * Returns the italic angle for the font.
       * @return the italic angle
       */
      int getItalicAngle();
      
      
      /**
       * Returns the vertical stem width for the font.
       * @return the vertical stem width
       */
      int getStemV();
  
      
      /**
       * Indicates if this font may be embedded.
       * @return True, if embedding is possible/permitted
       */
      boolean isEmbeddable();
      
      
  }
  
  
  
  1.1                  xml-fop/src/org/apache/fop/fonts/FontMetrics.java
  
  Index: FontMetrics.java
  ===================================================================
  /*
   * $Id: FontMetrics.java,v 1.1 2003/01/08 13:54:03 jeremias Exp $
   * Copyright (C) 2001-2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts;
  
  import java.util.Map;
  
  
  /**
   * Main interface for access to font metrics.
   */
  public interface FontMetrics {
  
      /**
       * Returns the font name.
       * @return the font name
       */
      String getFontName();
      
      
      /**
       * Returns the type of the font.
       * @return the font type
       */
      FontType getFontType();
      
  
      /**
       * Returns the ascent of the font described by this
       * FontMetrics object.
       * @param size font size
       * @return ascent in milliponts
       */
      int getAscender(int size);
      
      /**
       * Returns the size of a capital letter measured from the font's baseline.
       * @param size font size
       * @return height of capital characters
       */
      int getCapHeight(int size);
      
      
      /**
       * Returns the descent of the font described by this
       * FontMetrics object.
       * @param size font size
       * @return descent in milliponts
       */
      int getDescender(int size);
      
      
      /**
       * Determines the typical font height of this
       * FontMetrics object
       * @param size font size
       * @return font height in millipoints
       */
      int getXHeight(int size);
  
      /**
       * Return the width (in 1/1000ths of point size) of the character at
       * code point i.
       * @param i code point index
       * @param size font size
       * @return the width of the character
       */
      int getWidth(int i, int size);
  
      /**
       * Return the array of widths.
       * <p>
       * This is used to get an array for inserting in an output format.
       * It should not be used for lookup.
       * @return an array of widths
       */
      int[] getWidths();
      
      /**
       * Indicates if the font has kering information.
       * @return True, if kerning is available.
       */
      boolean hasKerningInfo();
          
      /**
       * Returns the kerning map for the font.
       * @return the kerning map
       */
      Map getKerningInfo();
      
  }
  
  
  
  1.1                  xml-fop/src/org/apache/fop/fonts/FontType.java
  
  Index: FontType.java
  ===================================================================
  /*
   * $Id: FontType.java,v 1.1 2003/01/08 13:54:03 jeremias Exp $
   * Copyright (C) 2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts;
  
  import org.apache.avalon.framework.ValuedEnum;
  
  /**
   * This class enumerates all supported font types.
   */
  public class FontType extends ValuedEnum {
  
      /**
       * Collective identifier for "other" font types
       */
      public static final FontType OTHER       = new FontType("Other", 0);
      /**
       * Adobe Type 0 fonts
       */
      public static final FontType TYPE0       = new FontType("Type0", 1);
      /**
       * Adobe Type 1 fonts
       */
      public static final FontType TYPE1       = new FontType("Type1", 2);
      /**
       * Adobe Multiple Master Type 1 fonts
       */
      public static final FontType MMTYPE1     = new FontType("MMType1", 3);
      /**
       * Adobe Type 3 fonts ("user-defined" fonts)
       */
      public static final FontType TYPE3       = new FontType("Type3", 4);
      /**
       * TrueType fonts
       */
      public static final FontType TRUETYPE    = new FontType("TrueType", 5);
  
  
      /**
       * @see org.apache.avalon.framework.Enum#Enum(String)
       */
      protected FontType(String name, int value) {
          super(name, value);
      }
  
  
      /**
       * Returns the FontType by name.
       * @param name Name of the font type to look up
       * @return the font type
       */
      public static FontType byName(String name) {
          if (name.equalsIgnoreCase(FontType.OTHER.getName())) {
              return FontType.OTHER;
          } else if (name.equalsIgnoreCase(FontType.TYPE0.getName())) {
              return FontType.TYPE0;
          } else if (name.equalsIgnoreCase(FontType.TYPE1.getName())) {
              return FontType.TYPE1;
          } else if (name.equalsIgnoreCase(FontType.MMTYPE1.getName())) {
              return FontType.MMTYPE1;
          } else if (name.equalsIgnoreCase(FontType.TYPE3.getName())) {
              return FontType.TYPE3;
          } else if (name.equalsIgnoreCase(FontType.TRUETYPE.getName())) {
              return FontType.TRUETYPE;
          } else {
              throw new IllegalArgumentException("Invalid font type: " + name);
          }
      }
      
      
      /**
       * Returns the FontType by value.
       * @param value Value of the font type to look up
       * @return the font type
       */
      public static FontType byValue(int value) {
          if (value == FontType.OTHER.getValue()) {
              return FontType.OTHER;
          } else if (value == FontType.TYPE0.getValue()) {
              return FontType.TYPE0;
          } else if (value == FontType.TYPE1.getValue()) {
              return FontType.TYPE1;
          } else if (value == FontType.MMTYPE1.getValue()) {
              return FontType.MMTYPE1;
          } else if (value == FontType.TYPE3.getValue()) {
              return FontType.TYPE3;
          } else if (value == FontType.TRUETYPE.getValue()) {
              return FontType.TRUETYPE;
          } else {
              throw new IllegalArgumentException("Invalid font type: " + value);
          }
      }
      
  }
  
  
  
  1.1                  xml-fop/src/org/apache/fop/fonts/LazyFont.java
  
  Index: LazyFont.java
  ===================================================================
  /*
   * $Id: LazyFont.java,v 1.1 2003/01/08 13:54:03 jeremias Exp $
   * Copyright (C) 2001-2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts;
  
  //Java
  import java.util.Map;
  
  //FOP
  import org.apache.fop.render.pdf.FontReader;
  
  /**
   * This class is used to defer the loading of a font until it is really used.
   */
  public class LazyFont extends Font implements FontDescriptor {
  
      private String metricsFileName = null;
      private String fontEmbedPath = null;
      private boolean useKerning = false;
  
      private boolean isMetricsLoaded = false;
      private Font realFont = null;
      private FontDescriptor realFontDescriptor = null;
  
      /**
       * Main constructor
       * @param fontEmbedPath path to embeddable file (may be null)
       * @param metricsFileName path to the metrics XML file
       * @param useKerning True, if kerning should be enabled
       */
      public LazyFont(String fontEmbedPath, String metricsFileName, boolean useKerning) {
          this.metricsFileName = metricsFileName;
          this.fontEmbedPath = fontEmbedPath;
          this.useKerning = useKerning;
      }
  
      private void load() {
          if (!isMetricsLoaded) {
              isMetricsLoaded = true;
              try {
                  /**@todo Possible thread problem here */
  
                  FontReader reader = new FontReader(metricsFileName);
                  reader.setKerningEnabled(useKerning);
                  reader.setFontEmbedPath(fontEmbedPath);
                  realFont = reader.getFont();
                  if (realFont instanceof FontDescriptor) {
                      realFontDescriptor = (FontDescriptor) realFont;
                  }
                  // System.out.println("Metrics " + metricsFileName + " loaded.");
              } catch (Exception ex) {
                  /**@todo Log this exception */
                  //log.error("Failed to read font metrics file "
                  //                     + metricsFileName
                  //                     + " : " + ex.getMessage());
              }
          }
      }
  
      /**
       * Gets the real font.
       * @return the real font
       */
      public Font getRealFont() {
          load();
          return realFont;
      }
  
      // ---- Font ----
      /**
       * @see org.apache.fop.fonts.Font#getEncoding()
       */
      public String getEncoding() {
          load();
          return realFont.getEncoding();
      }
  
      /**
       * @see org.apache.fonts.pdf.Font#mapChar(char)
       */
      public char mapChar(char c) {
          load();
          return realFont.mapChar(c);
      }
  
      /**
       * @see org.apache.fop.fonts.Font#isMultiByte()
       */
      public boolean isMultiByte() {
          return realFont.isMultiByte();
      }
  
      // ---- FontMetrics interface ----
      /**
       * @see org.apache.fop.fonts.FontMetrics#getFontName()
       */
      public String getFontName() {
          load();
          return realFont.getFontName();
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getAscender(int)
       */
      public int getAscender(int size) {
          load();
          return realFont.getAscender(size);
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getCapHeight(int)
       */
      public int getCapHeight(int size) {
          load();
          return realFont.getCapHeight(size);
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getDescender(int)
       */
      public int getDescender(int size) {
          load();
          return realFont.getDescender(size);
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getXHeight(int)
       */
      public int getXHeight(int size) {
          load();
          return realFont.getXHeight(size);
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getWidth(int, int)
       */
      public int getWidth(int i, int size) {
          load();
          return realFont.getWidth(i, size);
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getWidths()
       */
      public int[] getWidths() {
          load();
          return realFont.getWidths();
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#hasKerningInfo()
       */
      public boolean hasKerningInfo() {
          load();
          return realFont.hasKerningInfo();
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getKerningInfo()
       */
      public Map getKerningInfo() {
          load();
          return realFont.getKerningInfo();
      }
  
      // ---- FontDescriptor interface ----
      /**
       * @see org.apache.fop.fonts.FontDescriptor#getCapHeight()
       */
      public int getCapHeight() {
          load();
          return realFontDescriptor.getCapHeight();
      }
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#getDescender()
       */
      public int getDescender() {
          load();
          return realFontDescriptor.getDescender();
      }
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#getAscender()
       */
      public int getAscender() {
          load();
          return realFontDescriptor.getAscender();
      }
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#getFlags()
       */
      public int getFlags() {
          load();
          return realFontDescriptor.getFlags();
      }
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#getFontBBox()
       */
      public int[] getFontBBox() {
          load();
          return realFontDescriptor.getFontBBox();
      }
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#getItalicAngle()
       */
      public int getItalicAngle() {
          load();
          return realFontDescriptor.getItalicAngle();
      }
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#getStemV()
       */
      public int getStemV() {
          load();
          return realFontDescriptor.getStemV();
      }
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#getFontType()
       */
      public FontType getFontType() {
          load();
          return realFontDescriptor.getFontType();
      }
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#isEmbeddable()
       */
      public boolean isEmbeddable() {
          load();
          return realFontDescriptor.isEmbeddable();
      }
  
  }
  
  
  
  
  1.1                  xml-fop/src/org/apache/fop/fonts/MultiByteFont.java
  
  Index: MultiByteFont.java
  ===================================================================
  /*
   * $Id: MultiByteFont.java,v 1.1 2003/01/08 13:54:03 jeremias Exp $
   * Copyright (C) 2001-2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts;
  
  //Java
  import java.util.Map;
  
  //FOP
  import org.apache.fop.pdf.PDFWArray;
  
  /**
   * Generic MultiByte (CID) font
   */
  public class MultiByteFont extends CIDFont {
  
      private static int uniqueCounter = 1;
  
  
      private String ttcName = null;
      private String encoding = "Identity-H";
  
      private String embedResourceName = null;
  
      private int defaultWidth = 0;
      private CIDFontType cidType = CIDFontType.CIDTYPE2;
  
      private String namePrefix = null;    // Quasi unique prefix
      private PDFWArray warray = new PDFWArray();
      private int width[] = null;
  
      private BFEntry[] bfentries = null;
  
      /**
       * usedGlyphs contains orginal, new glyph index
       */
      private Map usedGlyphs = new java.util.HashMap();
  
      /**
       * usedGlyphsIndex contains new glyph, original index
       */
      private Map usedGlyphsIndex = new java.util.HashMap();
      private int usedGlyphsCount = 0;
  
  
      /**
       * Default constructor
       */
      public MultiByteFont() {
          // Make sure that the 3 first glyphs are included
          usedGlyphs.put(new Integer(0), new Integer(0));
          usedGlyphsIndex.put(new Integer(0), new Integer(0));
          usedGlyphsCount++;
          usedGlyphs.put(new Integer(1), new Integer(1));
          usedGlyphsIndex.put(new Integer(1), new Integer(1));
          usedGlyphsCount++;
          usedGlyphs.put(new Integer(2), new Integer(2));
          usedGlyphsIndex.put(new Integer(2), new Integer(2));
          usedGlyphsCount++;
  
          // Create a quasiunique prefix for fontname
          int cnt = 0;
          synchronized (this.getClass()) {
              cnt = uniqueCounter++;
          }
          int ctm = (int)(System.currentTimeMillis() & 0xffff);
          namePrefix = new String(cnt + "E" + Integer.toHexString(ctm));
          
          setFontType(FontType.TYPE0);
      }
  
      /**
       * @see org.apache.fop.fonts.CIDFont#getDefaultWidth()
       */
      public int getDefaultWidth() {
          return defaultWidth;
      }
  
      /**
       * @see org.apache.fop.fonts.CIDFont#getRegistry()
       */
      public String getRegistry() {
          return "Adobe";
      }
  
      /**
       * @see org.apache.fop.fonts.CIDFont#getOrdering()
       */
      public String getOrdering() {
          return "UCS";
      }
  
      /**
       * @see org.apache.fop.fonts.CIDFont#getSupplement()
       */
      public int getSupplement() {
          return 0;
      }
  
      /**
       * @see org.apache.fop.fonts.CIDFont#getCIDType()
       */
      public CIDFontType getCIDType() {
          return cidType;
      }
      
      /**
       * Sets the CIDType.
       * @param cidType The cidType to set
       */
      public void setCIDType(CIDFontType cidType) {
          this.cidType = cidType;
      }
  
      /**
       * @see org.apache.fop.fonts.CIDFont#getCidBaseFont()
       */
      public String getCidBaseFont() {
          if (isEmbeddable()) {
              return namePrefix + super.getFontName();
          } else {
              return super.getFontName();
          }
      }
  
  /* unused
      public PDFWArray getWidthsAsPDFWArray() {
          if (isEmbeddable()) {
              // Create widths for reencoded chars
              warray = new PDFWArray();
              int[] tmpWidth = new int[usedGlyphsCount];
  
              for (int i = 0; i < usedGlyphsCount; i++) {
                  Integer nw = (Integer)usedGlyphsIndex.get(new Integer(i));
                  int nwx = (nw == null) ? 0 : nw.intValue();
                  tmpWidth[i] = width[nwx];
              }
              warray.addEntry(0, tmpWidth);
          }
          return warray;
      }*/
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#isEmbeddable()
       */
      public boolean isEmbeddable() {
          if (getEmbedFileName() == null 
              && embedResourceName == null) {
              return false;
          } else {
              return true;
              }
      }
  
      /**
       * @see org.apache.fop.fonts.Font#getEncoding()
       */
      public String getEncoding() {
          return encoding;
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getFontName()
       */
      public String getFontName() {
          if (isEmbeddable()) {
              return namePrefix + super.getFontName();
          } else {
              return super.getFontName();
          }
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getWidth(int, int)
       */
      public int getWidth(int i, int size) {
          if (isEmbeddable()) {
              Integer idx = (Integer)usedGlyphsIndex.get(new Integer(i));
              return size * width[idx.intValue()];
          } else {
              return size * width[i];
          }
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getWidths()
       */
      public int[] getWidths() {
          int[] arr = new int[width.length];
          System.arraycopy(width, 0, arr, 0, width.length - 1);
          /*
          for (int i = 0; i < arr.length; i++)
              arr[i] *= size;
          */
          return arr;
      }
  
      /**
       * Remaps a codepoint based.
       * @param i codepoint to remap
       * @return new codepoint
       */
  /* unused
      public Integer reMap(Integer i) {
          if (isEmbeddable()) {
              Integer ret = (Integer)usedGlyphsIndex.get(i);
              if (ret == null) {
                  ret = i;
              }
              return ret;
          } else {
              return i;
          }
  
      }
  */
  
      /**
       * @see org.apache.fop.fonts.Font#mapChar(char)
       */
      public char mapChar(char c) {
          int idx = (int)c;
          int retIdx = 0;
  
          for (int i = 0; (i < bfentries.length) && retIdx == 0; i++) {
              if (bfentries[i].getUnicodeStart() <= idx
                      && bfentries[i].getUnicodeEnd() >= idx) {
                  retIdx = bfentries[i].getGlyphStartIndex() + idx
                           - bfentries[i].getUnicodeStart();
              }
          }
  
          if (isEmbeddable()) {
              // Reencode to a new subset font or get
              // the reencoded value
              Integer newIdx = (Integer)usedGlyphs.get(new Integer(retIdx));
              if (newIdx == null) {
                  usedGlyphs.put(new Integer(retIdx),
                                 new Integer(usedGlyphsCount));
                  usedGlyphsIndex.put(new Integer(usedGlyphsCount),
                                      new Integer(retIdx));
                  retIdx = usedGlyphsCount;
                  // System.out.println(c+"("+(int)c+") = "+retIdx);
                  usedGlyphsCount++;
              } else {
                  retIdx = newIdx.intValue();
              }
          }
  
          return (char)retIdx;
      }
  
      /**
       * Sets the bfentries.
       * @param bfentries The bfentries to set
       */
      public void setBFEntries(BFEntry[] bfentries) {
          this.bfentries = bfentries;
      }
  
      /**
       * Sets the defaultWidth.
       * @param defaultWidth The defaultWidth to set
       */
      public void setDefaultWidth(int defaultWidth) {
          this.defaultWidth = defaultWidth;
      }
  
      /**
       * Returns the TrueType Collection Name.
       * @return the TrueType Collection Name
       */
      public String getTTCName() {
          return ttcName;
      }
  
      /**
       * Sets the the TrueType Collection Name.
       * @param ttcName the TrueType Collection Name
       */
      public void setTTCName(String ttcName) {
          this.ttcName = ttcName;
      }
  
      /**
       * Adds a new CID width entry to the font.
       * @param cidWidthIndex index
       * @param wds array of widths
       */
      public void addCIDWidthEntry(int cidWidthIndex, int[] wds) {
          this.warray.addEntry(cidWidthIndex, wds);
      }
  
  
      /**
       * Sets the width array.
       * @param wds array of widths.
       */
      public void setWidthArray(int[] wds) {
          this.width = wds;
      }
  
      /**
       * Returns a Map of used Glyphs.
       * @return Map Map of used Glyphs
       */
      public Map getUsedGlyphs() {
          return usedGlyphs;
      }
  
  }
  
  
  
  
  1.1                  xml-fop/src/org/apache/fop/fonts/MutableFont.java
  
  Index: MutableFont.java
  ===================================================================
  /*
   * $Id: MutableFont.java,v 1.1 2003/01/08 13:54:03 jeremias Exp $
   * Copyright (C) 2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts;
  
  import java.util.Map;
  
  
  /**
   * This interface is used to set the values of a font during configuration time.
   */
  public interface MutableFont {
  
      /**
       * Sets the font name.
       * @param name font name
       */
      void setFontName(String name);
      
      /**
       * Sets the path to the embeddable font file.
       * @param path URI to the file
       */
      void setEmbedFileName(String path);
  
      /**
       * Sets the resource name of the embeddable font file.
       * @param name resource name
       */
      void setEmbedResourceName(String name);
  
      /**
       * Sets the capital height value.
       * @param capHeight capital height
       */
      void setCapHeight(int capHeight);
      
      /**
       * Sets the ascent value.
       * @param ascender ascent height
       */
      void setAscender(int ascender);
      
      /**
       * Sets the descent value.
       * @param descender descent value
       */
      void setDescender(int descender);
  
      /**
       * Sets the font's bounding box
       * @param bbox bounding box
       */
      void setFontBBox(int[] bbox);
  
      /**
       * Sets the font's flags
       * @param flags flags
       */
      void setFlags(int flags);
      
      /**
       * Sets the font's StemV value.
       * @param stemV StemV
       */
      void setStemV(int stemV);
      
      /**
       * Sets the font's italic angle.
       * @param italicAngle italic angle
       */
      void setItalicAngle(int italicAngle);
      
      /**
       * Sets the font's default width
       * @param width default width
       */
      void setMissingWidth(int width);
   
      /**
       * Sets the font type.
       * @param fontType font type
       */
      void setFontType(FontType fontType);
   
      /**
       * Sets the index of the first character in the character table.
       * @param index index of first character
       */
      void setFirstChar(int index);
      
      /**
       * Sets the index of the last character in the character table.
       * @param index index of the last character
       */
      void setLastChar(int index);
      
      /**
       * Enables/disabled kerning.
       * @param enabled True if kerning should be enabled if available
       */
      void setKerningEnabled(boolean enabled);
      
      /**
       * Adds an entry to the kerning table.
       * @param key Kerning key
       * @param value Kerning value
       */
      void putKerningEntry(Integer key, Map value);
         
  }
  
  
  
  1.1                  xml-fop/src/org/apache/fop/fonts/SingleByteFont.java
  
  Index: SingleByteFont.java
  ===================================================================
  /*
   * $Id: SingleByteFont.java,v 1.1 2003/01/08 13:54:03 jeremias Exp $
   * Copyright (C) 2001-2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts;
  
  /**
   * Generic SingleByte font
   */
  public class SingleByteFont extends CustomFont {
      
      private final CodePointMapping mapping
          = CodePointMapping.getMapping("WinAnsiEncoding");
  
      private String encoding = "WinAnsiEncoding";
  
      private int width[] = null;
  
  
      /**
       * @see org.apache.fop.fonts.FontDescriptor#isEmbeddable()
       */
      public boolean isEmbeddable() {
          return (getEmbedFileName() == null && getEmbedResourceName() == null) ? false
                 : true;
      }
  
      /**
       * @see org.apache.fop.fonts.Font#getEncoding()
       */
      public String getEncoding() {
          return encoding;
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getWidth(int, int)
       */
      public int getWidth(int i, int size) {
          return size * width[i];
      }
  
      /**
       * @see org.apache.fop.fonts.FontMetrics#getWidths()
       */
      public int[] getWidths() {
          int[] arr = new int[width.length];
          System.arraycopy(width, 0, arr, 0, width.length - 1);
          /*
          for (int i = 0; i < arr.length; i++)
              arr[i] *= size;
          */
          return arr;
      }
  
      /**
       * @see org.apache.fop.fonts.Font#mapChar(char)
       */
      public char mapChar(char c) {
          char d = mapping.mapChar(c);
          if (d != 0) {
              return d;
          } else {
              return '#';
          }
      }
      
      /* ---- single byte font specific setters --- */
  
      /**
       * Sets a width for a character.
       * @param index index of the character
       * @param width the width of the character
       */
      public void setWidth(int index, int width) {
          if (this.width == null) {
              this.width = new int[256];
          }
          this.width[index] = width;
      }
      
  }
  
  
  
  
  1.2       +6 -0      xml-fop/src/org/apache/fop/fonts/package.html
  
  
  
  
  1.11      +4 -4      xml-fop/src/org/apache/fop/fonts/apps/TTFReader.java
  
  Index: TTFReader.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/org/apache/fop/fonts/apps/TTFReader.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- TTFReader.java	2 Dec 2002 14:27:58 -0000	1.10
  +++ TTFReader.java	8 Jan 2003 13:54:04 -0000	1.11
  @@ -25,9 +25,9 @@
   import org.apache.avalon.framework.logger.Logger;
   
   //FOP
  -import org.apache.fop.fonts.FontFileReader;
  -import org.apache.fop.fonts.TTFCmapEntry;
  -import org.apache.fop.fonts.TTFFile;
  +import org.apache.fop.fonts.truetype.FontFileReader;
  +import org.apache.fop.fonts.truetype.TTFCmapEntry;
  +import org.apache.fop.fonts.truetype.TTFFile;
   
   /**
    * A tool which reads TTF files and generates
  
  
  
  1.1                  xml-fop/src/org/apache/fop/fonts/truetype/FontFileReader.java
  
  Index: FontFileReader.java
  ===================================================================
  /*
   * $Id: FontFileReader.java,v 1.1 2003/01/08 13:54:04 jeremias Exp $
   * Copyright (C) 2001-2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts.truetype;
  
  import java.io.InputStream;
  import java.io.File;
  import java.io.IOException;
  
  import org.apache.fop.util.StreamUtilities;
  
  /**
   * Reads a TrueType font file into a byte array and
   * provides file like functions for array access.
   */
  public class FontFileReader {
  
      private int fsize;      // file size
      private int current;    // current position in file
      private byte[] file;
  
      /**
       * Initializes class and reads stream. Init does not close stream.
       *
       * @param in InputStream to read from new array with size + inc
       * @throws IOException In case of an I/O problem
       */
      private void init(InputStream in) throws java.io.IOException {
          java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream();
          try {
              StreamUtilities.streamCopy(in, bout);
              this.file = bout.toByteArray();
              this.fsize = this.file.length;
              this.current = 0;
          } finally {
              bout.close();
          }
      }
  
      /**
       * Constructor
       *
       * @param fileName filename to read
       * @throws IOException In case of an I/O problem
       */
      public FontFileReader(String fileName) throws IOException {
          final File f = new File(fileName);
          InputStream in = new java.io.FileInputStream(f);
          try {
              init(in);
          } finally {
              in.close();
          }
      }
  
  
      /**
       * Constructor
       *
       * @param in InputStream to read from
       * @throws IOException In case of an I/O problem
       */
      public FontFileReader(InputStream in) throws IOException {
          init(in);
      }
  
  
      /**
       * Set current file position to offset
       *
       * @param offset The new offset to set
       * @throws IOException In case of an I/O problem
       */
      public void seekSet(long offset) throws IOException {
          if (offset > fsize || offset < 0) {
              throw new java.io.EOFException("Reached EOF, file size=" + fsize
                                             + " offset=" + offset);
          }
          current = (int)offset;
      }
  
      /**
       * Set current file position to offset
       *
       * @param add The number of bytes to advance
       * @throws IOException In case of an I/O problem
       */
      public void seekAdd(long add) throws IOException {
          seekSet(current + add);
      }
  
      /**
       * Skip a given number of bytes.
       *
       * @param add The number of bytes to advance
       * @throws IOException In case of an I/O problem
       */
      public void skip(long add) throws IOException {
          seekAdd(add);
      }
  
      /**
       * Returns current file position.
       *
       * @return int The current position.
       */
      public int getCurrentPos() {
          return current;
      }
  
      /**
       * Returns the size of the file.
       *
       * @return int The filesize
       */
      public int getFileSize() {
          return fsize;
      }
  
      /**
       * Read 1 byte.
       *
       * @return One byte
       * @throws IOException If EOF is reached
       */
      public byte read() throws IOException {
          if (current > fsize) {
              throw new java.io.EOFException("Reached EOF, file size=" + fsize);
          }
  
          final byte ret = file[current++];
          return ret;
      }
  
      /**
       * Read 1 signed byte.
       *
       * @return One byte
       * @throws IOException If EOF is reached
       */
      public final byte readTTFByte() throws IOException {
          return read();
      }
  
      /**
       * Read 1 unsigned byte.
       *
       * @return One unsigned byte
       * @throws IOException If EOF is reached
       */
      public final int readTTFUByte() throws IOException {
          final byte buf = read();
  
          if (buf < 0) {
              return (int)(256 + buf);
          } else {
              return (int)buf;
          }
      }
  
      /**
       * Read 2 bytes signed.
       *
       * @return One signed short
       * @throws IOException If EOF is reached
       */
      public final short readTTFShort() throws IOException {
          final int ret = (readTTFUByte() << 8) + readTTFUByte();
          final short sret = (short)ret;
          return sret;
      }
  
      /**
       * Read 2 bytes unsigned.
       *
       * @return One unsigned short
       * @throws IOException If EOF is reached
       */
      public final int readTTFUShort() throws IOException {
          final int ret = (readTTFUByte() << 8) + readTTFUByte();
          return (int)ret;
      }
  
      /**
       * Write a USHort at a given position.
       *
       * @param pos The absolute position to write to
       * @param val The value to write
       * @throws IOException If EOF is reached
       */
      public final void writeTTFUShort(int pos, int val) throws IOException {
          if ((pos + 2) > fsize) {
              throw new java.io.EOFException("Reached EOF");
          }
          final byte b1 = (byte)((val >> 8) & 0xff);
          final byte b2 = (byte)(val & 0xff);
          file[pos] = b1;
          file[pos + 1] = b2;
      }
  
      /**
       * Read 2 bytes signed at position pos without changing current position.
       *
       * @param pos The absolute position to read from
       * @return One signed short
       * @throws IOException If EOF is reached
       */
      public final short readTTFShort(long pos) throws IOException {
          final long cp = getCurrentPos();
          seekSet(pos);
          final short ret = readTTFShort();
          seekSet(cp);
          return ret;
      }
  
      /**
       * Read 2 bytes unsigned at position pos without changing current position.
       *
       * @param pos The absolute position to read from
       * @return One unsigned short
       * @throws IOException If EOF is reached
       */
      public final int readTTFUShort(long pos) throws IOException {
          long cp = getCurrentPos();
          seekSet(pos);
          int ret = readTTFUShort();
          seekSet(cp);
          return ret;
      }
  
      /**
       * Read 4 bytes.
       *
       * @return One signed integer
       * @throws IOException If EOF is reached
       */
      public final int readTTFLong() throws IOException {
          long ret = readTTFUByte();    // << 8;
          ret = (ret << 8) + readTTFUByte();
          ret = (ret << 8) + readTTFUByte();
          ret = (ret << 8) + readTTFUByte();
  
          return (int)ret;
      }
  
      /**
       * Read 4 bytes.
       *
       * @return One unsigned integer
       * @throws IOException If EOF is reached
       */
      public final long readTTFULong() throws IOException {
          long ret = readTTFUByte();
          ret = (ret << 8) + readTTFUByte();
          ret = (ret << 8) + readTTFUByte();
          ret = (ret << 8) + readTTFUByte();
  
          return ret;
      }
  
      /**
       * Read a NUL terminated ISO-8859-1 string.
       *
       * @return A String
       * @throws IOException If EOF is reached
       */
      public final String readTTFString() throws IOException {
          int i = current;
          while (file[i++] != 0) {
              if (i > fsize) {
                  throw new java.io.EOFException("Reached EOF, file size="
                                                 + fsize);
              }
          }
  
          byte[] tmp = new byte[i - current];
          System.arraycopy(file, current, tmp, 0, i - current);
          return new String(tmp, "ISO-8859-1");
      }
  
  
      /**
       * Read an ISO-8859-1 string of len bytes.
       *
       * @param len The length of the string to read
       * @return A String
       * @throws IOException If EOF is reached
       */
      public final String readTTFString(int len) throws IOException {
          if ((len + current) > fsize) {
              throw new java.io.EOFException("Reached EOF, file size=" + fsize);
          }
  
          byte[] tmp = new byte[len];
          System.arraycopy(file, current, tmp, 0, len);
          current += len;
          return new String(tmp, "ISO-8859-1");
      }
  
      /**
       * Return a copy of the internal array
       *
       * @param offset The absolute offset to start reading from
       * @param length The number of bytes to read
       * @return An array of bytes
       * @throws IOException if out of bounds
       */
      public byte[] getBytes(int offset,
                             int length) throws IOException {
          if ((offset + length) > fsize) {
              throw new java.io.IOException("Reached EOF");
          }
  
          byte[] ret = new byte[length];
          System.arraycopy(file, offset, ret, 0, length);
          return ret;
      }
  
  
  }
  
  
  1.1                  xml-fop/src/org/apache/fop/fonts/truetype/TTFCmapEntry.java
  
  Index: TTFCmapEntry.java
  ===================================================================
  /*
   * $Id: TTFCmapEntry.java,v 1.1 2003/01/08 13:54:04 jeremias Exp $
   * Copyright (C) 2001-2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts.truetype;
  
  /**
   * The CMap entry contains information of a Unicode range and the
   * the glyph indexes related to the range
   */
  public class TTFCmapEntry {
  
      private int unicodeStart;
      private int unicodeEnd;
      private int glyphStartIndex;
  
      TTFCmapEntry() {
          unicodeStart = 0;
          unicodeEnd = 0;
          glyphStartIndex = 0;
      }
  
      TTFCmapEntry(int unicodeStart, int unicodeEnd, int glyphStartIndex) {
          this.unicodeStart = unicodeStart;
          this.unicodeEnd = unicodeEnd;
          this.glyphStartIndex = glyphStartIndex;
      }
  
      /**
       * @see java.lang.Object#equals(Object)
       */
      public boolean equals(Object o) {
          if (o instanceof TTFCmapEntry) {
              TTFCmapEntry ce = (TTFCmapEntry)o;
              if (ce.unicodeStart == this.unicodeStart
                      && ce.unicodeEnd == this.unicodeEnd
                      && ce.glyphStartIndex == this.glyphStartIndex) {
                  return true;
              }
          }
          return false;
      }
  
      /**
       * Returns the glyphStartIndex.
       * @return int
       */
      public int getGlyphStartIndex() {
          return glyphStartIndex;
      }
  
      /**
       * Returns the unicodeEnd.
       * @return int
       */
      public int getUnicodeEnd() {
          return unicodeEnd;
      }
  
      /**
       * Returns the unicodeStart.
       * @return int
       */
      public int getUnicodeStart() {
          return unicodeStart;
      }
  
      /**
       * Sets the glyphStartIndex.
       * @param glyphStartIndex The glyphStartIndex to set
       */
      public void setGlyphStartIndex(int glyphStartIndex) {
          this.glyphStartIndex = glyphStartIndex;
      }
  
      /**
       * Sets the unicodeEnd.
       * @param unicodeEnd The unicodeEnd to set
       */
      public void setUnicodeEnd(int unicodeEnd) {
          this.unicodeEnd = unicodeEnd;
      }
  
      /**
       * Sets the unicodeStart.
       * @param unicodeStart The unicodeStart to set
       */
      public void setUnicodeStart(int unicodeStart) {
          this.unicodeStart = unicodeStart;
      }
  
  }
  
  
  
  1.1                  xml-fop/src/org/apache/fop/fonts/truetype/TTFDirTabEntry.java
  
  Index: TTFDirTabEntry.java
  ===================================================================
  /*
   * $Id: TTFDirTabEntry.java,v 1.1 2003/01/08 13:54:04 jeremias Exp $
   * Copyright (C) 2001-2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts.truetype;
  
  import java.io.IOException;
  
  
  /**
   * This class represents an entry to a TrueType font's Dir Tab.
   */
  class TTFDirTabEntry {
  
      private byte[] tag = new byte[4];
      private int checksum;
      private long offset;
      private long length;
  
      /**
       * Read Dir Tab, return tag name
       */
      public String read(FontFileReader in) throws IOException {
          tag[0] = in.readTTFByte();
          tag[1] = in.readTTFByte();
          tag[2] = in.readTTFByte();
          tag[3] = in.readTTFByte();
  
          in.skip(4);    // Skip checksum
  
          offset = in.readTTFULong();
          length = in.readTTFULong();
  
          //System.out.println(this.toString());
          return new String(tag, "ISO-8859-1");
      }
  
  
      public String toString() {
          return "Read dir tab ["
              + tag[0] + " " + tag[1] + " " + tag[2] + " " + tag[3] + "]"
              + " offset: " + offset
              + " length: " + length
              + " name: " + tag;
      }
  
      /**
       * Returns the checksum.
       * @return int
       */
      public int getChecksum() {
          return checksum;
      }
  
      /**
       * Returns the length.
       * @return long
       */
      public long getLength() {
          return length;
      }
  
      /**
       * Returns the offset.
       * @return long
       */
      public long getOffset() {
          return offset;
      }
  
      /**
       * Returns the tag.
       * @return byte[]
       */
      public byte[] getTag() {
          return tag;
      }
  
  }
  
  
  
  1.1                  xml-fop/src/org/apache/fop/fonts/truetype/TTFFile.java
  
  Index: TTFFile.java
  ===================================================================
  /*
   * $Id: TTFFile.java,v 1.1 2003/01/08 13:54:04 jeremias Exp $
   * Copyright (C) 2001-2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts.truetype;
  
  import java.io.IOException;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.List;
  
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.logger.ConsoleLogger;
  import org.apache.avalon.framework.logger.Logger;
  import org.apache.fop.fonts.Glyphs;
  
  /**
   * Reads a TrueType file or a TrueType Collection.
   * The TrueType spec can be found at the Microsoft.
   * Typography site: http://www.microsoft.com/truetype/
   */
  public class TTFFile extends AbstractLogEnabled {
  
      static final byte NTABS = 24;
      static final int NMACGLYPHS = 258;
      static final int MAX_CHAR_CODE = 255;
      static final int ENC_BUF_SIZE = 1024;
  
      private String encoding = "WinAnsiEncoding";    // Default encoding
  
      private short firstChar = 0;
      private boolean isEmbeddable = true;
      private boolean hasSerifs = true;
      /**
       * Table directory
       */
      protected Map dirTabs;
      private Map kerningTab;                          // for CIDs
      private Map ansiKerningTab;                      // For winAnsiEncoding
      private List cmaps;
      private List unicodeMapping;
  
      private int upem;                                // unitsPerEm from "head" table
      private int nhmtx;                               // Number of horizontal metrics
      private int postFormat;
      private int locaFormat;
      /**
       * Offset to last loca
       */
      protected long lastLoca = 0;
      private int numberOfGlyphs; // Number of glyphs in font (read from "maxp" table)
      private int nmGlyphs;                            // Used in fixWidths - remove?
  
      /**
       * Contains glyph data
       */
      protected TTFMtxEntry mtxTab[];                  // Contains glyph data
      private int[] mtxEncoded = null;
  
      private String fontName = "";
      private String fullName = "";
      private String notice = "";
      private String familyName = "";
      private String subFamilyName = "";
  
      private long italicAngle = 0;
      private long isFixedPitch = 0;
      private int fontBBox1 = 0;
      private int fontBBox2 = 0;
      private int fontBBox3 = 0;
      private int fontBBox4 = 0;
      private int capHeight = 0;
      private int underlinePosition = 0;
      private int underlineThickness = 0;
      private int xHeight = 0;
      private int ascender = 0;
      private int descender = 0;
  
      private short lastChar = 0;
  
      private int ansiWidth[];
      private Map ansiIndex;
  
      /**
       * Position inputstream to position indicated
       * in the dirtab offset + offset
       */
      void seekTab(FontFileReader in, String name,
                    long offset) throws IOException {
          TTFDirTabEntry dt = (TTFDirTabEntry)dirTabs.get(name);
          if (dt == null) {
              getLogger().error("Dirtab " + name + " not found.");
              return;
          }
  
          in.seekSet(dt.getOffset() + offset);
      }
  
      /**
       * Convert from truetype unit to pdf unit based on the
       * unitsPerEm field in the "head" table
       * @param n truetype unit
       * @return pdf unit
       */
      public int convertTTFUnit2PDFUnit(int n) {
          int ret;
          if (n < 0) {
              long rest1 = n % upem;
              long storrest = 1000 * rest1;
              long ledd2 = rest1 / storrest;
              ret = -((-1000 * n) / upem - (int)ledd2);
          } else {
              ret = (n / upem) * 1000 + ((n % upem) * 1000) / upem;
          }
  
          return ret;
      }
  
      /**
       * Read the cmap table,
       * return false if the table is not present or only unsupported
       * tables are present. Currently only unicode cmaps are supported.
       * Set the unicodeIndex in the TTFMtxEntries and fills in the
       * cmaps vector.
       */
      private boolean readCMAP(FontFileReader in) throws IOException {
  
          unicodeMapping = new java.util.ArrayList();
  
          //Read CMAP table and correct mtxTab.index
          int mtxPtr = 0;
  
          seekTab(in, "cmap", 2);
          int numCMap = in.readTTFUShort();    // Number of cmap subtables
          long cmapUniOffset = 0;
  
          getLogger().info(numCMap + " cmap tables");
  
          //Read offset for all tables. We are only interested in the unicode table
          for (int i = 0; i < numCMap; i++) {
              int cmapPID = in.readTTFUShort();
              int cmapEID = in.readTTFUShort();
              long cmapOffset = in.readTTFULong();
  
              getLogger().debug("Platform ID: " + cmapPID
                  + " Encoding: " + cmapEID);
  
              if (cmapPID == 3 && cmapEID == 1) {
                  cmapUniOffset = cmapOffset;
              }
          }
  
          if (cmapUniOffset <= 0) {
              getLogger().fatalError("Unicode cmap table not present");
              getLogger().fatalError("Unsupported format: Aborting");
              return false;
          }
  
          // Read unicode cmap
          seekTab(in, "cmap", cmapUniOffset);
          int cmapFormat = in.readTTFUShort();
          /*int cmap_length =*/ in.readTTFUShort(); //skip cmap length
  
          getLogger().info("CMAP format: " + cmapFormat);
          if (cmapFormat == 4) {
              in.skip(2);    // Skip version number
              int cmapSegCountX2 = in.readTTFUShort();
              int cmapSearchRange = in.readTTFUShort();
              int cmapEntrySelector = in.readTTFUShort();
              int cmapRangeShift = in.readTTFUShort();
  
              getLogger().debug("segCountX2   : " + cmapSegCountX2);
              getLogger().debug("searchRange  : " + cmapSearchRange);
              getLogger().debug("entrySelector: " + cmapEntrySelector);
              getLogger().debug("rangeShift   : " + cmapRangeShift);
  
  
              int cmapEndCounts[] = new int[cmapSegCountX2 / 2];
              int cmapStartCounts[] = new int[cmapSegCountX2 / 2];
              int cmapDeltas[] = new int[cmapSegCountX2 / 2];
              int cmapRangeOffsets[] = new int[cmapSegCountX2 / 2];
  
              for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
                  cmapEndCounts[i] = in.readTTFUShort();
              }
  
              in.skip(2);    // Skip reservedPad
  
              for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
                  cmapStartCounts[i] = in.readTTFUShort();
              }
  
              for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
                  cmapDeltas[i] = in.readTTFShort();
              }
  
              //int startRangeOffset = in.getCurrentPos();
  
              for (int i = 0; i < (cmapSegCountX2 / 2); i++) {
                  cmapRangeOffsets[i] = in.readTTFUShort();
              }
  
              int glyphIdArrayOffset = in.getCurrentPos();
  
              // Insert the unicode id for the glyphs in mtxTab
              // and fill in the cmaps ArrayList
  
              for (int i = 0; i < cmapStartCounts.length; i++) {
  
                  getLogger().debug(i + ": " + cmapStartCounts[i]
                      + " - " + cmapEndCounts[i]);
  
                  for (int j = cmapStartCounts[i]; j <= cmapEndCounts[i]; j++) {
  
                      // Update lastChar
                      if (j < 256 && j > lastChar) {
                          lastChar = (short)j;
                      }
  
                      if (mtxPtr < mtxTab.length) {
                          int glyphIdx;
                          // the last character 65535 = .notdef
                          // may have a range offset
                          if (cmapRangeOffsets[i] != 0 && j != 65535) {
                              int glyphOffset = glyphIdArrayOffset
                                  + ((cmapRangeOffsets[i] / 2)
                                      + (j - cmapStartCounts[i])
                                      + (i)
                                      - cmapSegCountX2 / 2) * 2;
                              in.seekSet(glyphOffset);
                              glyphIdx = (in.readTTFUShort() + cmapDeltas[i])
                                         & 0xffff;
  
                              unicodeMapping.add(new UnicodeMapping(glyphIdx, j));
                              mtxTab[glyphIdx].getUnicodeIndex().add(new Integer(j));
  
  
                              // Also add winAnsiWidth
                              List v = (List)ansiIndex.get(new Integer(j));
                              if (v != null) {
                                  Iterator e = v.listIterator();
                                  while (e.hasNext()) {
                                      Integer aIdx = (Integer)e.next();
                                      ansiWidth[aIdx.intValue()] =
                                          mtxTab[glyphIdx].getWx();
  
                                      getLogger().debug("Added width "
                                          + mtxTab[glyphIdx].getWx()
                                          + " uni: " + j
                                          + " ansi: " + aIdx.intValue());
                                  }
                              }
  
                              getLogger().debug("Idx: "
                                  + glyphIdx
                                  + " Delta: " + cmapDeltas[i]
                                  + " Unicode: " + j
                                  + " name: " + mtxTab[glyphIdx].getName());
                          } else {
                              glyphIdx = (j + cmapDeltas[i]) & 0xffff;
  
                              if (glyphIdx < mtxTab.length) {
                                  mtxTab[glyphIdx].getUnicodeIndex().add(new Integer(j));
                              } else {
                                  getLogger().debug("Glyph " + glyphIdx
                                                     + " out of range: "
                                                     + mtxTab.length);
                              }
  
                              unicodeMapping.add(new UnicodeMapping(glyphIdx, j));
                              if (glyphIdx < mtxTab.length) {
                                  mtxTab[glyphIdx].getUnicodeIndex().add(new Integer(j));
                              } else {
                                  getLogger().debug("Glyph " + glyphIdx
                                                     + " out of range: "
                                                     + mtxTab.length);
                              }
  
                              // Also add winAnsiWidth
                              List v = (List)ansiIndex.get(new Integer(j));
                              if (v != null) {
                                  Iterator e = v.listIterator();
                                  while (e.hasNext()) {
                                      Integer aIdx = (Integer)e.next();
                                      ansiWidth[aIdx.intValue()] = mtxTab[glyphIdx].getWx();
                                  }
                              }
  
                              //getLogger().debug("IIdx: " +
                              //    mtxPtr +
                              //    " Delta: " + cmap_deltas[i] +
                              //    " Unicode: " + j +
                              //    " name: " +
                              //    mtxTab[(j+cmap_deltas[i]) & 0xffff].name);
  
                          }
                          if (glyphIdx < mtxTab.length) {
                              if (mtxTab[glyphIdx].getUnicodeIndex().size() < 2) {
                                  mtxPtr++;
                              }
                          }
                      }
                  }
              }
          }
          return true;
      }
  
      /**
       * Print first char/last char
       */
      private void printMaxMin() {
          int min = 255;
          int max = 0;
          for (int i = 0; i < mtxTab.length; i++) {
              if (mtxTab[i].getIndex() < min) {
                  min = mtxTab[i].getIndex();
              }
              if (mtxTab[i].getIndex() > max) {
                  max = mtxTab[i].getIndex();
              }
          }
          getLogger().info("Min: " + min);
          getLogger().info("Max: " + max);
      }
  
  
      /**
       * Reads the font using a FontFileReader.
       *
       * @param in The FontFileReader to use
       * @throws IOException In case of an I/O problem
       */
      public void readFont(FontFileReader in) throws IOException {
          readFont(in, (String)null);
      }
  
      /**
       * initialize the ansiWidths array (for winAnsiEncoding)
       * and fill with the missingwidth
       */
      private void initAnsiWidths() {
          ansiWidth = new int[256];
          for (int i = 0; i < 256; i++) {
              ansiWidth[i] = mtxTab[0].getWx();
          }
  
          // Create an index hash to the ansiWidth
          // Can't just index the winAnsiEncoding when inserting widths
          // same char (eg bullet) is repeated more than one place
          ansiIndex = new java.util.HashMap();
          for (int i = 32; i < Glyphs.WINANSI_ENCODING.length; i++) {
              Integer ansi = new Integer(i);
              Integer uni = new Integer((int)Glyphs.WINANSI_ENCODING[i]);
  
              List v = (List)ansiIndex.get(uni);
              if (v == null) {
                  v = new java.util.ArrayList();
                  ansiIndex.put(uni, v);
              }
              v.add(ansi);
          }
      }
  
      /**
       * Read the font data.
       * If the fontfile is a TrueType Collection (.ttc file)
       * the name of the font to read data for must be supplied,
       * else the name is ignored.
       *
       * @param in The FontFileReader to use
       * @param name The name of the font
       * @return boolean Returns true if the font is valid
       * @throws IOException In case of an I/O problem
       */
      public boolean readFont(FontFileReader in, String name) throws IOException {
  
          /*
           * Check if TrueType collection, and that the name
           * exists in the collection
           */
          if (!checkTTC(in, name)) {
              throw new IOException("Failed to read font");
          }
  
          readDirTabs(in);
          readFontHeader(in);
          getNumGlyphs(in);
          getLogger().info("Number of glyphs in font: " + numberOfGlyphs);
          readHorizontalHeader(in);
          readHorizontalMetrics(in);
          initAnsiWidths();
          readPostscript(in);
          readOS2(in);
          readIndexToLocation(in);
          readGlyf(in);
          readName(in);
          readPCLT(in);
          // Read cmap table and fill in ansiwidths
          boolean valid = readCMAP(in);
          if (!valid) {
              return false;
          }
          // Create cmaps for bfentries
          createCMaps();
          // print_max_min();
  
          readKerning(in);
          return true;
      }
  
      private void createCMaps() {
          cmaps = new java.util.ArrayList();
          TTFCmapEntry tce = new TTFCmapEntry();
  
          Iterator e = unicodeMapping.listIterator();
          UnicodeMapping um = (UnicodeMapping)e.next();
          UnicodeMapping lastMapping = um;
  
          tce.setUnicodeStart(um.getUIdx());
          tce.setGlyphStartIndex(um.getGIdx());
  
          while (e.hasNext()) {
              um = (UnicodeMapping)e.next();
              if (((lastMapping.getUIdx() + 1) != um.getUIdx())
                      || ((lastMapping.getGIdx() + 1) != um.getGIdx())) {
                  tce.setUnicodeEnd(lastMapping.getUIdx());
                  cmaps.add(tce);
  
                  tce = new TTFCmapEntry();
                  tce.setUnicodeStart(um.getUIdx());
                  tce.setGlyphStartIndex(um.getGIdx());
              }
              lastMapping = um;
          }
  
          tce.setUnicodeEnd(um.getUIdx());
          cmaps.add(tce);
      }
  
      /**
       * Returns the Windows name of the font.
       * @return String The Windows name
       */
      public String getWindowsName() {
          return familyName + "," + subFamilyName;
      }
  
      /**
       * Returns the PostScript name of the font.
       * @return String The PostScript name
       */
      public String getPostscriptName() {
          if ("Regular".equals(subFamilyName) || "Roman".equals(subFamilyName)) {
              return familyName;
          } else {
              return familyName + "," + subFamilyName;
          }
      }
  
      /**
       * Returns the font family name of the font.
       * @return String The family name
       */
      public String getFamilyName() {
          return familyName;
      }
  
      /**
       * Returns the name of the character set used.
       * @return String The caracter set
       */
      public String getCharSetName() {
          return encoding;
      }
  
      /**
       * Returns the CapHeight attribute of the font.
       * @return int The CapHeight
       */
      public int getCapHeight() {
          return (int)convertTTFUnit2PDFUnit(capHeight);
      }
  
      /**
       * Returns the XHeight attribute of the font.
       * @return int The XHeight
       */
      public int getXHeight() {
          return (int)convertTTFUnit2PDFUnit(xHeight);
      }
  
      /**
       * Returns the Flags attribute of the font.
       * @return int The Flags
       */
      public int getFlags() {
          int flags = 32;    // Use Adobe Standard charset
          if (italicAngle != 0) {
              flags = flags | 64;
          }
          if (isFixedPitch != 0) {
              flags = flags | 2;
          }
          if (hasSerifs) {
              flags = flags | 1;
          }
          return flags;
      }
  
  
      /**
       * Returns the StemV attribute of the font.
       * @return String The StemV
       */
      public String getStemV() {
          return "0";
      }
  
      /**
       * Returns the ItalicAngle attribute of the font.
       * @return String The ItalicAngle
       */
      public String getItalicAngle() {
          String ia = Short.toString((short)(italicAngle / 0x10000));
  
          // This is the correct italic angle, however only int italic
          // angles are supported at the moment so this is commented out.
          /*
           * if ((italicAngle % 0x10000) > 0 )
           * ia=ia+(comma+Short.toString((short)((short)((italicAngle % 0x10000)*1000)/0x10000)));
           */
          return ia;
      }
  
      /**
       * Returns the font bounding box.
       * @return int[] The font bbox
       */
      public int[] getFontBBox() {
          final int[] fbb = new int[4];
          fbb[0] = (int)convertTTFUnit2PDFUnit(fontBBox1);
          fbb[1] = (int)convertTTFUnit2PDFUnit(fontBBox2);
          fbb[2] = (int)convertTTFUnit2PDFUnit(fontBBox3);
          fbb[3] = (int)convertTTFUnit2PDFUnit(fontBBox4);
  
          return fbb;
      }
  
      /**
       * Returns the LowerCaseAscent attribute of the font.
       * @return int The LowerCaseAscent
       */
      public int getLowerCaseAscent() {
          return (int)convertTTFUnit2PDFUnit(ascender);
      }
  
      /**
       * Returns the LowerCaseDescent attribute of the font.
       * @return int The LowerCaseDescent
       */
      public int getLowerCaseDescent() {
          return (int)convertTTFUnit2PDFUnit(descender);
      }
  
      /**
       * Returns the index of the last character, but this is for WinAnsiEncoding
       * only, so the last char is < 256.
       * @return short Index of the last character (<256)
       */
      public short getLastChar() {
          return lastChar;
      }
  
      /**
       * Returns the index of the first character.
       * @return short Index of the first character
       */
      public short getFirstChar() {
          return firstChar;
      }
  
      /**
       * Returns an array of character widths.
       * @return int[] The character widths
       */
      public int[] getWidths() {
          int[] wx = new int[mtxTab.length];
          for (int i = 0; i < wx.length; i++) {
              wx[i] = (int)convertTTFUnit2PDFUnit(mtxTab[i].getWx());
          }
  
          return wx;
      }
  
      /**
       * Returns the width of a given character.
       * @param idx Index of the character
       * @return int Standard width
       */
      public int getCharWidth(int idx) {
          return (int)convertTTFUnit2PDFUnit(ansiWidth[idx]);
      }
  
      /**
       * Returns the kerning table.
       * @return Map The kerning table
       */
      public Map getKerning() {
          return kerningTab;
      }
  
      /**
       * Returns the ANSI kerning table.
       * @return Map The ANSI kerning table
       */
      public Map getAnsiKerning() {
          return ansiKerningTab;
      }
  
      /**
       * Indicates if the font may be embedded.
       * @return boolean True if it may be embedded
       */
      public boolean isEmbeddable() {
          return isEmbeddable;
      }
  
  
      /**
       * Read Table Directory from the current position in the
       * FontFileReader and fill the global HashMap dirTabs
       * with the table name (String) as key and a TTFDirTabEntry
       * as value.
       * @param in FontFileReader to read the table directory from
       * @throws IOException in case of an I/O problem
       */
      protected void readDirTabs(FontFileReader in) throws IOException {
          in.skip(4);    // TTF_FIXED_SIZE
          int ntabs = in.readTTFUShort();
          in.skip(6);    // 3xTTF_USHORT_SIZE
  
          dirTabs = new java.util.HashMap();
          TTFDirTabEntry[] pd = new TTFDirTabEntry[ntabs];
          getLogger().debug("Reading " + ntabs + " dir tables");
          for (int i = 0; i < ntabs; i++) {
              pd[i] = new TTFDirTabEntry();
              dirTabs.put(pd[i].read(in), pd[i]);
          }
      }
  
      /**
       * Read the "head" table, this reads the bounding box and
       * sets the upem (unitsPerEM) variable
       * @param in FontFileReader to read the header from
       * @throws IOException in case of an I/O problem
       */
      protected void readFontHeader(FontFileReader in) throws IOException {
          seekTab(in, "head", 2 * 4 + 2 * 4 + 2);
          upem = in.readTTFUShort();
  
          in.skip(16);
  
          fontBBox1 = in.readTTFShort();
          fontBBox2 = in.readTTFShort();
          fontBBox3 = in.readTTFShort();
          fontBBox4 = in.readTTFShort();
  
          in.skip(2 + 2 + 2);
  
          locaFormat = in.readTTFShort();
      }
  
      /**
       * Read the number of glyphs from the "maxp" table
       * @param in FontFileReader to read the number of glyphs from
       * @throws IOException in case of an I/O problem
       */
      protected void getNumGlyphs(FontFileReader in) throws IOException {
          seekTab(in, "maxp", 4);
          numberOfGlyphs = in.readTTFUShort();
      }
  
  
      /**
       * Read the "hhea" table to find the ascender and descender and
       * size of "hmtx" table, i.e. a fixed size font might have only
       * one width
       * @param in FontFileReader to read the hhea table from
       * @throws IOException in case of an I/O problem
       */
      protected void readHorizontalHeader(FontFileReader in)
              throws IOException {
          seekTab(in, "hhea", 4);
          ascender = in.readTTFShort();    // Use sTypoAscender in "OS/2" table?
          descender = in.readTTFShort();    // Use sTypoDescender in "OS/2" table?
  
          in.skip(2 + 2 + 3 * 2 + 8 * 2);
          nhmtx = in.readTTFUShort();
          getLogger().debug("Number of horizontal metrics: " + nhmtx);
      }
  
      /**
       * Read "hmtx" table and put the horizontal metrics
       * in the mtxTab array. If the number of metrics is less
       * than the number of glyphs (eg fixed size fonts), extend
       * the mtxTab array and fill in the missing widths
       * @param in FontFileReader to read the hmtx table from
       * @throws IOException in case of an I/O problem
       */
      protected void readHorizontalMetrics(FontFileReader in)
              throws IOException {
          seekTab(in, "hmtx", 0);
  
          int mtxSize = (numberOfGlyphs > nhmtx) ? numberOfGlyphs : nhmtx;
          mtxTab = new TTFMtxEntry[mtxSize];
  
          getLogger().debug("*** Widths array: \n");
          for (int i = 0; i < mtxSize; i++) {
              mtxTab[i] = new TTFMtxEntry();
          }
          for (int i = 0; i < nhmtx; i++) {
              mtxTab[i].setWx(in.readTTFUShort());
              mtxTab[i].setLsb(in.readTTFUShort());
  
              getLogger().debug("   width[" + i + "] = "
                  + convertTTFUnit2PDFUnit(mtxTab[i].getWx()) + ";");
          }
  
          if (nhmtx < mtxSize) {
              // Fill in the missing widths
              int lastWidth = mtxTab[nhmtx - 1].getWx();
              for (int i = nhmtx; i < mtxSize; i++) {
                  mtxTab[i].setWx(lastWidth);
                  mtxTab[i].setLsb(in.readTTFUShort());
              }
          }
      }
  
  
      /**
       * Read the "post" table
       * containing the postscript names of the glyphs.
       */
      private final void readPostscript(FontFileReader in) throws IOException {
          String[] psGlyphsBuffer;
          int i, k, l;
  
          seekTab(in, "post", 0);
          postFormat = in.readTTFLong();
          italicAngle = in.readTTFULong();
          underlinePosition = in.readTTFShort();
          underlineThickness = in.readTTFShort();
          isFixedPitch = in.readTTFULong();
  
          in.skip(4 * 4);
  
          getLogger().debug("Post format: " + postFormat);
          switch (postFormat) {
          case 0x00010000:
              getLogger().debug("Postscript format 1");
              for (i = 0; i < Glyphs.MAC_GLYPH_NAMES.length; i++) {
                  mtxTab[i].setName(Glyphs.MAC_GLYPH_NAMES[i]);
              }
              break;
          case 0x00020000:
              getLogger().debug("Postscript format 2");
              int numGlyphStrings = 0;
              l = in.readTTFUShort();      // Num Glyphs
              // short minIndex=256;
              for (i = 0; i < l; i++) {    // Read indexes
                  mtxTab[i].setIndex(in.readTTFUShort());
                  // if (minIndex > mtxTab[i].index)
                  // minIndex=(short)mtxTab[i].index;
  
                  if (mtxTab[i].getIndex() > 257) {
                      numGlyphStrings++;
                  }
  
                  getLogger().debug("Post index: " + mtxTab[i].getIndex());
              }
              // firstChar=minIndex;
              psGlyphsBuffer = new String[numGlyphStrings];
              getLogger().debug("Reading " + numGlyphStrings
                  + " glyphnames" + ", was n num glyphs=" + l);
              for (i = 0; i < psGlyphsBuffer.length; i++) {
                  psGlyphsBuffer[i] = in.readTTFString(in.readTTFUByte());
              }
  
              for (i = 0; i < l; i++) {
                  if (mtxTab[i].getIndex() < NMACGLYPHS) {
                      mtxTab[i].setName(Glyphs.MAC_GLYPH_NAMES[mtxTab[i].getIndex()]);
                  } else {
                      k = mtxTab[i].getIndex() - NMACGLYPHS;
  
                      getLogger().debug(k + " i=" + i + " mtx=" + mtxTab.length
                          + " ps=" + psGlyphsBuffer.length);
  
                      mtxTab[i].setName(psGlyphsBuffer[k]);
                  }
              }
  
              break;
          case 0x00030000:
              // Postscript format 3 contains no glyph names
              getLogger().debug("Postscript format 3");
              break;
          default:
              getLogger().error("Unknown Postscript format: " + postFormat);
          }
      }
  
  
      /**
       * Read the "OS/2" table
       */
      private final void readOS2(FontFileReader in) throws IOException {
          // Check if font is embeddable
          if (dirTabs.get("OS/2") != null) {
              seekTab(in, "OS/2", 2 * 4);
              int fsType = in.readTTFUShort();
              if (fsType == 2) {
                  isEmbeddable = false;
              } else {
                  isEmbeddable = true;
              }
          } else {
              isEmbeddable = true;
          }
      }
  
      /**
       * Read the "loca" table.
       * @param in FontFileReader to read from
       * @throws IOException In case of a I/O problem
       */
      protected final void readIndexToLocation(FontFileReader in)
              throws IOException {
          seekTab(in, "loca", 0);
          for (int i = 0; i < numberOfGlyphs; i++) {
              mtxTab[i].setOffset(locaFormat == 1 ? in.readTTFULong()
                                   : (in.readTTFUShort() << 1));
          }
          lastLoca = (locaFormat == 1 ? in.readTTFULong()
                      : (in.readTTFUShort() << 1));
      }
  
      /**
       * Read the "glyf" table to find the bounding boxes.
       * @param in FontFileReader to read from
       * @throws IOException In case of a I/O problem
       */
      private final void readGlyf(FontFileReader in) throws IOException {
          TTFDirTabEntry dirTab = (TTFDirTabEntry)dirTabs.get("glyf");
          for (int i = 0; i < (numberOfGlyphs - 1); i++) {
              if (mtxTab[i].getOffset() != mtxTab[i + 1].getOffset()) {
                  in.seekSet(dirTab.getOffset() + mtxTab[i].getOffset());
                  in.skip(2);
                  final int[] bbox = {
                      in.readTTFShort(),
                      in.readTTFShort(),
                      in.readTTFShort(),
                      in.readTTFShort()};
                  mtxTab[i].setBoundingBox(bbox);
              } else {
                  mtxTab[i].setBoundingBox(mtxTab[0].getBoundingBox());
              }
          }
  
  
          long n = ((TTFDirTabEntry)dirTabs.get("glyf")).getOffset();
          for (int i = 0; i < numberOfGlyphs; i++) {
              if ((i + 1) >= mtxTab.length
                      || mtxTab[i].getOffset() != mtxTab[i + 1].getOffset()) {
                  in.seekSet(n + mtxTab[i].getOffset());
                  in.skip(2);
                  final int[] bbox = {
                      in.readTTFShort(),
                      in.readTTFShort(),
                      in.readTTFShort(),
                      in.readTTFShort()};
                  mtxTab[i].setBoundingBox(bbox);
              } else {
                  /**@todo Verify that this is correct, looks like a copy/paste bug (jm)*/
                  final int bbox0 = mtxTab[0].getBoundingBox()[0];
                  final int[] bbox = {bbox0, bbox0, bbox0, bbox0};
                  mtxTab[i].setBoundingBox(bbox);
                  /* Original code
                  mtxTab[i].bbox[0] = mtxTab[0].bbox[0];
                  mtxTab[i].bbox[1] = mtxTab[0].bbox[0];
                  mtxTab[i].bbox[2] = mtxTab[0].bbox[0];
                  mtxTab[i].bbox[3] = mtxTab[0].bbox[0]; */
              }
              getLogger().debug(mtxTab[i].toString(this));
          }
      }
  
      /**
       * Read the "name" table.
       * @param in FontFileReader to read from
       * @throws IOException In case of a I/O problem
       */
      private final void readName(FontFileReader in) throws IOException {
          seekTab(in, "name", 2);
          int i = in.getCurrentPos();
          int n = in.readTTFUShort();
          int j = in.readTTFUShort() + i - 2;
          i += 2 * 2;
  
          while (n-- > 0) {
              // getLogger().debug("Iteration: " + n);
              in.seekSet(i);
              final int platformID = in.readTTFUShort();
              final int encodingID = in.readTTFUShort();
              /*final int language_id =*/ in.readTTFUShort(); //Skip language id
  
              int k = in.readTTFUShort();
              int l = in.readTTFUShort();
  
              if (((platformID == 1 || platformID == 3) && (encodingID == 0 || encodingID == 1))
                      && (k == 1 || k == 2 || k == 0 || k == 4 || k == 6)) {
                  // if (k==1 || k==2 || k==0 || k==4 || k==6) {
                  in.seekSet(j + in.readTTFUShort());
                  String txt = in.readTTFString(l);
                  // getLogger().debug(platform_id + " " + encoding_id
                  //     + " " + k + " " + txt);
                  switch (k) {
                  case 0:
                      notice = txt;
                      break;
                  case 1:
                      familyName = txt;
                      break;
                  case 2:
                      subFamilyName = txt;
                      break;
                  case 4:
                      fullName = txt;
                      break;
                  case 6:
                      fontName = txt;
                      break;
                  }
                  if (!notice.equals("")
                          && !fullName.equals("")
                          && !fontName.equals("")
                          && !familyName.equals("")
                          && !subFamilyName.equals("")) {
                      break;
                  }
              }
              i += 6 * 2;
          }
      }
  
      /**
       * Read the "PCLT" table to find xHeight and capHeight.
       * @param in FontFileReader to read from
       * @throws IOException In case of a I/O problem
       */
      private final void readPCLT(FontFileReader in) throws IOException {
          TTFDirTabEntry dirTab = (TTFDirTabEntry)dirTabs.get("PCLT");
          if (dirTab != null) {
              in.seekSet(dirTab.getOffset() + 4 + 4 + 2);
              xHeight = in.readTTFUShort();
              in.skip(2 * 2);
              capHeight = in.readTTFUShort();
              in.skip(2 + 16 + 8 + 6 + 1 + 1);
  
              int serifStyle = in.readTTFUByte();
              serifStyle = serifStyle >> 6;
              serifStyle = serifStyle & 3;
              if (serifStyle == 1) {
                  hasSerifs = false;
              } else {
                  hasSerifs = true;
              }
          } else {
              // Approximate capHeight from height of "H"
              // It's most unlikly that a font misses the PCLT table
              // This also assumes that psocriptnames exists ("H")
              // Should look it up int the cmap (that wouldn't help
              // for charsets without H anyway...)
              for (int i = 0; i < mtxTab.length; i++) {
                  if ("H".equals(mtxTab[i].getName())) {
                      capHeight = mtxTab[i].getBoundingBox()[3] - mtxTab[i].getBoundingBox()[1];
                  }
              }
          }
      }
  
      /**
       * Read the kerning table, create a table for both CIDs and
       * winAnsiEncoding.
       * @param in FontFileReader to read from
       * @throws IOException In case of a I/O problem
       */
      private final void readKerning(FontFileReader in) throws IOException {
          // Read kerning
          kerningTab = new java.util.HashMap();
          ansiKerningTab = new java.util.HashMap();
          TTFDirTabEntry dirTab = (TTFDirTabEntry)dirTabs.get("kern");
          if (dirTab != null) {
              seekTab(in, "kern", 2);
              for (int n = in.readTTFUShort(); n > 0; n--) {
                  in.skip(2 * 2);
                  int k = in.readTTFUShort();
                  if (!((k & 1) != 0) || (k & 2) != 0 || (k & 4) != 0) {
                      return;
                  }
                  if ((k >> 8) != 0) {
                      continue;
                  }
  
                  k = in.readTTFUShort();
                  in.skip(3 * 2);
                  while (k-- > 0) {
                      int i = in.readTTFUShort();
                      int j = in.readTTFUShort();
                      int kpx = in.readTTFShort();
                      if (kpx != 0) {
                          // CID table
                          Integer iObj = new Integer(i);
                          Map adjTab = (Map)kerningTab.get(iObj);
                          if (adjTab == null) {
                              adjTab = new java.util.HashMap();
                          }
                          adjTab.put(new Integer(j),
                                     new Integer((int)convertTTFUnit2PDFUnit(kpx)));
                          kerningTab.put(iObj, adjTab);
                      }
                  }
              }
              // getLogger().debug(kerningTab.toString());
  
              // Create winAnsiEncoded kerning table
              Iterator ae = kerningTab.keySet().iterator();
              while (ae.hasNext()) {
                  Integer cidKey = (Integer)ae.next();
                  Map akpx = new java.util.HashMap();
                  Map ckpx = (Map)kerningTab.get(cidKey);
  
                  Iterator aee = ckpx.keySet().iterator();
                  while (aee.hasNext()) {
                      Integer cidKey2 = (Integer)aee.next();
                      Integer kern = (Integer)ckpx.get(cidKey2);
  
                      Iterator uniMap = mtxTab[cidKey2.intValue()].getUnicodeIndex().listIterator();
                      while (uniMap.hasNext()) {
                          Integer unicodeKey = (Integer)uniMap.next();
                          Integer[] ansiKeys = unicodeToWinAnsi(unicodeKey.intValue());
                          for (int u = 0; u < ansiKeys.length; u++) {
                              akpx.put(ansiKeys[u], kern);
                          }
                      }
                  }
  
                  if (akpx.size() > 0) {
                      Iterator uniMap = mtxTab[cidKey.intValue()].getUnicodeIndex().listIterator();
                      while (uniMap.hasNext()) {
                          Integer unicodeKey = (Integer)uniMap.next();
                          Integer[] ansiKeys = unicodeToWinAnsi(unicodeKey.intValue());
                          for (int u = 0; u < ansiKeys.length; u++) {
                              ansiKerningTab.put(ansiKeys[u], akpx);
                          }
                      }
                  }
              }
          }
      }
  
      /**
       * Return a List with TTFCmapEntry.
       * @return A list of TTFCmapEntry objects
       */
      public List getCMaps() {
          return cmaps;
      }
  
      /**
       * Check if this is a TrueType collection and that the given
       * name exists in the collection.
       * If it does, set offset in fontfile to the beginning of
       * the Table Directory for that font.
       * @param in FontFileReader to read from
       * @param name The name to check
       * @return True if not collection or font name present, false otherwise
       * @throws IOException In case of an I/O problem
       */
      protected final boolean checkTTC(FontFileReader in, String name) throws IOException {
          String tag = in.readTTFString(4);
  
          if ("ttcf".equals(tag)) {
              // This is a TrueType Collection
              in.skip(4);
  
              // Read directory offsets
              int numDirectories = (int)in.readTTFULong();
              // int numDirectories=in.readTTFUShort();
              long[] dirOffsets = new long[numDirectories];
              for (int i = 0; i < numDirectories; i++) {
                  dirOffsets[i] = in.readTTFULong();
              }
  
              getLogger().debug("This is a TrueType collection file with"
                                     + numDirectories + " fonts");
              getLogger().debug("Containing the following fonts: ");
              // Read all the directories and name tables to check
              // If the font exists - this is a bit ugly, but...
              boolean found = false;
  
              // Iterate through all name tables even if font
              // Is found, just to show all the names
              long dirTabOffset = 0;
              for (int i = 0; (i < numDirectories); i++) {
                  in.seekSet(dirOffsets[i]);
                  readDirTabs(in);
  
                  readName(in);
  
                  if (fullName.equals(name)) {
                      found = true;
                      dirTabOffset = dirOffsets[i];
                      getLogger().debug("* " + fullName);
                  } else {
                      getLogger().debug(fullName);
                  }
  
                  // Reset names
                  notice = "";
                  fullName = "";
                  familyName = "";
                  fontName = "";
                  subFamilyName = "";
              }
  
              in.seekSet(dirTabOffset);
              return found;
          } else {
              in.seekSet(0);
              return true;
          }
      }
  
      /*
       * Helper classes, they are not very efficient, but that really
       * doesn't matter...
       */
      private Integer[] unicodeToWinAnsi(int unicode) {
          List ret = new java.util.ArrayList();
          for (int i = 32; i < Glyphs.WINANSI_ENCODING.length; i++) {
              if (unicode == Glyphs.WINANSI_ENCODING[i]) {
                  ret.add(new Integer(i));
              }
          }
          return (Integer[])ret.toArray(new Integer[0]);
      }
  
      /**
       * Dumps a few informational values to System.out.
       */
      public void printStuff() {
          System.out.println("Font name:   " + fontName);
          System.out.println("Full name:   " + fullName);
          System.out.println("Family name: " + familyName);
          System.out.println("Subfamily name: " + subFamilyName);
          System.out.println("Notice:      " + notice);
          System.out.println("xHeight:     " + (int)convertTTFUnit2PDFUnit(xHeight));
          System.out.println("capheight:   " + (int)convertTTFUnit2PDFUnit(capHeight));
  
          int italic = (int)(italicAngle >> 16);
          System.out.println("Italic:      " + italic);
          System.out.print("ItalicAngle: " + (short)(italicAngle / 0x10000));
          if ((italicAngle % 0x10000) > 0) {
              System.out.print("."
                               + (short)((italicAngle % 0x10000) * 1000)
                                 / 0x10000);
          }
          System.out.println();
          System.out.println("Ascender:    " + convertTTFUnit2PDFUnit(ascender));
          System.out.println("Descender:   " + convertTTFUnit2PDFUnit(descender));
          System.out.println("FontBBox:    [" + (int)convertTTFUnit2PDFUnit(fontBBox1)
                             + " " + (int)convertTTFUnit2PDFUnit(fontBBox2) + " "
                             + (int)convertTTFUnit2PDFUnit(fontBBox3) + " "
                             + (int)convertTTFUnit2PDFUnit(fontBBox4) + "]");
      }
  
      /**
       * Static main method to get info about a TrueType font.
       * @param args The command line arguments
       */
      public static void main(String[] args) {
          int level = ConsoleLogger.LEVEL_WARN;
          Logger log = new ConsoleLogger(level);
          try {
              TTFFile ttfFile = new TTFFile();
              ttfFile.enableLogging(log);
  
              FontFileReader reader = new FontFileReader(args[0]);
  
              String name = null;
              if (args.length >= 2) {
                  name = args[1];
              }
  
              ttfFile.readFont(reader, name);
              ttfFile.printStuff();
  
          } catch (IOException ioe) {
              log.error("Problem reading font: " + ioe.toString(), ioe);
          }
      }
  
  }
  
  
  /**
   * Key-value helper class
   */
  class UnicodeMapping {
  
      private int uIdx;
      private int gIdx;
  
      UnicodeMapping(int gIdx, int uIdx) {
          this.uIdx = uIdx;
          this.gIdx = gIdx;
      }
  
      /**
       * Returns the gIdx.
       * @return int
       */
      public int getGIdx() {
          return gIdx;
      }
  
      /**
       * Returns the uIdx.
       * @return int
       */
      public int getUIdx() {
          return uIdx;
      }
  
  }
  
  
  
  1.1                  xml-fop/src/org/apache/fop/fonts/truetype/TTFMtxEntry.java
  
  Index: TTFMtxEntry.java
  ===================================================================
  /*
   * $Id: TTFMtxEntry.java,v 1.1 2003/01/08 13:54:04 jeremias Exp $
   * Copyright (C) 2001-2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts.truetype;
  
  import java.util.List;
  
  /**
   * This class represents a TrueType Mtx Entry.
   */
  class TTFMtxEntry {
  
      private int wx;
      private int lsb;
      private String name = "";
      private int index;
      private List unicodeIndex = new java.util.ArrayList();
      private int[] boundingBox = new int[4];
      private long offset;
      private byte found = 0;
  
      /**
       * Returns a String representation of this object.
       * 
       * @param t TTFFile to use for unit conversion
       * @return String String representation
       */
      public String toString(TTFFile t) {
          return "Glyph " + name + " index: " + index + " bbox [ "
               + t.convertTTFUnit2PDFUnit(boundingBox[0]) + " "
               + t.convertTTFUnit2PDFUnit(boundingBox[1]) + " "
               + t.convertTTFUnit2PDFUnit(boundingBox[2]) + " "
               + t.convertTTFUnit2PDFUnit(boundingBox[3]) + "] wx: "
               + t.convertTTFUnit2PDFUnit(wx);
      }
  
      /**
       * Returns the boundingBox.
       * @return int[]
       */
      public int[] getBoundingBox() {
          return boundingBox;
      }
  
      /**
       * Sets the boundingBox.
       * @param boundingBox The boundingBox to set
       */
      public void setBoundingBox(int[] boundingBox) {
          this.boundingBox = boundingBox;
      }
  
      /**
       * Returns the found.
       * @return byte
       */
      public byte getFound() {
          return found;
      }
  
      /**
       * Returns the index.
       * @return int
       */
      public int getIndex() {
          return index;
      }
  
      /**
       * Returns the lsb.
       * @return int
       */
      public int getLsb() {
          return lsb;
      }
  
      /**
       * Returns the name.
       * @return String
       */
      public String getName() {
          return name;
      }
  
      /**
       * Returns the offset.
       * @return long
       */
      public long getOffset() {
          return offset;
      }
  
      /**
       * Returns the unicodeIndex.
       * @return List
       */
      public List getUnicodeIndex() {
          return unicodeIndex;
      }
  
      /**
       * Returns the wx.
       * @return int
       */
      public int getWx() {
          return wx;
      }
  
      /**
       * Sets the found.
       * @param found The found to set
       */
      public void setFound(byte found) {
          this.found = found;
      }
  
      /**
       * Sets the index.
       * @param index The index to set
       */
      public void setIndex(int index) {
          this.index = index;
      }
  
      /**
       * Sets the lsb.
       * @param lsb The lsb to set
       */
      public void setLsb(int lsb) {
          this.lsb = lsb;
      }
  
      /**
       * Sets the name.
       * @param name The name to set
       */
      public void setName(String name) {
          this.name = name;
      }
  
      /**
       * Sets the offset.
       * @param offset The offset to set
       */
      public void setOffset(long offset) {
          this.offset = offset;
      }
  
      /**
       * Sets the wx.
       * @param wx The wx to set
       */
      public void setWx(int wx) {
          this.wx = wx;
      }
  
  
  }
  
  
  
  1.1                  xml-fop/src/org/apache/fop/fonts/truetype/TTFSubSetFile.java
  
  Index: TTFSubSetFile.java
  ===================================================================
  /*
   * $Id: TTFSubSetFile.java,v 1.1 2003/01/08 13:54:04 jeremias Exp $
   * Copyright (C) 2001-2003 The Apache Software Foundation. All rights reserved.
   * For details on use and redistribution please refer to the
   * LICENSE file included with these sources.
   */
  
  package org.apache.fop.fonts.truetype;
  
  import java.io.IOException;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.List;
  
  
  /**
   * Reads a TrueType file and generates a subset
   * that can be used to embed a TrueType CID font.
   * TrueType tables needed for embedded CID fonts are:
   * "head", "hhea", "loca", "maxp", "cvt ", "prep", "glyf", "hmtx" and "fpgm".
   * The TrueType spec can be found at the Microsoft
   * Typography site: http://www.microsoft.com/truetype/
   */
  public class TTFSubSetFile extends TTFFile {
  
      private byte[] output = null;
      private int realSize = 0;
      private int currentPos = 0;
  
      /*
       * Offsets in name table to be filled out by table.
       * The offsets are to the checkSum field
       */
      private int cvtDirOffset = 0;
      private int fpgmDirOffset = 0;
      private int glyfDirOffset = 0;
      private int headDirOffset = 0;
      private int hheaDirOffset = 0;
      private int hmtxDirOffset = 0;
      private int locaDirOffset = 0;
      private int maxpDirOffset = 0;
      private int prepDirOffset = 0;
  
      private int checkSumAdjustmentOffset = 0;
      private int locaOffset = 0;
  
      /**
       * Initalize the output array
       */
      private void init(int size) {
          output = new byte[size];
          realSize = 0;
          currentPos = 0;
  
          // createDirectory()
      }
  
      /**
       * Create the directory table
       */
      private void createDirectory() {
          int numTables = 9;
          // Create the TrueType header
          writeByte((byte)0);
          writeByte((byte)1);
          writeByte((byte)0);
          writeByte((byte)0);
          realSize += 4;
  
          writeUShort(numTables);
          realSize += 2;
  
          // Create searchRange, entrySelector and rangeShift
          int maxPow = maxPow2(numTables);
          int searchRange = maxPow * 16;
          writeUShort(searchRange);
          realSize += 2;
  
          writeUShort(maxPow);
          realSize += 2;
  
          writeUShort((numTables * 16) - searchRange);
          realSize += 2;
  
          // Create space for the table entries
          writeString("cvt ");
          cvtDirOffset = currentPos;
          currentPos += 12;
          realSize += 16;
  
          writeString("fpgm");
          fpgmDirOffset = currentPos;
          currentPos += 12;
          realSize += 16;
  
          writeString("glyf");
          glyfDirOffset = currentPos;
          currentPos += 12;
          realSize += 16;
  
          writeString("head");
          headDirOffset = currentPos;
          currentPos += 12;
          realSize += 16;
  
          writeString("hhea");
          hheaDirOffset = currentPos;
          currentPos += 12;
          realSize += 16;
  
          writeString("hmtx");
          hmtxDirOffset = currentPos;
          currentPos += 12;
          realSize += 16;
  
          writeString("loca");
          locaDirOffset = currentPos;
          currentPos += 12;
          realSize += 16;
  
          writeString("maxp");
          maxpDirOffset = currentPos;
          currentPos += 12;
          realSize += 16;
  
          writeString("prep");
          prepDirOffset = currentPos;
          currentPos += 12;
          realSize += 16;
      }
  
  
      /**
       * Copy the cvt table as is from original font to subset font
       */
      private void createCvt(FontFileReader in) throws IOException {
          TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("cvt ");
          if (entry != null) {
              pad4();
              seekTab(in, "cvt ", 0);
              System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
                               0, output, currentPos, (int)entry.getLength());
  
              int checksum = getCheckSum(currentPos, (int)entry.getLength());
              writeULong(cvtDirOffset, checksum);
              writeULong(cvtDirOffset + 4, currentPos);
              writeULong(cvtDirOffset + 8, (int)entry.getLength());
              currentPos += (int)entry.getLength();
              realSize += (int)entry.getLength();
          } else {
              throw new IOException("Can't find cvt table");
          }
      }
  
  
  
      /**
       * Copy the fpgm table as is from original font to subset font
       */
      private void createFpgm(FontFileReader in) throws IOException {
          TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("fpgm");
          if (entry != null) {
              pad4();
              seekTab(in, "fpgm", 0);
              System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
                               0, output, currentPos, (int)entry.getLength());
              int checksum = getCheckSum(currentPos, (int)entry.getLength());
              writeULong(fpgmDirOffset, checksum);
              writeULong(fpgmDirOffset + 4, currentPos);
              writeULong(fpgmDirOffset + 8, (int)entry.getLength());
              currentPos += (int)entry.getLength();
              realSize += (int)entry.getLength();
          } else {
              throw new IOException("Can't find fpgm table");
          }
      }
  
  
  
      /**
       * Create an empty loca table without updating checksum
       */
      private void createLoca(int size) throws IOException {
          pad4();
          locaOffset = currentPos;
          writeULong(locaDirOffset + 4, currentPos);
          writeULong(locaDirOffset + 8, size * 4 + 4);
          currentPos += size * 4 + 4;
          realSize += size * 4 + 4;
      }
  
  
      /**
       * Copy the maxp table as is from original font to subset font
       * and set num glyphs to size
       */
      private void createMaxp(FontFileReader in, int size) throws IOException {
          TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("maxp");
          if (entry != null) {
              pad4();
              seekTab(in, "maxp", 0);
              System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
                               0, output, currentPos, (int)entry.getLength());
              writeUShort(currentPos + 4, size);
  
              int checksum = getCheckSum(currentPos, (int)entry.getLength());
              writeULong(maxpDirOffset, checksum);
              writeULong(maxpDirOffset + 4, currentPos);
              writeULong(maxpDirOffset + 8, (int)entry.getLength());
              currentPos += (int)entry.getLength();
              realSize += (int)entry.getLength();
          } else {
              throw new IOException("Can't find maxp table");
          }
      }
  
  
      /**
       * Copy the prep table as is from original font to subset font
       */
      private void createPrep(FontFileReader in) throws IOException {
          TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("prep");
          if (entry != null) {
              pad4();
              seekTab(in, "prep", 0);
              System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
                               0, output, currentPos, (int)entry.getLength());
  
              int checksum = getCheckSum(currentPos, (int)entry.getLength());
              writeULong(prepDirOffset, checksum);
              writeULong(prepDirOffset + 4, currentPos);
              writeULong(prepDirOffset + 8, (int)entry.getLength());
              currentPos += (int)entry.getLength();
              realSize += (int)entry.getLength();
          } else {
              throw new IOException("Can't find prep table");
          }
      }
  
  
      /**
       * Copy the hhea table as is from original font to subset font
       * and fill in size of hmtx table
       */
      private void createHhea(FontFileReader in, int size) throws IOException {
          TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("hhea");
          if (entry != null) {
              pad4();
              seekTab(in, "hhea", 0);
              System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
                               0, output, currentPos, (int)entry.getLength());
              writeUShort((int)entry.getLength() + currentPos - 2, size);
  
              int checksum = getCheckSum(currentPos, (int)entry.getLength());
              writeULong(hheaDirOffset, checksum);
              writeULong(hheaDirOffset + 4, currentPos);
              writeULong(hheaDirOffset + 8, (int)entry.getLength());
              currentPos += (int)entry.getLength();
              realSize += (int)entry.getLength();
          } else {
              throw new IOException("Can't find hhea table");
          }
      }
  
  
      /**
       * Copy the head table as is from original font to subset font
       * and set indexToLocaFormat to long and set
       * checkSumAdjustment to 0, store offset to checkSumAdjustment
       * in checkSumAdjustmentOffset
       */
      private void createHead(FontFileReader in) throws IOException {
          TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("head");
          if (entry != null) {
              pad4();
              seekTab(in, "head", 0);
              System.arraycopy(in.getBytes((int)entry.getOffset(), (int)entry.getLength()),
                               0, output, currentPos, (int)entry.getLength());
  
              checkSumAdjustmentOffset = currentPos + 8;
              output[currentPos + 8] = 0;     // Set checkSumAdjustment to 0
              output[currentPos + 9] = 0;
              output[currentPos + 10] = 0;
              output[currentPos + 11] = 0;
              output[currentPos + 50] = 0;    // long locaformat
              output[currentPos + 51] = 1;    // long locaformat
  
              int checksum = getCheckSum(currentPos, (int)entry.getLength());
              writeULong(headDirOffset, checksum);
              writeULong(headDirOffset + 4, currentPos);
              writeULong(headDirOffset + 8, (int)entry.getLength());
  
              currentPos += (int)entry.getLength();
              realSize += (int)entry.getLength();
          } else {
              throw new IOException("Can't find head table");
          }
      }
  
  
      /**
       * Create the glyf table and fill in loca table
       */
      private void createGlyf(FontFileReader in,
                              Map glyphs) throws IOException {
          TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf");
          int size = 0;
          int start = 0;
          int endOffset = 0;    // Store this as the last loca
          if (entry != null) {
              pad4();
              start = currentPos;
  
              /* Loca table must be in order by glyph index, so build
               * an array first and then write the glyph info and
               * location offset.
               */
              int[] origIndexes = new int[glyphs.size()];
  
              Iterator e = glyphs.keySet().iterator();
              while (e.hasNext()) {
                  Integer origIndex = (Integer)e.next();
                  Integer subsetIndex = (Integer)glyphs.get(origIndex);
                  origIndexes[subsetIndex.intValue()] = origIndex.intValue();
              }
  
              for (int i = 0; i < origIndexes.length; i++) {
                  int glyphLength = 0;
                  int nextOffset = 0;
                  int origGlyphIndex = origIndexes[i];
                  if (origGlyphIndex >= (mtxTab.length - 1)) {
                      nextOffset = (int)lastLoca;
                  } else {
                      nextOffset = (int)mtxTab[origGlyphIndex + 1].getOffset();
                  }
                  glyphLength = nextOffset - (int)mtxTab[origGlyphIndex].getOffset();
  
                  // Copy glyph
                  System.arraycopy(
                      in.getBytes((int)entry.getOffset() + (int)mtxTab[origGlyphIndex].getOffset(),
                          glyphLength), 0,
                      output, currentPos,
                      glyphLength);
  
  
                  // Update loca table
                  writeULong(locaOffset + i * 4, currentPos - start);
                  if ((currentPos - start + glyphLength) > endOffset) {
                      endOffset = (currentPos - start + glyphLength);
                  }
  
                  currentPos += glyphLength;
                  realSize += glyphLength;
  
              }
  
              size = currentPos - start;
  
              int checksum = getCheckSum(start, size);
              writeULong(glyfDirOffset, checksum);
              writeULong(glyfDirOffset + 4, start);
              writeULong(glyfDirOffset + 8, size);
              currentPos += 12;
              realSize += 12;
  
              // Update loca checksum and last loca index
              writeULong(locaOffset + glyphs.size() * 4, endOffset);
  
              checksum = getCheckSum(locaOffset, glyphs.size() * 4 + 4);
              writeULong(locaDirOffset, checksum);
          } else {
              throw new IOException("Can't find glyf table");
          }
      }
  
  
      /**
       * Create the hmtx table by copying metrics from original
       * font to subset font. The glyphs Map contains an
       * Integer key and Integer value that maps the original
       * metric (key) to the subset metric (value)
       */
      private void createHmtx(FontFileReader in,
                              Map glyphs) throws IOException {
          TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("hmtx");
  
          int longHorMetricSize = glyphs.size() * 2;
          int leftSideBearingSize = glyphs.size() * 2;
          int hmtxSize = longHorMetricSize + leftSideBearingSize;
  
          if (entry != null) {
              pad4();
              //int offset = (int)entry.offset;
              Iterator e = glyphs.keySet().iterator();
              while (e.hasNext()) {
                  Integer origIndex = (Integer)e.next();
                  Integer subsetIndex = (Integer)glyphs.get(origIndex);
  
                  writeUShort(currentPos + subsetIndex.intValue() * 4,
                              mtxTab[origIndex.intValue()].getWx());
                  writeUShort(currentPos + subsetIndex.intValue() * 4 + 2,
                              mtxTab[origIndex.intValue()].getLsb());
              }
  
              int checksum = getCheckSum(currentPos, hmtxSize);
              writeULong(hmtxDirOffset, checksum);
              writeULong(hmtxDirOffset + 4, currentPos);
              writeULong(hmtxDirOffset + 8, hmtxSize);
              currentPos += hmtxSize;
              realSize += hmtxSize;
          } else {
              throw new IOException("Can't find hmtx table");
          }
      }
  
      /**
       * Returns a List containing the glyph itself plus all glyphs
       * that this composite glyph uses
       */
      private List getIncludedGlyphs(FontFileReader in, int glyphOffset,
                                       Integer glyphIdx) throws IOException {
          List ret = new java.util.ArrayList();
          ret.add(glyphIdx);
          int offset = glyphOffset + (int)mtxTab[glyphIdx.intValue()].getOffset() + 10;
          Integer compositeIdx = null;
          int flags = 0;
          boolean moreComposites = true;
          while (moreComposites) {
              flags = in.readTTFUShort(offset);
              compositeIdx = new Integer(in.readTTFUShort(offset + 2));
              ret.add(compositeIdx);
  
              offset += 4;
              if ((flags & 1) > 0) {
                  // ARG_1_AND_ARG_2_ARE_WORDS
                  offset += 4;
              } else {
                  offset += 2;
              }
  
              if ((flags & 8) > 0) {
                  offset += 2;    // WE_HAVE_A_SCALE
              } else if ((flags & 64) > 0) {
                  offset += 4;    // WE_HAVE_AN_X_AND_Y_SCALE
              } else if ((flags & 128) > 0) {
                  offset += 8;    // WE_HAVE_A_TWO_BY_TWO
              }
  
              if ((flags & 32) > 0) {
                  moreComposites = true;
              } else {
                  moreComposites = false;
              }
          }
  
          return ret;
      }
  
  
      /**
       * Rewrite all compositepointers in glyphindex glyphIdx
       *
       */
      private void remapComposite(FontFileReader in, Map glyphs,
                                  int glyphOffset,
                                  Integer glyphIdx) throws IOException {
          int offset = glyphOffset + (int)mtxTab[glyphIdx.intValue()].getOffset()
                       + 10;
  
          Integer compositeIdx = null;
          int flags = 0;
          boolean moreComposites = true;
  
          while (moreComposites) {
              flags = in.readTTFUShort(offset);
              compositeIdx = new Integer(in.readTTFUShort(offset + 2));
              Integer newIdx = (Integer)glyphs.get(compositeIdx);
              if (newIdx == null) {
                  // This errormessage would look much better
                  // if the fontname was printed to
                  //log.error("An embedded font "
                  //                     + "contains bad glyph data. "
                  //                     + "Characters might not display "
                  //                     + "correctly.");
                  moreComposites = false;
                  continue;
              }
  
              in.writeTTFUShort(offset + 2, newIdx.intValue());
  
              offset += 4;
  
              if ((flags & 1) > 0) {
                  // ARG_1_AND_ARG_2_ARE_WORDS
                  offset += 4;
              } else {
                  offset += 2;
              }
  
              if ((flags & 8) > 0) {
                  offset += 2;    // WE_HAVE_A_SCALE
              } else if ((flags & 64) > 0) {
                  offset += 4;    // WE_HAVE_AN_X_AND_Y_SCALE
              } else if ((flags & 128) > 0) {
                  offset += 8;    // WE_HAVE_A_TWO_BY_TWO
              }
  
              if ((flags & 32) > 0) {
                  moreComposites = true;
              } else {
                  moreComposites = false;
              }
          }
      }
  
  
      /**
       * Scan all the original glyphs for composite glyphs and add those glyphs
       * to the glyphmapping also rewrite the composite glyph pointers to the new
       * mapping
       */
      private void scanGlyphs(FontFileReader in,
                              Map glyphs) throws IOException {
          TTFDirTabEntry entry = (TTFDirTabEntry)dirTabs.get("glyf");
          Map newComposites = null;
          Map allComposites = new java.util.HashMap();
  
          int newIndex = glyphs.size();
  
          if (entry != null) {
              while (newComposites == null || newComposites.size() > 0) {
                  // Inefficient to iterate through all glyphs
                  newComposites = new java.util.HashMap();
  
                  Iterator e = glyphs.keySet().iterator();
                  while (e.hasNext()) {
                      Integer origIndex = (Integer)e.next();
  
                      if (in.readTTFShort(entry.getOffset()
                                          + mtxTab[origIndex.intValue()].getOffset()) < 0) {
                          // origIndex is a composite glyph
                          allComposites.put(origIndex, glyphs.get(origIndex));
                          List composites =
                              getIncludedGlyphs(in, (int)entry.getOffset(),
                                                origIndex);
  
                          // Iterate through all composites pointed to
                          // by this composite and check if they exists
                          // in the glyphs map, add them if not.
                          Iterator cps = composites.iterator();
                          while (cps.hasNext()) {
                              Integer cIdx = (Integer)cps.next();
                              if (glyphs.get(cIdx) == null
                                      && newComposites.get(cIdx) == null) {
                                  newComposites.put(cIdx,
                                                    new Integer(newIndex));
                                  newIndex++;
                              }
                          }
                      }
                  }
  
                  // Add composites to glyphs
                  Iterator m = newComposites.keySet().iterator();
                  while (m.hasNext()) {
                      Integer im = (Integer)m.next();
                      glyphs.put(im, newComposites.get(im));
                  }
              }
  
              // Iterate through all composites to remap their composite index
              Iterator ce = allComposites.keySet().iterator();
              while (ce.hasNext()) {
                  remapComposite(in, glyphs, (int)entry.getOffset(),
                                 (Integer)ce.next());
              }
  
          } else {
              throw new IOException("Can't find glyf table");
          }
      }
  
  
  
      /**
       * Returns a subset of the original font.
       *
       * @param in FontFileReader to read from
       * @param name Name to be checked for in the font file
       * @param glyphs Map of glyphs (glyphs has old index as (Integer) key and
       * new index as (Integer) value)
       * @return A subset of the original font
       * @throws IOException in case of an I/O problem
       */
      public byte[] readFont(FontFileReader in, String name,
                             Map glyphs) throws IOException {
  
          //Check if TrueType collection, and that the name exists in the collection
          if (!checkTTC(in, name)) {
              throw new IOException("Failed to read font");
          }
  
          output = new byte[in.getFileSize()];
  
          readDirTabs(in);
          readFontHeader(in);
          getNumGlyphs(in);
          readHorizontalHeader(in);
          readHorizontalMetrics(in);
          readIndexToLocation(in);
  
          scanGlyphs(in, glyphs);
  
          createDirectory();                // Create the TrueType header and directory
  
          createHead(in);
          createHhea(in, glyphs.size());    // Create the hhea table
          createHmtx(in, glyphs);           // Create hmtx table
          createMaxp(in, glyphs.size());    // copy the maxp table
  
          try {
              createCvt(in);    // copy the cvt table
          } catch (IOException ex) {
              // Cvt is optional (only required for OpenType (MS) fonts)
              //log.error("TrueType warning: " + ex.getMessage());
          }
  
          try {
              createFpgm(in);    // copy fpgm table
          } catch (IOException ex) {
              // Fpgm is optional (only required for OpenType (MS) fonts)
              //log.error("TrueType warning: " + ex.getMessage());
          }
  
          try {
              createPrep(in);    // copy prep table
          } catch (IOException ex) {
              // Prep is optional (only required for OpenType (MS) fonts)
              //log.error("TrueType warning: " + ex.getMessage());
          }
  
          try {
              createLoca(glyphs.size());    // create empty loca table
          } catch (IOException ex) {
              // Loca is optional (only required for OpenType (MS) fonts)
              //log.error("TrueType warning: " + ex.getMessage());
          }
  
          try {
              createGlyf(in, glyphs);
          } catch (IOException ex) {
              // Glyf is optional (only required for OpenType (MS) fonts)
              //log.error("TrueType warning: " + ex.getMessage());
          }
  
          pad4();
          createCheckSumAdjustment();
  
          byte[] ret = new byte[realSize];
          System.arraycopy(output, 0, ret, 0, realSize);
  
          return ret;
      }
  
      /**
       * writes a ISO-8859-1 string at the currentPosition
       * updates currentPosition but not realSize
       * @return number of bytes written
       */
      private int writeString(String str) {
          int length = 0;
          try {
              byte[] buf = str.getBytes("ISO-8859-1");
              System.arraycopy(buf, 0, output, currentPos, buf.length);
              length = buf.length;
              currentPos += length;
          } catch (java.io.UnsupportedEncodingException e) {
              // This should never happen!
          }
  
          return length;
      }
  
      /**
       * Appends a byte to the output array,
       * updates currentPost but not realSize
       */
      private void writeByte(byte b) {
          output[currentPos++] = b;
      }
  
      /**
       * Appends a USHORT to the output array,
       * updates currentPost but not realSize
       */
      private void writeUShort(int s) {
          byte b1 = (byte)((s >> 8) & 0xff);
          byte b2 = (byte)(s & 0xff);
          writeByte(b1);
          writeByte(b2);
      }
  
      /**
       * Appends a USHORT to the output array,
       * at the given position without changing currentPos
       */
      private void writeUShort(int pos, int s) {
          byte b1 = (byte)((s >> 8) & 0xff);
          byte b2 = (byte)(s & 0xff);
          output[pos] = b1;
          output[pos + 1] = b2;
      }
  
      /**
       * Appends a ULONG to the output array,
       * updates currentPos but not realSize
       */
      private void writeULong(int s) {
          byte b1 = (byte)((s >> 24) & 0xff);
          byte b2 = (byte)((s >> 16) & 0xff);
          byte b3 = (byte)((s >> 8) & 0xff);
          byte b4 = (byte)(s & 0xff);
          writeByte(b1);
          writeByte(b2);
          writeByte(b3);
          writeByte(b4);
      }
  
      /**
       * Appends a ULONG to the output array,
       * at the given position without changing currentPos
       */
      private void writeULong(int pos, int s) {
          byte b1 = (byte)((s >> 24) & 0xff);
          byte b2 = (byte)((s >> 16) & 0xff);
          byte b3 = (byte)((s >> 8) & 0xff);
          byte b4 = (byte)(s & 0xff);
          output[pos] = b1;
          output[pos + 1] = b2;
          output[pos + 2] = b3;
          output[pos + 3] = b4;
      }
  
      /**
       * Read a signed short value at given position
       */
      private short readShort(int pos) {
          int ret = readUShort(pos);
          return (short)ret;
      }
  
      /**
       * Read a unsigned short value at given position
       */
      private int readUShort(int pos) {
          int ret = (int)output[pos];
          if (ret < 0) {
              ret += 256;
          }
          ret = ret << 8;
          if ((int)output[pos + 1] < 0) {
              ret |= (int)output[pos + 1] + 256;
          } else {
              ret |= (int)output[pos + 1];
          }
  
          return ret;
      }
  
      /**
       * Create a padding in the fontfile to align
       * on a 4-byte boundary
       */
      private void pad4() {
          int padSize = currentPos % 4;
          for (int i = 0; i < padSize; i++) {
              output[currentPos++] = 0;
              realSize++;
          }
      }
  
      /**
       * Returns the maximum power of 2 <= max
       */
      private int maxPow2(int max) {
          int i = 0;
          while (Math.pow(2, (double)i) < max) {
              i++;
          }
  
          return (i - 1);
      }
  
      private int log2(int num) {
          return (int)(Math.log((double)num) / Math.log(2));
      }
  
  
      private int getCheckSum(int start, int size) {
          return (int)getLongCheckSum(start, size);
      }
  
      private long getLongCheckSum(int start, int size) {
          // All the tables here are aligned on four byte boundaries
          // Add remainder to size if it's not a multiple of 4
          int remainder = size % 4;
          if (remainder != 0) {
              size += remainder;
          }
  
          long sum = 0;
  
          for (int i = 0; i < size; i += 4) {
              int l = (int)(output[start + i] << 24);
              l += (int)(output[start + i + 1] << 16);
              l += (int)(output[start + i + 2] << 16);
              l += (int)(output[start + i + 3] << 16);
              sum += l;
              if (sum > 0xffffffff) {
                  sum = sum - 0xffffffff;
              }
          }
  
          return sum;
      }
  
      private void createCheckSumAdjustment() {
          long sum = getLongCheckSum(0, realSize);
          int checksum = (int)(0xb1b0afba - sum);
          writeULong(checkSumAdjustmentOffset, checksum);
      }
  
  }
  
  
  
  
  
  

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