Logo Search packages:      
Sourcecode: ted version File versions

psTtf.c

#   include <stdio.h>
#   include <string.h>
#   include <stdlib.h>
#   include <malloc.h>

#   define  y0    math_y0
#   define  y1    math_y1
#   include <math.h>
#   undef   y0
#   undef   y1

#   include <sioMemory.h>
#   include <sioEndian.h>
#   include <sioHex.h>
#   include <utilEndian.h>
#   include <utilMemoryBuffer.h>
#   include <utilMatchFont.h>
#   include <utilAffineTransform.h>
#   include <appDebugon.h>

/************************************************************************/
/*                                                    */
/*  True Type font.                                         */
/*                                                    */
/*  A considerable part of this code was borrowed from the ttf2pt1      */
/*  project. Differences in purpose and validations against the         */
/*  documentation made me change a lot.                           */
/*                                                    */
/*  SEE: http://developer.apple.com/fonts/TTRefMan/               */
/*                                                    */
/*  A substantial part of this code is experimental: E.G. it contains   */
/*  code that can be used to convert from true type fonts to postscript */
/*  type1 that was adapted from 'ttf2pt1' but it is never called. */
/*                                                    */
/*  1)  Platform: 0=Unicode, 1= Mac, 3= Windows.                  */
/*                                                    */
/************************************************************************/

typedef struct TrueTypeTableEntry
    {
    char          ttteTag[4+1];
    unsigned long ttteChecksum;
    unsigned long ttteOffset;
    unsigned long ttteLength;
    unsigned char *     ttteBytes;

    unsigned long ttteSaveOffset;
    } TrueTypeTableEntry;

typedef struct TrueTypeNameRecord
    {
    unsigned int  ttnrPlatformID;         /*  1  */
    unsigned int  ttnrEncodingID;
    unsigned int  ttnrLanguageID;
    unsigned int  ttnrNameID;
    unsigned int  ttnrLength;
    unsigned int  ttnrOffset;

    unsigned char *     ttnrSavedBytes;
    } TrueTypeNameRecord;

typedef struct TrueTypeNameTable
    {
    unsigned int        ttntFormat;
    unsigned int        ttntRecordCount;
    unsigned int        ttntOffset;

    TrueTypeNameRecord *      ttntRecords;
    } TrueTypeNameTable;

typedef struct TrueTypeOS_2Table
    {
    unsigned int        ttotVersion;
    int                 ttotAvgCharWidth;
    unsigned int  ttotWeightClass;
    unsigned int  ttotWidthClass;
    int                 ttotType;
    int                 ttotSubscriptXSize;
    int                 ttotSubscriptYSize;
    int                 ttotSubscriptXOffset;
    int                 ttotSubscriptYOffset;
    int                 ttotSuperscriptXSize;
    int                 ttotSuperscriptYSize;
    int                 ttotSuperscriptXOffset;
    int                 ttotSuperscriptYOffset;
    int                 ttotStrikeoutSize;
    int                 ttotStrikeoutPosition;
    int                 ttotFamilyClass;
    unsigned char       ttotPanose[10];
    unsigned long       ttotCharRange[4];
    unsigned char       ttotVendID[4+1];
    unsigned int  ttotSelection;
    unsigned int  ttotFirstCharIndex;
    unsigned int  ttotLastCharIndex;
    } TrueTypeOS_2Table;

typedef struct TrueTypeHeadTable
    {
    unsigned long tthtVersion;
    unsigned long tthtFontRevision;
    unsigned long tthtChecksumAdjust;
    unsigned long tthtMagicNo;
    unsigned int  tthtFlags;
    unsigned int  tthtUnitsPerEm;
    unsigned char tthtCreated[8+1];
    unsigned char tthtModified[8+1];
    int                 tthtXMin;
    int                 tthtYMin;
    int                 tthtXMax;
    int                 tthtYMax;
    unsigned int  tthtMacStyle;
    unsigned int  tthtLowestRecPPem;
    int                 tthtFontDirection;
    int                 tthtIndexToLocFormat;
    int                 tthtGlyphDataFormat;
    } TrueTypeHeadTable;

typedef struct TrueTypePostTable
    {
    int                 ttptFormatUpper;
    unsigned int  ttptFormatLower;
    int                 ttptItalicAngleUpper;
    unsigned int  ttptItalicAngleLower;
    int                 ttptUnderlinePosition;
    int                 ttptUnderlineThickness;
    unsigned int  ttptIsFixedPitch;
    /* unsigned int     ttptReserved */
    unsigned long ttptMinMemType42;
    unsigned long ttptMaxMemType42;
    unsigned long ttptMinMemType1;
    unsigned long ttptMaxMemType1;

    unsigned int  ttptIndexCount;
    unsigned short *    ttptIndices;
    unsigned int  ttptStringCount;
    unsigned char **    ttptStrings;
    } TrueTypePostTable;

typedef struct TrueTypeHheaTable
    {
    unsigned char hheaVersion[4+1];
    int                 hheaAscender;
    int                 hheaDescender;
    int                 hheaLineGap;
    unsigned int  hheaMaxAdvanceWidth;
    int                 hheaMinLsb;
    int                 hheaMinRsb;
    int                 hheaXMaxExtent;
    int                 hheaCaretSlopeRise;
    int                 hheaCaretSlopeRun;
    /* int        hheaReserved[5]; */
    int                 hheaMetricDataFormat;
    unsigned int  hheaMetricCount;
    } TrueTypeHheaTable;

typedef struct HorizontalMetric
    {
    unsigned int  hmAdvanceWidth;
    int                 hmLsb;
    } HorizontalMetric;

typedef struct TrueTypeGlyph
    {
    int                       ttgContourCount;  /* signed ! */
    int                       ttgXMin;
    int                       ttgYMin;
    int                       ttgXMax;
    int                       ttgYMax;

    const unsigned char *     ttgData;
    } TrueTypeGlyph;

typedef struct TrueTypeCmapRecord
    {
    unsigned int        ttcrPlatformID;         /*  1  */
    unsigned int        ttcrEncodingID;
    unsigned long       ttcrOffset;


    unsigned int        ttcrFormat;
    unsigned int        ttcrLength;
    unsigned int        ttcrLanguage;

                        /*  If format == 0  */
    unsigned char       ttcr0GlyphIDArray[256];

                        /*  If format == 4  */
    unsigned int        ttcr4SegCountX2;
    unsigned int        ttcr4SearchRange;
    unsigned int        ttcr4EntrySelector;
    unsigned int        ttcr4RangeShift;

    const unsigned char *     ttcr4Data;
    } TrueTypeCmapRecord;

typedef struct TrueTypeCmapTable
    {
    int                       ttctVersion;
    int                       ttctEncodingRecordCount;
    TrueTypeCmapRecord *      ttctEncodingRecords;
    } TrueTypeCmapTable;

typedef struct TrueTypeKernPair
    {
    unsigned int  ttkpLeft;
    unsigned int  ttkpRight;
    unsigned int  ttkpValue;
    } TrueTypeKernPair;

typedef struct TrueTypeKernSub
    {
    unsigned int  ttksVersion;
    unsigned int  ttksLength;
    unsigned int  ttksCoverage;
                        /*  Bits in Coverage:               */
                        /*  0x8000: Has vertical kerning values   */
                        /*  0x4000: Has cross stream values */
                        /*  0x4000: Has variation kerning vals    */
                        /*  0x1f00: Unused: must be 0.            */
                        /*  0x00ff: Contain the format in which   */
                        /*          the pairs are stored.   */
                        /*  So normal horizontal kerning stored   */
                        /*  as pairs has zero upper and lower     */
                        /*  bytes.                    */
    unsigned int  ttksPairCount;
    unsigned int  ttksSearchRange;
    unsigned int  ttksEntrySelector;
    unsigned int  ttksRangeShift;

    TrueTypeKernPair *  ttksPairs;
    } TrueTypeKernSub;

typedef struct TrueTypeKernTable
    {
    int                       ttktVersion;
    int                       ttktKernSubCount;
    TrueTypeKernSub *         ttktKernSubs;
    } TrueTypeKernTable;

typedef struct TrueTypeFont
    {
    unsigned long       ttfVersion;
    int                       ttfTableCount;
    int                       ttfSearchRange;
    int                       ttfEntrySelector;
    int                       ttfRangeShift;

    TrueTypeTableEntry *      ttfTables;

    TrueTypeNameTable         ttfNameTable;
    TrueTypePostTable         ttfPostTable;
    TrueTypeHeadTable         ttfHeadTable;
    TrueTypeHheaTable         ttfHheaTable;
    TrueTypeCmapTable         ttfCmapTable;
    TrueTypeKernTable         ttfKernTable;
    TrueTypeOS_2Table         ttfOS_2Table;

    unsigned long *           ttfLocations;
    int                       ttfLocationCount;

    HorizontalMetric *        ttfHorizontalMetrics;
    int                       ttfHorizontalMetricCount;

    TrueTypeGlyph *           ttfGlyphs;
    int                       ttfGlyphCount;
    } TrueTypeFont;

/************************************************************************/
/*                                                    */
/*  Elementary bookeeping.                                  */
/*                                                    */
/************************************************************************/

static void utilInitTrueTypeOS_2Table(    TrueTypeOS_2Table *     ttot )
    {
    ttot->ttotVersion= 0;
    ttot->ttotAvgCharWidth= 0;
    ttot->ttotWeightClass= 0;
    ttot->ttotWidthClass= 0;
    ttot->ttotType= 0;
    ttot->ttotSubscriptXSize= 0;
    ttot->ttotSubscriptYSize= 0;
    ttot->ttotSubscriptXOffset= 0;
    ttot->ttotSubscriptYOffset= 0;
    ttot->ttotSuperscriptXSize= 0;
    ttot->ttotSuperscriptYSize= 0;
    ttot->ttotSuperscriptXOffset= 0;
    ttot->ttotSuperscriptYOffset= 0;
    ttot->ttotStrikeoutSize= 0;
    ttot->ttotStrikeoutPosition= 0;
    ttot->ttotFamilyClass= 0;
    memset( ttot->ttotPanose, '\0', 10 );
    ttot->ttotCharRange[0]= 0;
    ttot->ttotCharRange[1]= 0;
    ttot->ttotCharRange[2]= 0;
    ttot->ttotCharRange[3]= 0;
    memset( ttot->ttotVendID, '\0', 4+1 );
    ttot->ttotSelection= 0;
    ttot->ttotFirstCharIndex= 0;
    ttot->ttotLastCharIndex= 0;

    return;
    }

static void utilInitTrueTypePostTable(    TrueTypePostTable *     ttpt )
    {
    ttpt->ttptFormatUpper= 0;
    ttpt->ttptFormatLower= 0;
    ttpt->ttptItalicAngleUpper= 0;
    ttpt->ttptItalicAngleLower= 0;
    ttpt->ttptUnderlinePosition= 0;
    ttpt->ttptUnderlineThickness= 0;
    ttpt->ttptIsFixedPitch= 0;
    ttpt->ttptMinMemType42= 0;
    ttpt->ttptMaxMemType42= 0;
    ttpt->ttptMinMemType1= 0;
    ttpt->ttptMaxMemType1= 0;
    ttpt->ttptIndexCount= 0;
    ttpt->ttptIndices= (unsigned short *)0;
    ttpt->ttptStringCount= 0;
    ttpt->ttptStrings= (unsigned char **)0;
    }

static void utilCleanTrueTypePostTable(   TrueTypePostTable *     ttpt )
    {
    int           name;

    for ( name= 0; name < ttpt->ttptStringCount; name++ )
      {
      if  ( ttpt->ttptStrings[name] )
          { free( ttpt->ttptStrings[name] );    }
      }

    if  ( ttpt->ttptIndices )
      { free( ttpt->ttptIndices );  }
    if  ( ttpt->ttptStrings )
      { free( ttpt->ttptStrings );  }
    }

static void utilInitTrueTypeKernSub(      TrueTypeKernSub * ttks )
    {
    ttks->ttksVersion= 0;
    ttks->ttksLength= 0;
    ttks->ttksCoverage= 0;
    ttks->ttksPairCount= 0;
    ttks->ttksSearchRange= 0;
    ttks->ttksEntrySelector= 0;
    ttks->ttksRangeShift= 0;

    ttks->ttksPairs= (TrueTypeKernPair *)0;
    }

static void utilCleanTrueTypeKernSub(     TrueTypeKernSub * ttks )
    {
    if  ( ttks->ttksPairs )
      { free( ttks->ttksPairs );    }
    }

static void utilInitTrueTypeKernTable(    TrueTypeKernTable *     ttkt )
    {
    ttkt->ttktVersion= 0;
    ttkt->ttktKernSubCount= 0;
    ttkt->ttktKernSubs= (TrueTypeKernSub *)0;
    }

static void utilCleanTrueTypeKernTable(   TrueTypeKernTable *     ttkt )
    {
    int           i;

    for ( i= 0; i < ttkt->ttktKernSubCount; i++ )
      { utilCleanTrueTypeKernSub( &(ttkt->ttktKernSubs[i]) ); }

    if  ( ttkt->ttktKernSubs )
      { free( ttkt->ttktKernSubs ); }

    return;
    }

static void utilInitTrueTypeCmapTable(    TrueTypeCmapTable *     ttct )
    {
    ttct->ttctVersion= 0;
    ttct->ttctEncodingRecordCount= 0;
    ttct->ttctEncodingRecords= (TrueTypeCmapRecord *)0;
    }

static void utilCleanTrueTypeCmapTable(   TrueTypeCmapTable *     ttct )
    {
    if  ( ttct->ttctEncodingRecords )
      { free( ttct->ttctEncodingRecords );      }
    }

static void utilInitTrueTypeNameRecord(   TrueTypeNameRecord *    ttnr )
    {
    ttnr->ttnrPlatformID= 0;
    ttnr->ttnrEncodingID= 0;
    ttnr->ttnrLanguageID= 0;
    ttnr->ttnrNameID= 0;
    ttnr->ttnrLength= 0;
    ttnr->ttnrOffset= 0;

    ttnr->ttnrSavedBytes= (unsigned char *)0;

    return;
    }

static void utilCleanTrueTypeNameRecord(  TrueTypeNameRecord *    ttnr )
    {
    if  ( ttnr->ttnrSavedBytes )
      { free( ttnr->ttnrSavedBytes );     }

    return;
    }

static void utilInitTrueTypeNameTable(    TrueTypeNameTable *     ttnt )
    {
    ttnt->ttntFormat= 0;
    ttnt->ttntRecordCount= 0;
    ttnt->ttntOffset= 0;

    ttnt->ttntRecords= (TrueTypeNameRecord *)0;
    }

static void utilCleanTrueTypeNameTable(   TrueTypeNameTable *     ttnt )
    {
    int           rec;

    for ( rec= 0; rec < ttnt->ttntRecordCount; rec++ )
      { utilCleanTrueTypeNameRecord( &(ttnt->ttntRecords[rec]) ); }

    if  ( ttnt->ttntRecords )
      { free( ttnt->ttntRecords );  }
    }

static void utilInitTrueTypeTableEntry(   TrueTypeTableEntry *    ttte )
    {
    ttte->ttteTag[0]= '\0';
    ttte->ttteChecksum= 0;
    ttte->ttteOffset= 0;
    ttte->ttteLength= 0;
    ttte->ttteBytes= (unsigned char *)0;

    ttte->ttteSaveOffset= 0;

    return;
    }

static void utilCleanTrueTypeTableEntry(  TrueTypeTableEntry *    ttte )
    {
    if  ( ttte->ttteBytes )
      { free( ttte->ttteBytes );    }
    }

static void utilInitTrueTypeFont(   TrueTypeFont *    ttf )
    {
    ttf->ttfVersion= 0;
    ttf->ttfTableCount= 0;
    ttf->ttfSearchRange= 0;
    ttf->ttfEntrySelector= 0;
    ttf->ttfRangeShift= 0;

    ttf->ttfTables= (TrueTypeTableEntry *)0;

    utilInitTrueTypeNameTable( &(ttf->ttfNameTable) );
    /* utilInitTrueTypePostTable( &(ttf->ttfPostTable) ); */
    /* utilInitTrueTypeHeadTable( &(ttf->ttfHeadTable) ); */
    /* utilInitTrueTypeHheaTable( &(ttf->ttfHheaTable) ); */
    utilInitTrueTypeCmapTable( &(ttf->ttfCmapTable) );
    utilInitTrueTypeKernTable( &(ttf->ttfKernTable) );
    utilInitTrueTypePostTable( &(ttf->ttfPostTable) );
    utilInitTrueTypeOS_2Table( &(ttf->ttfOS_2Table) );

    ttf->ttfLocations= (unsigned long *)0;
    ttf->ttfLocationCount= 0;

    ttf->ttfHorizontalMetrics= (HorizontalMetric *)0;
    ttf->ttfHorizontalMetricCount= 0;

    ttf->ttfGlyphs= (TrueTypeGlyph *)0;
    ttf->ttfGlyphCount= 0;

    return;
    }

static void utilCleanTrueTypeFont(  TrueTypeFont *    ttf )
    {
    int           ent;

    for ( ent= 0; ent < ttf->ttfTableCount; ent++ )
      { utilCleanTrueTypeTableEntry( &(ttf->ttfTables[ent]) );    }

    if  ( ttf->ttfTables )
      { free( ttf->ttfTables );     }

    utilCleanTrueTypeNameTable( &(ttf->ttfNameTable) );
    /* utilCleanTrueTypePostTable( &(ttf->ttfPostTable) ); */
    /* utilCleanTrueTypeHeadTable( &(ttf->ttfHeadTable) ); */
    /* utilCleanTrueTypeHheaTable( &(ttf->ttfHheaTable) ); */
    utilCleanTrueTypeCmapTable( &(ttf->ttfCmapTable) );
    utilCleanTrueTypeKernTable( &(ttf->ttfKernTable) );
    utilCleanTrueTypePostTable( &(ttf->ttfPostTable) );
    /* utilCleanTrueTypeOS_2Table( &(ttf->ttfOS_2Table) ); */

    if  ( ttf->ttfLocations )
      { free( ttf->ttfLocations );  }

    if  ( ttf->ttfHorizontalMetrics )
      { free( ttf->ttfHorizontalMetrics );      }

    if  ( ttf->ttfGlyphs )
      { free( ttf->ttfGlyphs );     }

    return;
    }

static int utilTrueTypeFontCompareTables( const void *      vttte1,
                                    const void *      vttte2 )
    {
    const TrueTypeTableEntry *      ttte1= (const TrueTypeTableEntry *)vttte1;
    const TrueTypeTableEntry *      ttte2= (const TrueTypeTableEntry *)vttte2;

    if  ( ttte1->ttteOffset > ttte2->ttteOffset )
      { return  1;      }
    if  ( ttte1->ttteOffset < ttte2->ttteOffset )
      { return -1;      }

    return 0;
    }

/************************************************************************/
/*                                                    */
/*  Open a stream to one of the tables.                           */
/*                                                    */
/************************************************************************/

static SimpleInputStream * utilTtfOpenTableStream(
                              MemoryBuffer *                mb,
                              const TrueTypeTableEntry **   pTtte,
                              const char *                  tag,
                              const TrueTypeFont *          ttf )
    {
    int                       tab;
    const TrueTypeTableEntry *      ttte;
    SimpleInputStream *       sis;

    ttte= ttf->ttfTables;
    for ( tab= 0; tab < ttf->ttfTableCount; ttte++, tab++ )
      {
      if  ( ! strcmp( ttte->ttteTag, tag ) )
          { break;      }
      }

    if  ( tab >= ttf->ttfTableCount )
      { /*SLDEB(tag,ttf->ttfTableCount);*/ return (SimpleInputStream *)0; }

    mb->mbBytes= ttte->ttteBytes;
    mb->mbSize= ttte->ttteLength;

    sis= sioInMemoryOpen( mb );
    if  ( ! sis )
      { XDEB(sis); return (SimpleInputStream *)0;     }

    *pTtte= ttte;
    return sis;
    }

/************************************************************************/
/*                                                    */
/*  Extract the name table from a TrueType file.                  */
/*                                                    */
/************************************************************************/

static int utilTtfExtractNameTable( TrueTypeFont *    ttf )
    {
    int                       rval= 0;

    int                       rec;
    MemoryBuffer        mb;
    SimpleInputStream *       sisName= (SimpleInputStream *)0;
    const TrueTypeTableEntry *      ttte;

    TrueTypeNameTable *       ttnt= &(ttf->ttfNameTable);
    TrueTypeNameRecord *      ttnr;

    int                       recordCount;

    utilInitMemoryBuffer( &mb );

    sisName= utilTtfOpenTableStream( &mb, &ttte, "name", ttf );
    if  ( ! sisName )
      { XDEB(sisName); rval= -1; goto ready;    }

    ttnt->ttntFormat= sioEndianGetBeUint16( sisName );
    recordCount= sioEndianGetBeUint16( sisName );
    ttnt->ttntOffset= sioEndianGetBeUint16( sisName );

    ttnt->ttntRecords= malloc( recordCount* sizeof(TrueTypeNameRecord) );
    if  ( ! ttnt->ttntRecords )
      { LXDEB(recordCount,ttnt->ttntRecords); rval= -1; goto ready; }

    ttnr= ttnt->ttntRecords;
    for ( rec= 0; rec < recordCount; ttnr++, rec++ )
      { utilInitTrueTypeNameRecord( ttnr );     }
    ttnt->ttntRecordCount= recordCount;

    ttnr= ttnt->ttntRecords;
    for ( rec= 0; rec < recordCount; ttnr++, rec++ )
      {
      const unsigned char *   from;

      ttnr->ttnrPlatformID= sioEndianGetBeUint16( sisName );
      ttnr->ttnrEncodingID= sioEndianGetBeUint16( sisName );
      ttnr->ttnrLanguageID= sioEndianGetBeUint16( sisName );
      ttnr->ttnrNameID= sioEndianGetBeUint16( sisName );
      ttnr->ttnrLength= sioEndianGetBeUint16( sisName );
      ttnr->ttnrOffset= sioEndianGetBeUint16( sisName );

      from= ttte->ttteBytes+ ttnt->ttntOffset+ ttnr->ttnrOffset;

      ttnr->ttnrSavedBytes= malloc( ttnr->ttnrLength+ 1 );
      if  ( ! ttnr->ttnrSavedBytes )
          {
          LXDEB(ttnr->ttnrLength,ttnr->ttnrSavedBytes);
          rval= -1; goto ready;
          }

      memcpy( ttnr->ttnrSavedBytes, from, ttnr->ttnrLength );
      ttnr->ttnrSavedBytes[ttnr->ttnrLength]= '\0';

      /* LLSDEB(rec,ttnr->ttnrLength,(char *)ttnr->ttnrSavedBytes); */
      }

  ready:

    if  ( sisName )
      { sioInClose( sisName );      }

    return rval;
    }

static int utilTtfExtractPostTable( TrueTypeFont *    ttf )
    {
    int                       rval= 0;

    MemoryBuffer        mb;
    SimpleInputStream *       sisPost= (SimpleInputStream *)0;
    const TrueTypeTableEntry *      ttte;
    unsigned int        reserved;

    TrueTypePostTable *       ttpt= &(ttf->ttfPostTable);
    unsigned int        idxCount= 0;
    unsigned int        stringCount= 0;
    int                       name;

    utilInitMemoryBuffer( &mb );

    sisPost= utilTtfOpenTableStream( &mb, &ttte, "post", ttf );
    if  ( ! sisPost )
      { XDEB(sisPost); rval= -1; goto ready;    }

    ttpt->ttptFormatUpper= sioEndianGetBeInt16( sisPost );
    ttpt->ttptFormatLower= sioEndianGetBeUint16( sisPost );
    ttpt->ttptItalicAngleUpper= sioEndianGetBeInt16( sisPost );
    ttpt->ttptItalicAngleLower= sioEndianGetBeUint16( sisPost );
    ttpt->ttptUnderlinePosition= sioEndianGetBeInt16( sisPost );
    ttpt->ttptUnderlineThickness= sioEndianGetBeInt16( sisPost );
    ttpt->ttptIsFixedPitch= sioEndianGetBeUint16( sisPost );
    reserved= sioEndianGetBeUint16( sisPost );
    ttpt->ttptMinMemType42= sioEndianGetBeUint32( sisPost );
    ttpt->ttptMaxMemType42= sioEndianGetBeUint32( sisPost );
    ttpt->ttptMinMemType1= sioEndianGetBeUint32( sisPost );
    ttpt->ttptMaxMemType1= sioEndianGetBeUint32( sisPost );

    switch( ttpt->ttptFormatUpper )
      {
      case 2:
          if  ( ttpt->ttptFormatLower != 0 )
            { LDEB(ttpt->ttptFormatLower); goto ready;      }

          idxCount= sioEndianGetBeUint16( sisPost );
          ttpt->ttptIndices= malloc( idxCount* sizeof(unsigned short) );
          if  ( ! ttpt->ttptIndices )
            { LXDEB( idxCount, ttpt->ttptIndices ); rval= -1; goto ready; }

          for ( name= 0; name < idxCount; name++ )
            { ttpt->ttptIndices[name]= 0; }
          ttpt->ttptIndexCount= idxCount;

          stringCount= 0;
          for ( name= 0; name < idxCount; name++ )
            {
            ttpt->ttptIndices[name]= sioEndianGetBeUint16( sisPost );
            if  ( ttpt->ttptIndices[name] >= 258 )
                { stringCount++;    }
            }

          if  ( stringCount > 0 )
            {
            ttpt->ttptStrings= malloc( stringCount*
                                        sizeof(unsigned char *) );
            if  ( ! ttpt->ttptStrings )
                {
                LXDEB(stringCount, ttpt->ttptStrings);
                rval= -1; goto ready;
                }

            for ( name= 0; name < stringCount; name++ )
                { ttpt->ttptStrings[name]= (unsigned char *)0; }

            ttpt->ttptStringCount= stringCount;

            for ( name= 0; name < stringCount; name++ )
                {
                int     size= sioInGetCharacter( sisPost );

                ttpt->ttptStrings[name]= malloc( size+ 1 );
                if  ( ! ttpt->ttptStrings[name] )
                  {
                  LXDEB(size,ttpt->ttptStrings[name]);
                  rval= -1; goto ready;
                  }

                if  ( sioInReadBytes( sisPost, ttpt->ttptStrings[name],
                                                size ) != size )
                  { LDEB(size); rval= -1; goto ready; }
                ttpt->ttptStrings[name][size]= '\0';
                }
            }

          break;

      default:
          LLDEB(ttpt->ttptFormatUpper,ttpt->ttptFormatLower);
          break;
      }

  ready:

    if  ( sisPost )
      { sioInClose( sisPost );      }

    return rval;
    }

static int utilTtfExtractOS_2Table( TrueTypeFont *    ttf )
    {
    int                       rval= 0;

    MemoryBuffer        mb;
    SimpleInputStream *       sisOS_2= (SimpleInputStream *)0;
    const TrueTypeTableEntry *      ttte;

    TrueTypeOS_2Table *       ttot= &(ttf->ttfOS_2Table);
    int                       i;

    utilInitMemoryBuffer( &mb );

    sisOS_2= utilTtfOpenTableStream( &mb, &ttte, "OS/2", ttf );
    if  ( ! sisOS_2 )
      { XDEB(sisOS_2); goto ready;  }

    ttot->ttotVersion= sioEndianGetBeUint16( sisOS_2 );
    ttot->ttotAvgCharWidth= sioEndianGetBeUint16( sisOS_2 );
    ttot->ttotWeightClass= sioEndianGetBeUint16( sisOS_2 );
    ttot->ttotWidthClass= sioEndianGetBeUint16( sisOS_2 );
    ttot->ttotType= sioEndianGetBeInt16( sisOS_2 );
    ttot->ttotSubscriptXSize= sioEndianGetBeInt16( sisOS_2 );
    ttot->ttotSubscriptYSize= sioEndianGetBeInt16( sisOS_2 );
    ttot->ttotSubscriptXOffset= sioEndianGetBeInt16( sisOS_2 );
    ttot->ttotSubscriptYOffset= sioEndianGetBeInt16( sisOS_2 );
    ttot->ttotSuperscriptXSize= sioEndianGetBeInt16( sisOS_2 );
    ttot->ttotSuperscriptYSize= sioEndianGetBeInt16( sisOS_2 );
    ttot->ttotSuperscriptXOffset= sioEndianGetBeInt16( sisOS_2 );
    ttot->ttotSuperscriptYOffset= sioEndianGetBeInt16( sisOS_2 );
    ttot->ttotStrikeoutSize= sioEndianGetBeInt16( sisOS_2 );
    ttot->ttotStrikeoutPosition= sioEndianGetBeInt16( sisOS_2 );
    ttot->ttotFamilyClass= sioEndianGetBeInt16( sisOS_2 );

    for ( i= 0; i < 10; i++ )
      { ttot->ttotPanose[i]= sioInGetCharacter( sisOS_2 );  }

    ttot->ttotCharRange[0]= sioEndianGetBeUint32( sisOS_2 );
    ttot->ttotCharRange[1]= sioEndianGetBeUint32( sisOS_2 );
    ttot->ttotCharRange[2]= sioEndianGetBeUint32( sisOS_2 );
    ttot->ttotCharRange[3]= sioEndianGetBeUint32( sisOS_2 );

    for ( i= 0; i < 4; i++ )
      { ttot->ttotVendID[i]= sioInGetCharacter( sisOS_2 );  }
    ttot->ttotVendID[i]= '\0';

    ttot->ttotSelection= sioEndianGetBeUint16( sisOS_2 );
    ttot->ttotFirstCharIndex= sioEndianGetBeUint16( sisOS_2 );
    ttot->ttotLastCharIndex= sioEndianGetBeUint16( sisOS_2 );

  ready:

    if  ( sisOS_2 )
      { sioInClose( sisOS_2 );      }

    return rval;
    }

/************************************************************************/
/*                                                    */
/*  Extract the Hhea table from a TrueType file.                  */
/*                                                    */
/************************************************************************/

static int utilTtfExtractHheaTable( TrueTypeFont *    ttf )
    {
    int                       rval= 0;

    MemoryBuffer        mb;
    SimpleInputStream *       sisHhea= (SimpleInputStream *)0;
    const TrueTypeTableEntry *      ttte;

    int                       i;
    int                       reserved;

    TrueTypeHheaTable *       hhea= &(ttf->ttfHheaTable);

    utilInitMemoryBuffer( &mb );

    sisHhea= utilTtfOpenTableStream( &mb, &ttte, "hhea", ttf );
    if  ( ! sisHhea )
      { XDEB(sisHhea); rval= -1; goto ready;    }

    for ( i= 0; i < 4; i++ )
      { hhea->hheaVersion[i]= sioInGetCharacter( sisHhea ); }
    hhea->hheaVersion[4]= '\0';

    hhea->hheaAscender= sioEndianGetBeInt16( sisHhea );
    hhea->hheaDescender= sioEndianGetBeInt16( sisHhea );
    hhea->hheaLineGap= sioEndianGetBeInt16( sisHhea );
    hhea->hheaMaxAdvanceWidth= sioEndianGetBeUint16( sisHhea );
    hhea->hheaMinLsb= sioEndianGetBeInt16( sisHhea );
    hhea->hheaMinRsb= sioEndianGetBeInt16( sisHhea );
    hhea->hheaXMaxExtent= sioEndianGetBeInt16( sisHhea );
    hhea->hheaCaretSlopeRise= sioEndianGetBeInt16( sisHhea );
    hhea->hheaCaretSlopeRun= sioEndianGetBeInt16( sisHhea );

    for ( i= 0; i < 5; i++ )
      { reserved= sioEndianGetBeInt16( sisHhea );     }

    hhea->hheaMetricDataFormat= sioEndianGetBeInt16( sisHhea );
    hhea->hheaMetricCount= sioEndianGetBeUint16( sisHhea );

  ready:

    if  ( sisHhea )
      { sioInClose( sisHhea );      }

    return rval;
    }

/************************************************************************/
/*                                                    */
/*  Extract the head table from a TrueType file.                  */
/*                                                    */
/************************************************************************/

static int utilTtfExtractHeadTable( TrueTypeFont *    ttf )
    {
    int                       rval= 0;

    MemoryBuffer        mb;
    SimpleInputStream *       sisHead= (SimpleInputStream *)0;
    const TrueTypeTableEntry *      ttte;

    TrueTypeHeadTable *       ttht= &(ttf->ttfHeadTable);

    int                       i;

    utilInitMemoryBuffer( &mb );

    sisHead= utilTtfOpenTableStream( &mb, &ttte, "head", ttf );
    if  ( ! sisHead )
      { XDEB(sisHead); rval= -1; goto ready;    }

    ttht->tthtVersion= sioEndianGetBeUint32( sisHead );
    ttht->tthtFontRevision= sioEndianGetBeUint32( sisHead );
    ttht->tthtChecksumAdjust= sioEndianGetBeUint32( sisHead );
    ttht->tthtMagicNo= sioEndianGetBeUint32( sisHead );
    ttht->tthtFlags= sioEndianGetBeUint16( sisHead );
    ttht->tthtUnitsPerEm= sioEndianGetBeUint16( sisHead );

    for ( i= 0; i < 8; i++ )
      { ttht->tthtCreated[i]= sioInGetCharacter( sisHead ); }
    ttht->tthtCreated[8]= '\0';

    for ( i= 0; i < 8; i++ )
      { ttht->tthtModified[i]= sioInGetCharacter( sisHead ); }
    ttht->tthtModified[8]= '\0';

    ttht->tthtXMin= sioEndianGetBeInt16( sisHead );
    ttht->tthtYMin= sioEndianGetBeInt16( sisHead );
    ttht->tthtXMax= sioEndianGetBeInt16( sisHead );
    ttht->tthtYMax= sioEndianGetBeInt16( sisHead );

    ttht->tthtMacStyle= sioEndianGetBeUint16( sisHead );
    ttht->tthtLowestRecPPem= sioEndianGetBeUint16( sisHead );
    ttht->tthtFontDirection= sioEndianGetBeInt16( sisHead );
    ttht->tthtIndexToLocFormat= sioEndianGetBeInt16( sisHead );
    ttht->tthtGlyphDataFormat= sioEndianGetBeInt16( sisHead );

  ready:

    if  ( sisHead )
      { sioInClose( sisHead );      }

    return rval;
    }

/************************************************************************/
/*                                                    */
/*  Extract the location table from a TrueType file.              */
/*                                                    */
/************************************************************************/

static int utilTtfExtractLocaTable( TrueTypeFont *    ttf )
    {
    int                       rval= 0;

    MemoryBuffer        mb;
    SimpleInputStream *       sisLoca= (SimpleInputStream *)0;
    const TrueTypeTableEntry *      ttte;

    TrueTypeHeadTable *       ttht= &(ttf->ttfHeadTable);

    int                       i;

    utilInitMemoryBuffer( &mb );

    sisLoca= utilTtfOpenTableStream( &mb, &ttte, "loca", ttf );
    if  ( ! sisLoca )
      { XDEB(sisLoca); rval= -1; goto ready;    }

    switch( ttht->tthtIndexToLocFormat )
      {
      case 0:
          if  ( ttte->ttteLength % 2 )
            { LLDEB(ttte->ttteLength,2); rval= -1; goto ready; }
          ttf->ttfLocationCount= ttte->ttteLength/ 2;
          break;

      case 1:
          if  ( ttte->ttteLength % 4 )
            { LLDEB(ttte->ttteLength,4); rval= -1; goto ready; }
          ttf->ttfLocationCount= ttte->ttteLength/ 4;
          break;
      default:
          LDEB(ttht->tthtIndexToLocFormat); rval= -1; goto ready;
      }

    ttf->ttfLocations= malloc( ttf->ttfLocationCount* sizeof(unsigned long) );
    if  ( ! ttf->ttfLocations )
      {
      LXDEB(ttf->ttfLocationCount,ttf->ttfLocations);
      rval= -1; goto ready;
      }

    switch( ttht->tthtIndexToLocFormat )
      {
      case 0:
          for ( i= 0; i < ttf->ttfLocationCount; i++ )
            { ttf->ttfLocations[i]= 2* sioEndianGetBeUint16( sisLoca ); }
          break;

      case 1:
          for ( i= 0; i < ttf->ttfLocationCount; i++ )
            { ttf->ttfLocations[i]= sioEndianGetBeUint32( sisLoca ); }
          break;

      default:
          LDEB(ttht->tthtIndexToLocFormat); rval= -1; goto ready;
      }

  ready:

    if  ( sisLoca )
      { sioInClose( sisLoca );      }

    return rval;
    }

/************************************************************************/
/*                                                    */
/*  Extract the horizontal metrics table from a TrueType file.          */
/*                                                    */
/************************************************************************/

static int utilTtfExtractHmtxTable( TrueTypeFont *    ttf )
    {
    int                       rval= 0;

    MemoryBuffer        mb;
    SimpleInputStream *       sisHmtx= (SimpleInputStream *)0;
    const TrueTypeTableEntry *      ttte;

    int                       i;

    utilInitMemoryBuffer( &mb );

    sisHmtx= utilTtfOpenTableStream( &mb, &ttte, "hmtx", ttf );
    if  ( ! sisHmtx )
      { XDEB(sisHmtx); rval= -1; goto ready;    }


    if  ( ttte->ttteLength % 4 )
      { LLDEB(ttte->ttteLength,4); rval= -1; goto ready; }
    ttf->ttfHorizontalMetricCount= ttte->ttteLength/ 4;

    ttf->ttfHorizontalMetrics= malloc( ttf->ttfHorizontalMetricCount*
                                        sizeof(HorizontalMetric) );
    if  ( ! ttf->ttfHorizontalMetrics )
      {
      LXDEB(ttf->ttfHorizontalMetricCount,ttf->ttfHorizontalMetrics);
      rval= -1; goto ready;
      }

    for ( i= 0; i < ttf->ttfHorizontalMetricCount; i++ )
      {
      ttf->ttfHorizontalMetrics[i].hmAdvanceWidth=
                                  sioEndianGetBeUint16( sisHmtx );
      ttf->ttfHorizontalMetrics[i].hmLsb= sioEndianGetBeInt16( sisHmtx );
      }

  ready:

    if  ( sisHmtx )
      { sioInClose( sisHmtx );      }

    return rval;
    }

/************************************************************************/
/*                                                    */
/*  Extract the glyph table from a TrueType file.                 */
/*                                                    */
/************************************************************************/

# define GLYFSZ                     2000

# define ONOROFF              0x01
# define XSHORT                     0x02
# define YSHORT                     0x04
# define REPEAT                     0x08
# define XSAME                      0x10
# define YSAME                      0x20

# define ARG_1_AND_2_ARE_WORDS            0x0001
# define ARGS_ARE_XY_VALUES         0x0002
# define XY_BOUND_TO_GRID           0x0004
# define WE_HAVE_A_SCALE            0x0008
# define MORE_COMPONENTS            0x0020
# define WE_HAVE_AN_X_AND_Y_SCALE   0x0040
# define WE_HAVE_A_TWO_BY_TWO       0x0080
# define WE_HAVE_INSTRUCTIONS       0x0100
# define USE_MY_METRICS             0x0200

# define fg_rmoveto(a,x,y) appDebug( "fg_rmoveto( %g, %g )\n", x, y )
# define fg_rlineto(a,x,y) appDebug( "fg_rlineto( %g, %g )\n", x, y )
# define g_closepath(a) appDebug( "g_closepath()\n" )
# define fg_rrcurveto(a,x1,y1,x2,y2,x3,y3) appDebug( "fg_rrcurveto(%g,%g,%g,%g,%g,%g)\n", x1,y1,x2,y2,x3,y3 )

static int utilTtfTranslateSimpleGlyphData(
                            const TrueTypeFont *      ttf,
                            const AffineTransform2D * at,
                            const TrueTypeGlyph *     ttg )
    {
    const TrueTypeHeadTable * ttht= &(ttf->ttfHeadTable);
    double              fac= 1000.0/ ttht->tthtUnitsPerEm;
    const unsigned char *     data= ttg->ttgData;

    int                       cc= ttg->ttgContourCount;

    unsigned char       flag[GLYFSZ];
    int                       xrel[GLYFSZ];
    int                       yrel[GLYFSZ];
    double              xc[GLYFSZ];
    double              yc[GLYFSZ];

    const unsigned char *     cep;
    const unsigned char *     p;
    int                       lastP;
    int                       nP;

    int                       k;
    int                       j;
    int                       i;

    double              x;
    double              y;

    cep= data;
    lastP= utilEndianExtractBeInt16( cep+ 2* cc- 2  );
    nP= utilEndianExtractBeInt16( cep+ 2* cc  );
    p= cep+ 2* cc+ nP+ 2;

    j= k= 0;
    while( k <= lastP )
      {
      flag[k]= p[j];
      if  ( p[j] & REPEAT )
          {
          int     n= p[j+1];

          while( n > 0 )
            { flag[++k]= p[j]; n--; }
          j++;
          }
      j++; k++;
      }

    for ( k= 0; k <= lastP; k++ )
      {
      if  ( flag[k] & XSHORT )
          {
          if  ( flag[k] & XSAME )
            { xrel[k] =  p[j++];    }
          else{ xrel[k] = -p[j++];  }
          }
      else{
          if  ( flag[k] & XSAME )
            { xrel[k]= 0;                       }
          else{ xrel[k]= utilEndianExtractBeInt16( p+ j ); j += 2;      }
          }
      }

    for ( k= 0; k <= lastP; k++ )
      {
      if  ( flag[k] & YSHORT )
          {
          if  ( flag[k] & YSAME )
            { yrel[k] =  p[j++];    }
          else{ yrel[k] = -p[j++];  }
          }
      else{
          if  ( flag[k] & YSAME )
            { yrel[k]= 0;                       }
          else{ yrel[k]= utilEndianExtractBeInt16( p+ j ); j += 2;      }
          }
      }

    x= xrel[0];
    y= yrel[0];
    if  ( at )
      {
      xc[0]= fac* AT2_X( x, y, at );
      yc[0]= fac* AT2_Y( x, y, at );

      for ( k= 1; k <= lastP; k++ )
          {
          x += xrel[k];
          y += yrel[k];

          xc[k]= fac* AT2_X( x, y, at );
          yc[k]= fac* AT2_Y( x, y, at );
          }
      }
    else{
      xc[0]= fac* x;
      yc[0]= fac* y;

      for ( k= 1; k <= lastP; k++ )
          {
          x += xrel[k];
          y += yrel[k];

          xc[k]= fac* x;
          yc[k]= fac* y;
          }
      }

    i= j= 0;
    x= xc[0]; y= yc[0];
    while( i <= lastP )
      {
      int   contEnd= utilEndianExtractBeUint16( cep+ 2* j  );
      int   contStart= i;

      if  ( i <= contEnd )
          {
          x= xc[i]; y= yc[i];
          fg_rmoveto( g, x, y );
          i++;
          }

      while( i <= contEnd )
          {
          int           cs;
          int           ce;
          int           nguide;

          if  ( flag[i] & ONOROFF )
            {
            x= xc[i]; y= yc[i];
            fg_rlineto( g, x, y );
            i++; continue;
            }

          cs= i- 1; nguide= 0;
          for (;;)
            {
            if  ( i > contEnd )
                { ce= contStart; break;   }
            if  ( flag[i] & ONOROFF )
                { ce= i; break; }
            i++; nguide++;
            }

          switch( nguide )
            {
            int         k1;

            case 0:
                fg_rlineto(g, xc[ce], yc[ce]);

                x = xc[ce]; y = yc[ce]; break;

            case 1:
                fg_rrcurveto(g,
                        (xc[cs] + 2.0 * xc[cs + 1]) / 3.0,
                        (yc[cs] + 2.0 * yc[cs + 1]) / 3.0,
                        (2.0 * xc[cs + 1] + xc[ce]) / 3.0,
                        (2.0 * yc[cs + 1] + yc[ce]) / 3.0,
                            xc[ce], yc[ce] );

                x = xc[ce]; y = yc[ce]; break;

            case 2:
                fg_rrcurveto(g,
                       (-xc[cs] + 4.0 * xc[cs + 1]) / 3.0,
                       (-yc[cs] + 4.0 * yc[cs + 1]) / 3.0,
                        (4.0 * xc[cs + 2] - xc[ce]) / 3.0,
                        (4.0 * yc[cs + 2] - yc[ce]) / 3.0,
                            xc[ce], yc[ce] );

                x = xc[ce]; y = yc[ce]; break;

            case 3:
                fg_rrcurveto(g,
                        (xc[cs] + 2.0 * xc[cs + 1]) / 3.0,
                        (yc[cs] + 2.0 * yc[cs + 1]) / 3.0,
                    (5.0 * xc[cs + 1] + xc[cs + 2]) / 6.0,
                    (5.0 * yc[cs + 1] + yc[cs + 2]) / 6.0,
                        (xc[cs + 1] + xc[cs + 2]) / 2.0,
                        (yc[cs + 1] + yc[cs + 2]) / 2.0 );

                fg_rrcurveto(g,
                    (xc[cs + 1] + 5.0 * xc[cs + 2]) / 6.0,
                    (yc[cs + 1] + 5.0 * yc[cs + 2]) / 6.0,
                    (5.0 * xc[cs + 2] + xc[cs + 3]) / 6.0,
                    (5.0 * yc[cs + 2] + yc[cs + 3]) / 6.0,
                        (xc[cs + 3] + xc[cs + 2]) / 2.0,
                        (yc[cs + 3] + yc[cs + 2]) / 2.0 );

                fg_rrcurveto(g,
                    (xc[cs + 2] + 5.0 * xc[cs + 3]) / 6.0,
                    (yc[cs + 2] + 5.0 * yc[cs + 3]) / 6.0,
                        (2.0 * xc[cs + 3] + xc[ce]) / 3.0,
                        (2.0 * yc[cs + 3] + yc[ce]) / 3.0,
                            xc[ce], yc[ce] );

                y = yc[ce]; x = xc[ce]; break;

            default:
                k1 = cs + nguide;
                fg_rrcurveto(g,
                        (xc[cs] + 2.0 * xc[cs + 1]) / 3.0,
                        (yc[cs] + 2.0 * yc[cs + 1]) / 3.0,
                    (5.0 * xc[cs + 1] + xc[cs + 2]) / 6.0,
                    (5.0 * yc[cs + 1] + yc[cs + 2]) / 6.0,
                        (xc[cs + 1] + xc[cs + 2]) / 2.0,
                        (yc[cs + 1] + yc[cs + 2]) / 2.0 );

                for (k = cs + 2; k <= k1 - 1; k++)
                  {
                  fg_rrcurveto(g,
                        (xc[k - 1] + 5.0 * xc[k]) / 6.0,
                        (yc[k - 1] + 5.0 * yc[k]) / 6.0,
                        (5.0 * xc[k] + xc[k + 1]) / 6.0,
                        (5.0 * yc[k] + yc[k + 1]) / 6.0,
                            (xc[k] + xc[k + 1]) / 2.0,
                            (yc[k] + yc[k + 1]) / 2.0 );

                  }

                fg_rrcurveto(g,
                        (xc[k1 - 1] + 5.0 * xc[k1]) / 6.0,
                        (yc[k1 - 1] + 5.0 * yc[k1]) / 6.0,
                          (2.0 * xc[k1] + xc[ce]) / 3.0,
                          (2.0 * yc[k1] + yc[ce]) / 3.0,
                            xc[ce], yc[ce] );

                x = xc[ce]; y = yc[ce]; 
                break;
            }
          }

      g_closepath( g );
      i++; j++;
      }

    return 0;
    }

static double utilTtfMatrixElement( const unsigned char *   data )
    {
    int           val= utilEndianExtractBeInt16( data );

    return ( val >> 14 )+ (( val & 0x3fff )/ 16384.0 );
    }

static int utilTtfTranslateGlyphData(
                        const TrueTypeFont *          ttf,
                        const AffineTransform2D *     at,
                        const TrueTypeGlyph *         ttg )
    {
    const unsigned char *     data= ttg->ttgData;
    unsigned int        flags;

    if  ( ttg->ttgContourCount >= 0 )
      {
      utilTtfTranslateSimpleGlyphData( ttf, at, ttg );
      return 0;
      }

    do  {
      unsigned int            glyphno;
      int               arg1;
      int               arg2;

      AffineTransform2D atHere;

      utilIdentityAffineTransform2D( &atHere );

      flags= utilEndianExtractBeUint16( data ); data += 2;
      glyphno= utilEndianExtractBeUint16( data ); data += 2;

      if  ( flags & ARG_1_AND_2_ARE_WORDS )
          {
          arg1= utilEndianExtractBeInt16( data ); data += 2;
          arg2= utilEndianExtractBeInt16( data ); data += 2;
          }
      else{
          arg1= *((signed char *)data); data++;
          arg2= *((signed char *)data); data++;
          }

      if  ( flags & WE_HAVE_A_SCALE )
          {
          atHere.at2Axx= utilTtfMatrixElement( data ); data += 2;
          atHere.at2Ayy= atHere.at2Axx;
          }
      else{
          if  ( flags & WE_HAVE_AN_X_AND_Y_SCALE )
            {
            atHere.at2Axx= utilTtfMatrixElement( data ); data += 2;
            atHere.at2Ayy= utilTtfMatrixElement( data ); data += 2;
            }
          else{
            if  ( flags & WE_HAVE_A_TWO_BY_TWO )
                {
                atHere.at2Axx= utilTtfMatrixElement( data ); data += 2;
                atHere.at2Ayx= utilTtfMatrixElement( data ); data += 2;
                atHere.at2Axy= utilTtfMatrixElement( data ); data += 2;
                atHere.at2Ayy= utilTtfMatrixElement( data ); data += 2;
                }
            }
          }

      if  ( glyphno >= ttf->ttfGlyphCount )
          { LLDEB(glyphno,ttf->ttfGlyphCount); return -1; }

      if  ( fabs( atHere.at2Axx ) > fabs( atHere.at2Axy ) )
          { atHere.at2Tx= fabs( atHere.at2Axx );      }
      else{ atHere.at2Tx= fabs( atHere.at2Axy );      }
      if  ( fabs( fabs( atHere.at2Axx )- fabs( atHere.at2Ayx ) )
                                          <= 33.0/ 65536.0 )
          { atHere.at2Tx *= 2.0;    }

      if  ( fabs( atHere.at2Ayx ) > fabs( atHere.at2Ayy ) )
          { atHere.at2Ty= fabs( atHere.at2Ayx );      }
      else{ atHere.at2Ty= fabs( atHere.at2Ayy );      }
      if  ( fabs( fabs( atHere.at2Ayx )- fabs( atHere.at2Ayy ) )
                                          <= 33.0/ 65536.0 )
          { atHere.at2Ty *= 2.0;    }

      if  ( flags & ARGS_ARE_XY_VALUES )
          {
          atHere.at2Tx *= arg1;
          atHere.at2Ty *= arg2;
          }
      else{
          XXDEB(flags,ARGS_ARE_XY_VALUES);
          }

      if  ( at )
          { utilAffineTransform2DProduct( &atHere, at, &atHere ); }

      utilTtfTranslateGlyphData( ttf, &atHere, ttf->ttfGlyphs+ glyphno );

      } while ( flags & MORE_COMPONENTS );

    return 0;
    }

static int utilTtfTranslateGlyphs(  const TrueTypeFont *    ttf )
    {
    int                       glyphno;
    TrueTypeGlyph *           ttg;

    ttg= ttf->ttfGlyphs;
    for ( glyphno= 0; glyphno < ttf->ttfGlyphCount; ttg++, glyphno++ )
      {
      utilTtfTranslateGlyphData( ttf, (const AffineTransform2D *)0, ttg );
      }

    return 0;
    }

static int utilTtfExtractGlyfTable( TrueTypeFont *    ttf )
    {
    int                       rval= 0;

    int                       tab;
    const TrueTypeTableEntry *      ttte;
    TrueTypeGlyph *           ttg;

    int                       glyphno;

    ttte= ttf->ttfTables;
    for ( tab= 0; tab < ttf->ttfTableCount; ttte++, tab++ )
      {
      if  ( ! strcmp( ttte->ttteTag, "glyf" ) )
          { break;      }
      }

    if  ( tab >= ttf->ttfTableCount )
      { LLDEB(tab,ttf->ttfTableCount); rval= -1; goto ready;      }

    ttf->ttfGlyphCount= ttf->ttfLocationCount- 1;

    ttf->ttfGlyphs= malloc( ttf->ttfGlyphCount* sizeof(TrueTypeGlyph) );
    if  ( ! ttf->ttfGlyphs )
      { LXDEB(ttf->ttfGlyphCount,ttf->ttfGlyphs); rval= -1; goto ready; }

    ttg= ttf->ttfGlyphs;
    for ( glyphno= 0; glyphno < ttf->ttfGlyphCount; ttg++, glyphno++ )
      {
      const unsigned char *   data;

      data= ttte->ttteBytes+ ttf->ttfLocations[glyphno];

      /* signed ! */
      ttg->ttgContourCount= utilEndianExtractBeInt16( data ); data += 2;

      ttg->ttgXMin= utilEndianExtractBeInt16( data ); data += 2;
      ttg->ttgYMin= utilEndianExtractBeInt16( data ); data += 2;
      ttg->ttgXMax= utilEndianExtractBeInt16( data ); data += 2;
      ttg->ttgYMax= utilEndianExtractBeInt16( data ); data += 2;

      ttg->ttgData= data;
      }

  ready:

    return rval;
    }

/************************************************************************/
/*                                                    */
/*  Extract the encoding table from a TrueType file.              */
/*                                                    */
/************************************************************************/

static int utilTtfExtractCmapTable( TrueTypeFont *    ttf )
    {
    int                       rval= 0;

    MemoryBuffer        mb;
    SimpleInputStream *       sisCmap= (SimpleInputStream *)0;
    const TrueTypeTableEntry *      ttte;
    TrueTypeCmapTable *       ttct= &(ttf->ttfCmapTable);
    TrueTypeCmapRecord *      ttcr;

    int                       i;

    utilInitMemoryBuffer( &mb );

    sisCmap= utilTtfOpenTableStream( &mb, &ttte, "cmap", ttf );
    if  ( ! sisCmap )
      { XDEB(sisCmap); rval= -1; goto ready;    }

    ttct->ttctVersion= sioEndianGetBeUint16( sisCmap );
    ttct->ttctEncodingRecordCount= sioEndianGetBeUint16( sisCmap );

    ttct->ttctEncodingRecords= malloc( ttct->ttctEncodingRecordCount*
                                    sizeof(TrueTypeCmapRecord) );
    if  ( ! ttct->ttctEncodingRecords )
      {
      LXDEB(ttct->ttctEncodingRecordCount,ttct->ttctEncodingRecords);
      rval= -1; goto ready;
      }

    ttcr= ttct->ttctEncodingRecords;
    for ( i= 0; i < ttct->ttctEncodingRecordCount; ttcr++, i++ )
      {
      const unsigned char *   p;

      ttcr->ttcrPlatformID= sioEndianGetBeUint16( sisCmap );
      ttcr->ttcrEncodingID= sioEndianGetBeUint16( sisCmap );
      ttcr->ttcrOffset= sioEndianGetBeUint32( sisCmap );

      p= ttte->ttteBytes+ ttcr->ttcrOffset;
      ttcr->ttcrFormat= utilEndianExtractBeUint16( p ); p += 2;
      ttcr->ttcrLength= utilEndianExtractBeUint16( p ); p += 2;
      ttcr->ttcrLanguage= utilEndianExtractBeUint16( p ); p += 2;

      switch( ttcr->ttcrFormat )
          {
          case 0:
            memcpy( ttcr->ttcr0GlyphIDArray, p, ttcr->ttcrLength- 6 );
            break;

          case 4:
            ttcr->ttcr4SegCountX2= utilEndianExtractBeUint16( p ); p += 2;
            ttcr->ttcr4SearchRange= utilEndianExtractBeUint16( p ); p += 2;
            ttcr->ttcr4EntrySelector= utilEndianExtractBeUint16( p ); p += 2;
            ttcr->ttcr4RangeShift= utilEndianExtractBeUint16( p ); p += 2;
            ttcr->ttcr4Data= p;
            break;

          default:
            LDEB(ttcr->ttcrFormat);
            break;
          }
      }

  ready:

    if  ( sisCmap )
      { sioInClose( sisCmap );      }

    return rval;
    }

/************************************************************************/
/*                                                    */
/*  Extract the kerning table from a TrueType file.               */
/*                                                    */
/*  1)  The kerning table is optional, so it is not an error if it      */
/*    cannot be opened.                               */
/*                                                    */
/************************************************************************/

static int ttfExtractFormat0KernPairs(    const TrueTypeKernSub * ttks,
                              const unsigned char *   p )
    {
    int                       pair;
    TrueTypeKernPair *        ttkp;

    ttkp= ttks->ttksPairs;
    for ( pair= 0; pair < ttks->ttksPairCount; ttkp++, pair++ )
      {
      ttkp->ttkpLeft= utilEndianExtractBeUint16( p ); p += 2;
      ttkp->ttkpRight= utilEndianExtractBeUint16( p ); p += 2;
      ttkp->ttkpValue= utilEndianExtractBeUint16( p ); p += 2;
      }

    return 0;
    }

static int utilTtfExtractKernTable( TrueTypeFont *    ttf )
    {
    int                       rval= 0;

    MemoryBuffer        mb;
    SimpleInputStream *       sisKern= (SimpleInputStream *)0;
    const TrueTypeTableEntry *      ttte;
    TrueTypeKernTable *       ttkt= &(ttf->ttfKernTable);
    TrueTypeKernSub *         ttks;

    int                       sub;
    int                       subCount;
    const unsigned char *     data;

    utilInitMemoryBuffer( &mb );

    /*  1  */
    sisKern= utilTtfOpenTableStream( &mb, &ttte, "kern", ttf );
    if  ( ! sisKern )
      { rval= 0; goto ready;  }

    ttkt->ttktVersion= sioEndianGetBeUint16( sisKern );
    subCount= sioEndianGetBeUint16( sisKern );

    ttkt->ttktKernSubs= malloc( subCount* sizeof(TrueTypeKernSub) );
    if  ( ! ttkt->ttktKernSubs )
      {
      LXDEB(subCount,ttkt->ttktKernSubs);
      rval= -1; goto ready;
      }

    ttks= ttkt->ttktKernSubs;
    for ( sub= 0; sub < subCount; ttks++, sub++ )
      { utilInitTrueTypeKernSub( ttks );  }

    ttkt->ttktKernSubCount= subCount;

    data= ttte->ttteBytes+ 4;

    ttks= ttkt->ttktKernSubs;
    for ( sub= 0; sub < subCount; ttks++, sub++ )
      {
      const unsigned char *   p= data;
      unsigned int            format;

      ttks->ttksVersion= utilEndianExtractBeUint16( p ); p += 2;
      ttks->ttksLength= utilEndianExtractBeUint16( p ); p += 2;
      ttks->ttksCoverage= utilEndianExtractBeUint16( p ); p += 2;
      ttks->ttksPairCount= utilEndianExtractBeUint16( p ); p += 2;
      ttks->ttksSearchRange= utilEndianExtractBeUint16( p ); p += 2;
      ttks->ttksEntrySelector= utilEndianExtractBeUint16( p ); p += 2;
      ttks->ttksRangeShift= utilEndianExtractBeUint16( p ); p += 2;

      ttks->ttksPairs= malloc( ttks->ttksPairCount*
                                    sizeof(TrueTypeKernPair) );
      if  ( ! ttks->ttksPairs )
          {
          LXDEB(ttks->ttksPairCount,ttks->ttksPairs);
          ttks->ttksPairCount= 0;
          rval= -1; goto ready;
          }

      format= ttks->ttksCoverage & 0x00ff;
      switch( format )
          {
          case 0:
            if  ( ttfExtractFormat0KernPairs( ttks, data ) )
                { LDEB(1); ttks->ttksPairCount= 0; rval= -1; goto ready; }
            break;

          default:
            XDEB(ttks->ttksCoverage);
            ttks->ttksPairCount= 0;
            break;
          }

      data += ttks->ttksLength;
      }

  ready:

    if  ( sisKern )
      { sioInClose( sisKern );      }

    return rval;
    }


/************************************************************************/
/*                                                    */
/*  Try to find names for a format4 unicode cmap.                 */
/*                                                    */
/************************************************************************/

static int utilTtfSetUnicodeCmapFormat4Names(
                        const TrueTypeFont *          ttf,
                        const TrueTypeCmapRecord *    ttcr,
                        AfmCharMetric *               acm )
    {
    const unsigned char *     p= ttcr->ttcr4Data;

    int                       n= ttcr->ttcr4SegCountX2;
    const unsigned char *     e= p+ 0;
    const unsigned char *     s= p+ 1* n+ 2;
    const unsigned char *     d= p+ 2* n+ 2;
    const unsigned char *     r= p+ 3* n+ 2;

    int                       seg;
    int                       segCount= n/ 2- 1;

    if  ( ! p )
      { XDEB(p); return -1; }

    for ( seg= 0; seg < segCount; seg++ )
      {
      int   ss;
      int   ee;
      int   dd;
      int   rr;

      int   v;

      ss= utilEndianExtractBeUint16( s ); s += 2;
      ee= utilEndianExtractBeUint16( e ); e += 2;
      dd= utilEndianExtractBeInt16( d ); d += 2;
      rr= utilEndianExtractBeUint16( r ); r += 2;

      for ( v= ss; v <= ee; v++ )
          {
          int                 g;
          const char *  name;
          char *        saved;

          if  ( rr > 0 )
            {
            int o= rr/ 2+ ( v- ss );
            g= utilEndianExtractBeUint16( r+ 2* o- 2 );
            }
          else{
            g= ( v+ dd ) % 65536;
            }

          if  ( g < 0 || g >= ttf->ttfGlyphCount )
            { LLDEB(g,ttf->ttfGlyphCount); return -1; }

          if  ( acm[g].acmN )
            { /*SDEB(acm[g].acmN);*/ continue;  }

          name= psUnicodeToGlyphName( v );
          if  ( ! name )
            { XDEB(name); return -1;      }
          saved= strdup( name );
          if  ( ! saved )
            { XDEB(saved); return -1;     }
          acm[g].acmN= saved;
          }
      }

    return 0;
    }

/************************************************************************/
/*                                                    */
/*  Try to set glyph names from the names found in the post table.      */
/*                                                    */
/************************************************************************/

static int utilTtfSetPostGlyphNames(
                        const TrueTypeFont *          ttf,
                        AfmCharMetric *               acm )
    {
    const TrueTypePostTable * ttpt= &(ttf->ttfPostTable);

    if  ( ttpt->ttptFormatUpper == 2 && ttpt->ttptFormatLower == 0 )
      {
      int               glyphno;
      TrueTypeGlyph *         ttg;

      ttg= ttf->ttfGlyphs;
      for ( glyphno= 0; glyphno < ttf->ttfGlyphCount;
                                    acm++, ttg++, glyphno++ )
          {
          int           idx;

          if  ( acm->acmN )
            { /* SDEB(acm->acmN); */ continue; }

          if  ( glyphno >= ttpt->ttptIndexCount )
            { LLDEB(glyphno,ttpt->ttptIndexCount); break; }

          idx= ttpt->ttptIndices[glyphno];
          if  ( idx < 258 )
            {
            acm->acmN= strdup( psAppleTtfGlyphNames[idx] );
            if  ( ! acm->acmN )
                { XDEB(acm->acmN); return -1; }
            continue;
            }

          idx -= 258;
          if  ( idx >= ttpt->ttptStringCount )
            { LLDEB(idx,ttpt->ttptStringCount); return -1; }

          acm->acmN= strdup( ttpt->ttptStrings[idx] );
          if  ( ! acm->acmN )
            { XDEB(acm->acmN); return -1; }
          }

      return 0;
      }

    LLDEB(ttpt->ttptFormatUpper,ttpt->ttptFormatLower);
    return 0;
    }

/************************************************************************/
/*                                                    */
/*  Try to find names for the glyphs in the font.                 */
/*                                                    */
/*  1)  Look for unicode encoding.                          */
/*  2)  Requirement per Appendix B of the ttf specification. (1)  */
/*  3)  Requirement per Appendix B of the ttf specification. (2)  */
/*                                                    */
/************************************************************************/

static int utilTtfSetCharNames(     const TrueTypeFont *    ttf,
                        AfmCharMetric *         acm )
    {
    const TrueTypeCmapTable * ttct= &(ttf->ttfCmapTable);
    const TrueTypeCmapRecord *      ttcr;

    int                       i;

    /*  2  */
    acm[0].acmN= strdup( ".notdef" );
    if  ( ! acm[0].acmN )
      { XDEB(acm[0].acmN); return -1;     }
    /*  3  */
    acm[1].acmN= strdup( ".null" );
    if  ( ! acm[1].acmN )
      { XDEB(acm[1].acmN); return -1;     }

    /*  1  */
    ttcr= ttct->ttctEncodingRecords;
    for ( i= 0; i < ttct->ttctEncodingRecordCount; ttcr++, i++ )
      {
      if  ( ttcr->ttcrPlatformID == 0           &&
            ttcr->ttcrFormat == 4         )
          { break;      }
      if  ( ttcr->ttcrPlatformID == 3           &&
            ttcr->ttcrEncodingID == 1           &&
            ttcr->ttcrFormat == 4         )
          { break;      }
      }

    if  ( i < ttct->ttctEncodingRecordCount )
      {
      if  ( utilTtfSetUnicodeCmapFormat4Names( ttf, ttcr, acm ) )
          { LDEB(1); return -1;     }

      return 0;
      }

    LDEB(ttct->ttctEncodingRecordCount); return -1;
    }

/************************************************************************/
/*                                                    */
/*  Write an afm metric file.                               */
/*                                                    */
/************************************************************************/

static int utilTtfGetName(    const TrueTypeNameTable *     ttnt,
                        int                     nameID )
    {
    int                       found= -1;
    int                       rec;
    const TrueTypeNameRecord *      ttnr;
    const TrueTypeNameRecord *      ttnrFound= (const TrueTypeNameRecord *)0;

    ttnr= ttnt->ttntRecords;
    for ( rec= 0; rec < ttnt->ttntRecordCount; ttnr++, rec++ )
      {
      if  ( ttnr->ttnrNameID != nameID )
          { continue; }

      if  ( found < 0 )
          { found= rec; ttnrFound= ttnr; break; }

      /*
      LDEB(ttnr->ttnrPlatformID);
      LDEB(ttnr->ttnrEncodingID);
      LDEB(ttnr->ttnrLanguageID);
      SDEB((char *)ttnr->ttnrSavedBytes);
      */
      }

    return found;
    }

static int utilTtfScaledInteger(    const TrueTypeFont *    ttf,
                              int               val )
    {
    const TrueTypeHeadTable * ttht= &(ttf->ttfHeadTable);
    double              fac= 1000.0/ ttht->tthtUnitsPerEm;

    if  ( val > 0 )
      { return fac* val+ 0.5; }
    else{ return fac* val- 0.5;     }
    }

static void utilTtfSetCharMetrics(  const TrueTypeFont *    ttf,
                              AfmCharMetric *         acm )
    {
    const TrueTypeGlyph *     ttg;
    const HorizontalMetric *  hm;

    int                       glyphno;

    ttg= ttf->ttfGlyphs;
    hm= ttf->ttfHorizontalMetrics;
    for ( glyphno= 0; glyphno < ttf->ttfGlyphCount;
                                  acm++, ttg++, hm++, glyphno++ )
      {
      if  ( glyphno >= ttf->ttfHorizontalMetricCount )
          { LLDEB(glyphno,ttf->ttfHorizontalMetricCount); return; }

      acm->acmWX= utilTtfScaledInteger( ttf, hm->hmAdvanceWidth );

      acm->acmBBox.abbLeft= utilTtfScaledInteger( ttf, ttg->ttgXMin );
      acm->acmBBox.abbBottom= utilTtfScaledInteger( ttf, ttg->ttgYMin );
      acm->acmBBox.abbRight= utilTtfScaledInteger( ttf, ttg->ttgXMax );
      acm->acmBBox.abbTop= utilTtfScaledInteger( ttf, ttg->ttgYMax );
      }

    return;
    }

static int utilTtfSaveName(   char **                       pName,
                        const TrueTypeNameTable *     ttnt,
                        int                     which )
    {
    int                       recFound;
    char *              name;
    const TrueTypeNameRecord *      ttnr;

    recFound= utilTtfGetName( ttnt, which );
    if  ( recFound < 0 )
      { LLDEB(which,recFound); return -1; }

    ttnr= ttnt->ttntRecords+ recFound;

    name= malloc( ttnr->ttnrLength+ 1 );
    if  ( ! name )
      { LXDEB(ttnr->ttnrLength,name);     }

    memcpy( name, ttnr->ttnrSavedBytes, ttnr->ttnrLength );
    name[ttnr->ttnrLength]= '\0';

    if  ( *pName )
      { free( *pName ); }

    *pName= name;
    return 0;
    }

static int utilTtfFontInfo(   AfmFontInfo *           afi,
                        const TrueTypeFont *    ttf )
    {
    const TrueTypeNameTable * ttnt= &(ttf->ttfNameTable);
    const TrueTypePostTable * ttpt= &(ttf->ttfPostTable);
    const TrueTypeHheaTable * hhea= &(ttf->ttfHheaTable);
    const TrueTypeHeadTable * ttht= &(ttf->ttfHeadTable);

    int                       glyphno;
    int                       recFound;

    AfmCharMetric *           acm;
    int                       enc;
    int                       code;

    char *              str;
    int                       start;
    int                       length;
    int                       weight;
    int                       width;

    afi->afiMetrics= malloc( ttf->ttfGlyphCount* sizeof(AfmCharMetric) );
    if  ( ! afi->afiMetrics )
      { LXDEB(ttf->ttfGlyphCount,afi->afiMetrics); return -1; }
    acm= afi->afiMetrics;
    for ( glyphno= 0; glyphno < ttf->ttfGlyphCount; acm++, glyphno++ )
      { psInitAfmCharMetric( acm ); }
    afi->afiMetricCount= ttf->ttfGlyphCount;

    utilTtfSetCharMetrics( ttf, afi->afiMetrics );
    utilTtfSetCharNames( ttf, afi->afiMetrics );
    utilTtfSetPostGlyphNames( ttf, afi->afiMetrics );

    if  ( psGetFontEncodings( afi ) )
      { LDEB(1); return -1;   }

    for ( enc= 0; enc < ENCODINGps_COUNT; enc++ )
      {
      if  ( afi->afiSupportedCharsets[enc].scSupported )
          { break;      }
      }
    if  ( enc >= ENCODINGps_COUNT )
      {
      acm= afi->afiMetrics;
      for ( code= 0; code < 256; acm++, code++ )
          {
          if  ( code >= afi->afiMetricCount )
            { break;    }

          afi->afiMetrics[code].acmC= code;
          }
      }
    else{
      for ( code= 0; code < 256; code++ )
          {
          glyphno= afi->afiSupportedCharsets[enc].scCodeToGlyphMapping[code];

          if  ( glyphno >= 0 )
            {
            acm= afi->afiMetrics+ glyphno;
            if  ( acm->acmC < 0 )
                { acm->acmC= code;  }
            }
          }
      }
    if  ( enc == ENCODINGpsISO_8859_1 )
      { afi->afiEncodingScheme= strdup( "ISOLatin1Encoding" );    }
    else{ afi->afiEncodingScheme= strdup( "FontSpecific" ); }

    afi->afiXHeight= 0;
    afi->afiCapHeight= 0;
    acm= afi->afiMetrics;
    for ( glyphno= 0; glyphno < afi->afiMetricCount; acm++, glyphno++ )
      {
      if  ( ! acm->acmN )
          { continue;   }
      if  ( ! strcmp( acm->acmN, "x" ) )
          { afi->afiXHeight= acm->acmBBox.abbTop;     }
      if  ( ! strcmp( acm->acmN, "H" ) )
          { afi->afiCapHeight= acm->acmBBox.abbTop;   }
      }

    if  ( utilTtfSaveName( &(afi->afiFontName), ttnt, 6 ) )
      { LDEB(6); return -1;   }

    if  ( utilTtfSaveName( &(afi->afiFullName), ttnt, 4 ) )
      { LDEB(4); return -1;   }

    if  ( utilTtfSaveName( &(afi->afiNotice), ttnt, 0 ) )
      { LDEB(0); return -1;   }

    if  ( utilTtfSaveName( &(afi->afiFamilyName), ttnt, 1 ) )
      { LDEB(1); return -1;   }

    if  ( utilTtfSaveName( &(afi->afiVersion), ttnt, 5 ) )
      { LDEB(5); return -1;   }

    recFound= utilTtfGetName( ttnt, 2 );
    if  ( recFound < 0 )
      { LLDEB(2,recFound); return -1; }
    str= (char *)ttnt->ttntRecords[recFound].ttnrSavedBytes;
    if  ( utilFontWeightFromString( &weight, &start, &length, str ) )
      {
      afi->afiWeight= malloc( length+ 1 );
      if  ( ! afi->afiWeight )
          { XDEB(afi->afiWeight); return -1;    }
      strncpy( afi->afiWeight, str+ start, length )[length]= '\0';
      }
    if  ( utilFontWidthFromString( &width, &start, &length, str ) )
      {
      afi->afiWidth= malloc( length+ 1 );
      if  ( ! afi->afiWidth )
          { XDEB(afi->afiWidth); return -1;     }
      strncpy( afi->afiWidth, str+ start, length )[length]= '\0';
      }

    if  ( ! afi->afiWeight )
      {
      str= afi->afiFullName;
      if  ( utilFontWeightFromString( &weight, &start, &length, str ) )
          {
          afi->afiWeight= malloc( length+ 1 );
          if  ( ! afi->afiWeight )
            { XDEB(afi->afiWeight); return -1;  }
          strncpy( afi->afiWeight, str+ start, length )[length]= '\0';
          }
      }

    if  ( ! afi->afiWeight )
      {
      str= afi->afiFullName;
      if  ( utilFontWidthFromString( &width, &start, &length, str ) )
          {
          afi->afiWidth= malloc( length+ 1 );
          if  ( ! afi->afiWidth )
            { XDEB(afi->afiWidth); return -1;   }
          strncpy( afi->afiWidth, str+ start, length )[length]= '\0';
          }
      }

    if  ( ttpt->ttptItalicAngleUpper >= 0 )
      {
      afi->afiItalicAngle= 
            ttpt->ttptItalicAngleUpper+
            ttpt->ttptItalicAngleLower/ 65536.0;
      }
    else{
      afi->afiItalicAngle= 
            ttpt->ttptItalicAngleUpper-
            ttpt->ttptItalicAngleLower/ 65536.0;
      }

    if  ( afi->afiItalicAngle > -0.05 && afi->afiItalicAngle < 0.05 )
      { afi->afiItalicAngle= 0.0;   }
    afi->afiTanItalicAngle= tan( afi->afiItalicAngle );

    afi->afiIsFixedPitch= ttpt->ttptIsFixedPitch != 0;

    afi->afiFontBBox.abbLeft= utilTtfScaledInteger( ttf, ttht->tthtXMin );
    afi->afiFontBBox.abbBottom= utilTtfScaledInteger( ttf, ttht->tthtYMin );
    afi->afiFontBBox.abbRight= utilTtfScaledInteger( ttf, ttht->tthtXMax );
    afi->afiFontBBox.abbTop= utilTtfScaledInteger( ttf, ttht->tthtYMax );

    afi->afiUnderlinePosition=
                utilTtfScaledInteger( ttf, ttpt->ttptUnderlinePosition );
    afi->afiUnderlineThickness=
                utilTtfScaledInteger( ttf, ttpt->ttptUnderlineThickness );
    afi->afiAscender=
                utilTtfScaledInteger( ttf, hhea->hheaAscender );
    afi->afiDescender=
                utilTtfScaledInteger( ttf, hhea->hheaDescender );

    if  ( ttf->ttfOS_2Table.ttotVendID[0] )
      {
      afi->afiVendor= strdup( ttf->ttfOS_2Table.ttotVendID );
      if  ( ! afi->afiVendor )
          { XDEB(afi->afiVendor); return -1;    }
      }

    return 0;
    }

static void utilTtfWriteCharStrings(      SimpleOutputStream *    sos,
                              int               nchars,
                              const AfmFontInfo *     afi )
    {
    int                       i;
    const AfmCharMetric *     acm= afi->afiMetrics;

    sioOutPrintf( sos, "/CharStrings %d dict dup begin\n", nchars );

    acm= afi->afiMetrics;
    for ( i= 0; i < afi->afiMetricCount; acm++, i++ )
      {
      if  ( ! acm->acmN )
          { /*LXDEB(i,acm->acmN);*/ continue;   }

      sioOutPrintf( sos, "  /%s %d def\n", acm->acmN, i );
      }

    sioOutPrintf( sos, "end readonly def\n" );

    return;
    }

/************************************************************************/
/*                                                    */
/*  Write a selection of the true type file to the sfnts dictionary     */
/*                                                    */
/*  1)  List of tables that might be used by the PostScript engine.     */
/*    See paragraph 4.7 on p 12 of the T42 spec. [Techmote #5012].      */
/*  2)  Determine new file offsets for the tables.                */
/*                                                    */
/************************************************************************/

static long utilTtfWriteTableByteArray(   SimpleOutputStream *    sos,
                              long              filePos,
                              const char *            tag,
                              const unsigned char *   bytes,
                              unsigned long           count,
                              int               pad )
    {
    SimpleOutputStream *      sosHex= (SimpleOutputStream *)0;

    const int                 wide= 72;
    const int                 lastNL= 0;

    sioOutPrintf( sos, "%% %s %ld bytes @%lu\n", tag, count, filePos );

    sioOutPrintf( sos, "<\n" );
    sosHex= sioOutHexOpenFolded( sos, wide, lastNL );
    if  ( ! sosHex )
      { XDEB(sosHex); filePos= -1; goto ready;  }

    if  ( sioOutWriteBytes( sosHex, bytes, count ) != count )
      { LDEB(count); filePos= -1; goto ready;   }

    if  ( pad > 1 )
      {
      while( count % pad )
          { sioOutPutCharacter( '\0', sosHex ); count++; }
      }

    filePos += count;

    sioOutPutCharacter( '\0', sosHex );
    sioOutClose( sosHex ); sosHex= (SimpleOutputStream *)0;
    sioOutPrintf( sos, ">\n" );

  ready:

    if  ( sosHex )
      { sioOutClose( sosHex );      }

    return filePos;
    }

static int utilTtfWriteT42Sfnts(    SimpleOutputStream *    sos,
                              const TrueTypeFont *    ttf )
    {
    int                       rval= 0;
    int                       tab;
    TrueTypeTableEntry *      ttte= ttf->ttfTables;
    unsigned long       offset;
    unsigned long       filePos;
    int                       tableCount;
    SimpleOutputStream *      sosHex= (SimpleOutputStream *)0;

    const int                 wide= 72;
    const int                 lastNL= 0;

    /*  1  */
    static const char * const sfntfTags[]=
      {
      "head", "hhea", "hmtx", "loca",
      "prep", "fpgm", "vhea", "glyf",
      "cvt ", "maxp", "vmtx",
      };

    offset= 12;
    tableCount= 0;

    /*  2  */
    ttte= ttf->ttfTables;
    for ( tab= 0; tab < ttf->ttfTableCount; ttte++, tab++ )
      {
      int   i;

      for ( i= 0; i < sizeof(sfntfTags)/sizeof(char *); i++ )
          {
          if  ( ! strcmp( ttte->ttteTag, sfntfTags[i] ) )
            { break;    }
          }

      if  ( i >= sizeof(sfntfTags)/sizeof(char *) )
          { ttte->ttteSaveOffset= 0;      }
      else{
          ttte->ttteSaveOffset= offset;
          tableCount++;
          offset += ttte->ttteLength;
          while( offset % 4 )
            { offset++; }
          }
      }

    ttte= ttf->ttfTables;
    for ( tab= 0; tab < ttf->ttfTableCount; ttte++, tab++ )
      {
      if  ( ttte->ttteSaveOffset > 0 )
          { ttte->ttteSaveOffset += 16* tableCount;
          }
      }

    filePos= 0;

    sioOutPrintf( sos, "/sfnts[\n" );

    sioOutPrintf( sos, "<\n" );
    sosHex= sioOutHexOpenFolded( sos, wide, lastNL );
    if  ( ! sosHex )
      { XDEB(sosHex); rval= -1; goto ready;     }

    sioEndianPutBeUint32( ttf->ttfVersion, sosHex ); filePos += 4;
    sioEndianPutBeUint16( tableCount, sosHex ); filePos += 2;
    sioEndianPutBeUint16( ttf->ttfSearchRange, sosHex ); filePos += 2;
    sioEndianPutBeUint16( ttf->ttfEntrySelector, sosHex ); filePos += 2;
    sioEndianPutBeUint16( ttf->ttfRangeShift, sosHex ); filePos += 2;

    ttte= ttf->ttfTables;
    for ( tab= 0; tab < ttf->ttfTableCount; ttte++, tab++ )
      {
      int         b;

      if  ( ttte->ttteSaveOffset == 0 )
          { continue;   }

      for ( b= 0; b < 4; b++ )
          { sioOutPutCharacter( ttte->ttteTag[b], sosHex ); }
      filePos += 4;

      sioEndianPutBeUint32( ttte->ttteChecksum, sosHex ); filePos += 4;
      sioEndianPutBeUint32( ttte->ttteSaveOffset, sosHex ); filePos += 4;
      sioEndianPutBeUint32( ttte->ttteLength, sosHex ); filePos += 4;
      }

    sioOutPutCharacter( '\0', sosHex );
    sioOutClose( sosHex ); sosHex= (SimpleOutputStream *)0;
    sioOutPrintf( sos, ">\n" );

    ttte= ttf->ttfTables;
    for ( tab= 0; tab < ttf->ttfTableCount; ttte++, tab++ )
      {
      if  ( ttte->ttteSaveOffset == 0 )
          { continue;   }

      if  ( filePos != ttte->ttteSaveOffset )
          { LLDEB(filePos,ttte->ttteSaveOffset); rval= -1; goto ready; }

      if  ( ttte->ttteLength > 65528 )
          {
          long    pos= 0;
          int           locPos= 0;
          long    upto= 65534;

          if  ( strcmp( ttte->ttteTag, "glyf" ) )
            {
            SLDEB(ttte->ttteTag,ttte->ttteLength);
            rval= -1; goto ready;
            }

          while( pos < ttte->ttteLength )
            {
            int         l, r, m;
            int         pad= 2;

            l= locPos; r= ttf->ttfLocationCount; m= ( l+ r )/ 2;

            while ( l < m )
                {
                if  ( ttf->ttfLocations[m] > upto )
                  { r= m;     }
                else{ l= m; }

                m= ( l+ r )/ 2;
                }

            upto= ttf->ttfLocations[m];

            if  ( upto == ttte->ttteLength )
                { pad= 4;     }

            filePos= utilTtfWriteTableByteArray( sos, filePos,
                  ttte->ttteTag, ttte->ttteBytes+ pos, upto- pos, pad );

            if  ( filePos < 0 )
                {
                SLLDEB(ttte->ttteTag,ttte->ttteLength,filePos);
                rval= -1; goto ready;
                }

            pos= upto;
            upto += 65528;
            locPos= m;
            }
          }
      else{
          filePos= utilTtfWriteTableByteArray( sos, filePos, ttte->ttteTag,
                            ttte->ttteBytes, ttte->ttteLength, 4 );
          if  ( filePos < 0 )
            {
            SLLDEB(ttte->ttteTag,ttte->ttteLength,filePos);
            rval= -1; goto ready;
            }
          }
      }

    sioOutPrintf( sos, "]def\n" );

  ready:

    if  ( sosHex )
      { sioOutClose( sosHex );      }

    return rval;
    }

static int utilTtfWriteT42(   SimpleOutputStream *    sos,
                        const AfmFontInfo *     afi,
                        const TrueTypeFont *    ttf )
    {
    int                       i;
    const TrueTypeHeadTable * ttht= &(ttf->ttfHeadTable);
    const AfmCharMetric *     acm;
    int                       map[256];
    int                       nchars;

    for ( i= 0; i < 256; i++ )
      { map[i]= -1;     }

    nchars= 0;
    acm= afi->afiMetrics;
    for ( i= 0; i < afi->afiMetricCount; acm++, i++ )
      {
      if  ( ! acm->acmN )
          { /*LXDEB(i,acm->acmN);*/ continue;   }

      nchars++;

      if  ( acm->acmC < 0 || acm->acmC >= 256 )
          { /*LDEB(acm->acmC);*/ continue;      }

      map[acm->acmC]= i;
      }

    sioOutPrintf( sos, "%%!PS-TrueTypeFont-%lu-%lu\n",
                            ttht->tthtVersion,
                            ttht->tthtFontRevision );
    sioOutPrintf( sos, "11 dict begin\n" );
    sioOutPrintf( sos, "  /FontName /%s def\n", afi->afiFontName );
    sioOutPrintf( sos, "  /Encoding 256 array\n" );
    sioOutPrintf( sos, "   0 1 255 { 1 index exch /.notdef put } for\n" );

    for ( i= 0; i < 256; i++ )
      {
      if  ( map[i] < 0 )
          { continue;   }

      acm= afi->afiMetrics+ map[i];
      sioOutPrintf( sos, "   dup %d /%s put\n", acm->acmC, acm->acmN );
      }

    sioOutPrintf( sos, "  readonly def\n" );
    sioOutPrintf( sos, "  /PaintType 0 def\n" );
    sioOutPrintf( sos, "  /FontMatrix [1 0 0 1 0 0] def\n" );
    sioOutPrintf( sos, "  /FontBBox [%d %d %d %d] def\n",
                              afi->afiFontBBox.abbLeft,
                              afi->afiFontBBox.abbBottom,
                              afi->afiFontBBox.abbRight,
                              afi->afiFontBBox.abbTop );
    sioOutPrintf( sos, "  /FontType 42 def\n" );

    psWriteFontInfoDict( sos, afi );

    utilTtfWriteT42Sfnts( sos, ttf );

    utilTtfWriteCharStrings( sos, nchars, afi );

    sioOutPrintf( sos, "FontName currentdict end definefont pop\n" );

    return 0;
    }

static int utilTtfWriteT42File(     SimpleOutputStream *    sosPf42,
                        const TrueTypeFont *    ttf )
    {
    int                       rval= 0;

    AfmFontInfo               afi;

    psInitAfmFontInfo( &afi );

    if  ( utilTtfFontInfo( &afi, ttf ) )
      { LDEB(1); rval= -1; goto ready;    }

    utilTtfWriteT42( sosPf42, &afi, ttf );

  ready:

    psCleanAfmFontInfo( &afi );

    return rval;
    }

static int utilTtfWriteT1(    SimpleOutputStream *    sos,
                        const AfmFontInfo *     afi,
                        const TrueTypeFont *    ttf )
    {
    int                       i;
    const AfmCharMetric *     acm;
    int                       map[256];
    int                       nchars;

    for ( i= 0; i < 256; i++ )
      { map[i]= -1;     }

    nchars= 0;
    acm= afi->afiMetrics;
    for ( i= 0; i < afi->afiMetricCount; acm++, i++ )
      {
      if  ( ! acm->acmN )
          { /*LXDEB(i,acm->acmN);*/ continue;   }

      nchars++;

      if  ( acm->acmC < 0 || acm->acmC >= 256 )
          { /*LDEB(acm->acmC);*/ continue;      }

      map[acm->acmC]= i;
      }

    sioOutPrintf( sos, "%%!PS-AdobeFont-1.0: %s %s\n",
                            afi->afiFontName,
                            afi->afiNotice );
    sioOutPrintf( sos, "12 dict begin\n" );
    sioOutPrintf( sos, "  /FontName /%s def\n", afi->afiFontName );
    sioOutPrintf( sos, "  /Encoding 256 array\n" );
    sioOutPrintf( sos, "   0 1 255 { 1 index exch /.notdef put } for\n" );

    for ( i= 0; i < 256; i++ )
      {
      if  ( map[i] < 0 )
          { continue;   }

      acm= afi->afiMetrics+ map[i];
      sioOutPrintf( sos, "   dup %d /%s put\n", acm->acmC, acm->acmN );
      }

    sioOutPrintf( sos, "  readonly def\n" );
    sioOutPrintf( sos, "  /PaintType 0 def\n" );
    sioOutPrintf( sos, "  /StrokeWidth 0 def\n" );
    sioOutPrintf( sos, "  /FontMatrix [0.001 0 0 0.001 0 0] def\n" );
    sioOutPrintf( sos, "  /FontBBox [%d %d %d %d] def\n",
                              afi->afiFontBBox.abbLeft,
                              afi->afiFontBBox.abbBottom,
                              afi->afiFontBBox.abbRight,
                              afi->afiFontBBox.abbTop );
    sioOutPrintf( sos, "  /FontType 1 def\n" );

    psWriteFontInfoDict( sos, afi );

    sioOutPrintf( sos, "currentdict end\n" );
    sioOutPrintf( sos, "currentfile eexec\n" );
    sioOutPrintf( sos, "dup /Private 16 dict dup begin\n" );
    sioOutPrintf( sos, "  /RD{string currentfile exch readstring pop}executeonly def\n" );
    sioOutPrintf( sos, "  /ND{noaccess def}executeonly def\n" );
    sioOutPrintf( sos, "  /NP{noaccess put}executeonly def\n" );

    return 0;
    }


static int utilTtfWriteT1File(      SimpleOutputStream *    sosPf1,
                        const TrueTypeFont *    ttf )
    {
    int                       rval= 0;

    AfmFontInfo               afi;

    psInitAfmFontInfo( &afi );

    if  ( utilTtfFontInfo( &afi, ttf ) )
      { LDEB(1); rval= -1; goto ready;    }

    utilTtfWriteT1( sosPf1, &afi, ttf );

  ready:

    psCleanAfmFontInfo( &afi );

    return rval;
    }

/************************************************************************/
/*                                                    */
/*  Read a true type font from file.                              */
/*                                                    */
/************************************************************************/

static int utilTtfLoadFile(   TrueTypeFont *          ttf,
                        SimpleInputStream *     sisTtf )
    {
    long                filePos= 0;

    int                       tab;
    int                       tableCount;
    TrueTypeTableEntry *      ttte;

    ttf->ttfVersion= sioEndianGetBeUint32( sisTtf ); filePos += 4;
    tableCount= sioEndianGetBeUint16( sisTtf ); filePos += 2;
    ttf->ttfSearchRange= sioEndianGetBeUint16( sisTtf ); filePos += 2;
    ttf->ttfEntrySelector= sioEndianGetBeUint16( sisTtf ); filePos += 2;
    ttf->ttfRangeShift= sioEndianGetBeUint16( sisTtf ); filePos += 2;

    ttf->ttfTables= (TrueTypeTableEntry *)malloc( tableCount*
                                  sizeof(TrueTypeTableEntry) );
    if  ( ! ttf->ttfTables )
      { LXDEB(tableCount,ttf->ttfTables); return -1;  }

    ttte= ttf->ttfTables;
    for ( tab= 0; tab < tableCount; ttte++, tab++ )
      { utilInitTrueTypeTableEntry( ttte );     }
    ttf->ttfTableCount= tableCount;

    ttte= ttf->ttfTables;
    for ( tab= 0; tab < tableCount; ttte++, tab++ )
      {
      int         b;

      for ( b= 0; b < 4; b++ )
          { ttte->ttteTag[b]= sioInGetCharacter( sisTtf );  }
      ttte->ttteTag[b]= '\0';
      filePos += 4;

      ttte->ttteChecksum= sioEndianGetBeUint32( sisTtf ); filePos += 4;
      ttte->ttteOffset= sioEndianGetBeUint32( sisTtf ); filePos += 4;
      ttte->ttteLength= sioEndianGetBeUint32( sisTtf ); filePos += 4;
      }

    qsort( ttf->ttfTables, ttf->ttfTableCount, sizeof(TrueTypeTableEntry),
                                  utilTrueTypeFontCompareTables );

    ttte= ttf->ttfTables;
    for ( tab= 0; tab < tableCount; ttte++, tab++ )
      {
      /*
      appDebug( "%3d: \"%.4s\" @%-7lu: %6lu bytes (%lu)\n",
                                  tab, ttte->ttteTag,
                                  ttte->ttteOffset, ttte->ttteLength,
                                  ttte->ttteChecksum );
      */

      if  ( filePos > ttte->ttteOffset )
          { LLDEB(filePos,ttte->ttteOffset); return -1;     }

      while( filePos < ttte->ttteOffset )
          {
          int     c= sioInGetCharacter( sisTtf );
          if  ( c == EOF )
            { LLLDEB(filePos,ttte->ttteOffset,c); return -1; }
          filePos++;
          }

      ttte->ttteBytes= malloc( ttte->ttteLength );
      if  ( ! ttte->ttteBytes )
          { LXDEB(ttte->ttteLength,ttte->ttteBytes); return -1; }
      if  ( sioInReadBytes( sisTtf, ttte->ttteBytes,
                            ttte->ttteLength ) != ttte->ttteLength )
          { LDEB(ttte->ttteLength); return -1;  }

      filePos += ttte->ttteLength;
      }

    if  ( utilTtfExtractHeadTable( ttf ) )
      { LDEB(1); return -1;   }
    if  ( utilTtfExtractNameTable( ttf ) )
      { LDEB(1); return -1;   }
    if  ( utilTtfExtractPostTable( ttf ) )
      { LDEB(1); return -1;   }
    if  ( utilTtfExtractHheaTable( ttf ) )
      { LDEB(1); return -1;   }
    if  ( utilTtfExtractLocaTable( ttf ) )
      { LDEB(1); return -1;   }
    if  ( utilTtfExtractHmtxTable( ttf ) )
      { LDEB(1); return -1;   }
    if  ( utilTtfExtractGlyfTable( ttf ) )
      { LDEB(1); return -1;   }
    if  ( utilTtfExtractCmapTable( ttf ) )
      { LDEB(1); return -1;   }

    if  ( utilTtfExtractKernTable( ttf ) )
      { LDEB(1); return -1;   }

    if  ( utilTtfExtractOS_2Table( ttf ) )
      { LDEB(1); return -1;   }

    return 0;
    }

/************************************************************************/
/*                                                    */
/*  Translate Truetype font to PostScript type 1.                 */
/*                                                    */
/*  Experimental code for future development and experimentation. */
/*                                                    */
/************************************************************************/

int psTtfToPt1(         SimpleOutputStream *    sosPt1,
                  SimpleInputStream *     sisTtf )
    {
    int                       rval= 0;
    TrueTypeFont        ttf;

    utilInitTrueTypeFont( &ttf );

    if  ( utilTtfLoadFile( &ttf, sisTtf ) )
      { LDEB(1); rval= -1; goto ready;    }

    utilTtfTranslateGlyphs( &ttf );

    utilTtfWriteT1File( sosPt1, &ttf );

  ready:

    utilCleanTrueTypeFont( &ttf );

    return rval;
    }

/************************************************************************/
/*                                                    */
/*  Translate Truetype font to PostScript type 42.                */
/*                                                    */
/************************************************************************/

int psTtfToPf42(        SimpleOutputStream *    sosPf42,
                        SimpleInputStream *     sisTtf )
    {
    int                       rval= 0;
    TrueTypeFont        ttf;

    utilInitTrueTypeFont( &ttf );

    if  ( utilTtfLoadFile( &ttf, sisTtf ) )
      { LDEB(1); rval= -1; goto ready;    }

    utilTtfWriteT42File( sosPf42, &ttf );

  ready:

    utilCleanTrueTypeFont( &ttf );

    return rval;
    }

/************************************************************************/
/*                                                    */
/*  Translate Truetype font to PostScript type 42.                */
/*                                                    */
/************************************************************************/

int psTtfToAfm(         SimpleOutputStream *    sosAfm,
                  SimpleInputStream *     sisTtf )
    {
    int                       rval= 0;

    AfmFontInfo               afi;
    TrueTypeFont        ttf;

    utilInitTrueTypeFont( &ttf );
    psInitAfmFontInfo( &afi );

    if  ( utilTtfLoadFile( &ttf, sisTtf ) )
      { LDEB(1); rval= -1; goto ready;    }

    if  ( utilTtfFontInfo( &afi, &ttf ) )
      { LDEB(1); rval= -1; goto ready;    }

    psWriteAfmFile( sosAfm, &afi );

  ready:

    psCleanAfmFontInfo( &afi );
    utilCleanTrueTypeFont( &ttf );

    return rval;
    }


Generated by  Doxygen 1.6.0   Back to index