shithub: freetype+ttf2subf

ref: 1a26888da3d9168cbcb403dc28511bd222b5e12b
dir: /src/sfnt/ttpost.c/

View raw version
/***************************************************************************/
/*                                                                         */
/*  ttpost.c                                                               */
/*                                                                         */
/*    Postscript names table processing (body).                            */
/*                                                                         */
/*  Copyright 1996-1999 by                                                 */
/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
/*                                                                         */
/*  This file is part of the FreeType project, and may only be used        */
/*  modified and distributed under the terms of the FreeType project       */
/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
/*  this file you indicate that you have read the license and              */
/*  understand and accept it fully.                                        */
/*                                                                         */
/***************************************************************************/


  /*************************************************************************/
  /*                                                                       */
  /* The post table is not completely loaded by the core engine.  This     */
  /* file loads the missing PS glyph names and implements an API to access */
  /* them.                                                                 */
  /*                                                                       */
  /*************************************************************************/


#include <ttpost.h>
#include <ftstream.h>
#include <tterrors.h>
#include <ttload.h>
#include <tttags.h>

  /* the 258 default Mac PS glyph names */

  const TT_String*  TT_Mac_Postscript_Names[258] =
  {
    /*   0 */
    ".notdef",
    ".null",
    "CR",
    "space",
    "exclam",
    "quotedbl",
    "numbersign",
    "dollar",
    "percent",
    "ampersand",

    /*  10 */
    "quotesingle",
    "parenleft",
    "parenright",
    "asterisk",
    "plus",
    "comma",
    "hyphen",
    "period",
    "slash",
    "zero",

    /*  20 */
    "one",
    "two",
    "three",
    "four",
    "five",
    "six",
    "seven",
    "eight",
    "nine",
    "colon",

    /*  30 */
    "semicolon",
    "less",
    "equal",
    "greater", "question",
    "at",
    "A",
    "B",
    "C",
    "D",

    /*  40 */
    "E",
    "F",
    "G",
    "H",
    "I",
    "J",
    "K",
    "L",
    "M",
    "N",

    /*  50 */
    "O",
    "P",
    "Q",
    "R",
    "S",
    "T",
    "U",
    "V",
    "W",
    "X",

    /*  60 */
    "Y",
    "Z",
    "bracketleft",
    "backslash",
    "bracketright",
    "asciicircum",
    "underscore",
    "grave",
    "a",
    "b",

    /*  70 */
    "c",
    "d",
    "e",
    "f",
    "g",
    "h",
    "i",
    "j",
    "k",
    "l",

    /*  80 */
    "m",
    "n",
    "o",
    "p",
    "q",
    "r",
    "s",
    "t",
    "u",
    "v",

    /*  90 */
    "w",
    "x",
    "y",
    "z",
    "braceleft",
    "bar",
    "braceright",
    "asciitilde",
    "Adieresis",
    "Aring",

    /* 100 */
    "Ccedilla",
    "Eacute",
    "Ntilde",
    "Odieresis",
    "Udieresis",
    "aacute",
    "agrave",
    "acircumflex",
    "adieresis",
    "atilde",

    /* 110 */
    "aring",
    "ccedilla",
    "eacute",
    "egrave",
    "ecircumflex",
    "edieresis",
    "iacute",
    "igrave",
    "icircumflex",
    "idieresis",

    /* 120 */
    "ntilde",
    "oacute",
    "ograve",
    "ocircumflex",
    "odieresis",
    "otilde",
    "uacute",
    "ugrave",
    "ucircumflex",
    "udieresis",

    /* 130 */
    "dagger",
    "degree",
    "cent",
    "sterling",
    "section",
    "bullet",
    "paragraph",
    "germandbls",
    "registered",
    "copyright",

    /* 140 */
    "trademark",
    "acute",
    "dieresis",
    "notequal",
    "AE",
    "Oslash",
    "infinity",
    "plusminus",
    "lessequal",
    "greaterequal",

    /* 150 */
    "yen",
    "mu",
    "partialdiff",
    "summation",
    "product",
    "pi",
    "integral",
    "ordfeminine",
    "ordmasculine",
    "Omega",

    /* 160 */
    "ae",
    "oslash",
    "questiondown",
    "exclamdown",
    "logicalnot",
    "radical",
    "florin",
    "approxequal",
    "Delta",
    "guillemotleft",

    /* 170 */
    "guillemotright",
    "ellipsis",
    "nbspace",
    "Agrave",
    "Atilde",
    "Otilde",
    "OE",
    "oe",
    "endash",
    "emdash",

    /* 180 */
    "quotedblleft",
    "quotedblright",
    "quoteleft",
    "quoteright",
    "divide",
    "lozenge",
    "ydieresis",
    "Ydieresis",
    "fraction",
    "currency",

    /* 190 */
    "guilsinglleft",
    "guilsinglright",
    "fi",
    "fl",
    "daggerdbl",
    "periodcentered",
    "quotesinglbase",
    "quotedblbase",
    "perthousand",
    "Acircumflex",

    /* 200 */
    "Ecircumflex",
    "Aacute",
    "Edieresis",
    "Egrave",
    "Iacute",
    "Icircumflex",
    "Idieresis",
    "Igrave",
    "Oacute",
    "Ocircumflex",

    /* 210 */
    "apple",
    "Ograve",
    "Uacute",
    "Ucircumflex",
    "Ugrave",
    "dotlessi",
    "circumflex",
     "tilde",
     "macron",
     "breve",

    /* 220 */
    "dotaccent",
    "ring",
    "cedilla",
    "hungarumlaut",
    "ogonek",
    "caron",
    "Lslash",
    "lslash",
    "Scaron",
    "scaron",

    /* 230 */
    "Zcaron",
    "zcaron",
    "brokenbar",
    "Eth",
    "eth",
    "Yacute",
    "yacute",
    "Thorn",
    "thorn",
    "minus",

    /* 240 */
    "multiply",
    "onesuperior",
    "twosuperior",
    "threesuperior",
    "onehalf",
    "onequarter",
    "threequarters",
    "franc",
    "Gbreve",
    "gbreve",

    /* 250 */
    "Idot",
    "Scedilla",
    "scedilla",
    "Cacute",
    "cacute",
    "Ccaron",
    "ccaron",
    "dmacron",
  };


  static
  TT_Error  Load_Format_20( TT_Face    face,
                            FT_Stream  stream )
  {
    FT_Memory  memory = stream->memory;
    TT_Error   error;

    TT_Int     num_glyphs;
    TT_Int     num_names;

    TT_UShort* glyph_indices = 0;
    TT_Char**  name_strings  = 0;


    if ( READ_UShort( num_glyphs ) )
      goto Exit;

    /* UNDOCUMENTED!  The number of glyphs in this table can be smaller */
    /* than the value in the maxp table (cf. cyberbit.ttf).             */

    /* There already exist fonts which have more than 32768 glyph names */
    /* in this table, so the test for this threshold has been dropped.  */

    if ( num_glyphs > face->root.num_glyphs )
    {
      error = TT_Err_Invalid_File_Format;
      goto Exit;
    }

    /* load the indices */
    {
      TT_Int  n;

      if ( ALLOC_ARRAY ( glyph_indices, num_glyphs, TT_UShort ) ||
           ACCESS_Frame( num_glyphs * 2L )                      )
        goto Fail;

      for ( n = 0; n < num_glyphs; n++ )
        glyph_indices[n] = GET_UShort();

      FORGET_Frame();
    }

    /* compute number of names stored in table */
    {
      TT_Int  n;

      num_names = 0;

      for ( n = 0; n < num_glyphs; n++ )
      {
        TT_Int  index;

        index = glyph_indices[n];
        if ( index >= 258 )
        {
          index -= 257;
          if ( index > num_names )
            num_names = index;
        }
      }
    }

    /* now load the name strings */
    {
      TT_Int  n;

      if ( ALLOC_ARRAY( name_strings, num_names, TT_Char* ) )
        goto Fail;

      for ( n = 0; n < num_names; n++ )
      {
        TT_UInt  len;

        if ( READ_Byte  ( len )                             ||
             ALLOC_ARRAY( name_strings[n], len+1, TT_Char ) ||
             FILE_Read  ( name_strings[n], len )            )
          goto Fail1;

        name_strings[n][len] = '\0';
      }
    }

    /* all right, set table fields and exit successfuly */
    {
      TT_Post_20*  table = &face->postscript_names.names.format_20;

      table->num_glyphs    = num_glyphs;
      table->num_names     = num_names;
      table->glyph_indices = glyph_indices;
      table->glyph_names   = name_strings;
    }
    return TT_Err_Ok;


  Fail1:
    {
      TT_Int  n;

      for ( n = 0; n < num_names; n++ )
        FREE( name_strings[n] );
    }

  Fail:
    FREE( name_strings );
    FREE( glyph_indices );

  Exit:
    return error;
  }


  static
  TT_Error  Load_Format_25( TT_Face    face,
                            FT_Stream  stream )
  {
    FT_Memory  memory = stream->memory;
    TT_Error   error;

    TT_Int     num_glyphs;
    TT_Char*   offset_table = 0;


    /* UNDOCUMENTED!  This value appears only in the Apple TT specs. */
    if ( READ_UShort( num_glyphs ) )
      goto Exit;

    /* check the number of glyphs */
    if ( num_glyphs > face->root.num_glyphs || num_glyphs > 258 )
    {
      error = TT_Err_Invalid_File_Format;
      goto Exit;
    }

    if ( ALLOC    ( offset_table, num_glyphs ) ||
         FILE_Read( offset_table, num_glyphs ) )
      goto Fail;

    /* now check the offset table */
    {
      TT_Int  n;


      for ( n = 0; n < num_glyphs; n++ )
      {
        TT_Long  index = (TT_Long)n + offset_table[n];


        if ( index < 0 || index > num_glyphs )
        {
          error = TT_Err_Invalid_File_Format;
          goto Fail;
        }
      }
    }

    /* OK, set table fields and exit successfuly */
    {
      TT_Post_25*  table = &face->postscript_names.names.format_25;


      table->num_glyphs = num_glyphs;
      table->offsets    = offset_table;
    }

    return TT_Err_Ok;

  Fail:
    FREE( offset_table );

  Exit:
    return error;
  }


  static
  TT_Error  Load_Post_Names( TT_Face  face )
  {
    FT_Stream   stream;
    TT_Error    error;

    /* get a stream for the face's resource */
    stream = face->root.stream;

    /* seek to the beginning of the PS names table */
    error = face->goto_table( face, TTAG_post, stream, 0 );
    if (error) goto Exit;

    /* now read postscript table */
    switch ( face->postscript.FormatType )
    {
    case 0x00020000:
      error = Load_Format_20( face, stream );
      break;

    case 0x00028000:
      error = Load_Format_25( face, stream );
      break;

    default:
      error = TT_Err_Invalid_File_Format;
    }

    face->postscript_names.loaded = 1;

  Exit:
    return error;
  }


  LOCAL_FUNC
  void  TT_Free_Post_Names( TT_Face  face )
  {
    FT_Memory       memory = face->root.memory;
    TT_Post_Names*  names  = &face->postscript_names;


    if ( names->loaded )
    {
      switch ( face->postscript.FormatType )
      {
      case 0x00020000:
        {
          TT_Post_20*  table = &names->names.format_20;
          TT_UInt      n;


          FREE( table->glyph_indices );
          table->num_glyphs = 0;

          for ( n = 0; n < table->num_names; n++ )
            FREE( table->glyph_names[n] );

          FREE( table->glyph_names );
          table->num_names = 0;
        }
        break;

      case 0x00028000:
        {
          TT_Post_25*  table = &names->names.format_25;


          FREE( table->offsets );
          table->num_glyphs = 0;
        }
        break;
      }
    }
    names->loaded = 0;
  }


  /*************************************************************************/
  /*                                                                       */
  /* <Function>                                                            */
  /*    TT_Get_PS_Name                                                     */
  /*                                                                       */
  /* <Description>                                                         */
  /*    Gets the PostScript glyph name of a glyph.                         */
  /*                                                                       */
  /* <Input>                                                               */
  /*    index  :: The glyph index.                                         */
  /*                                                                       */
  /*    PSname :: The address of a string pointer.  Will be NULL in case   */
  /*              of error, otherwise it is a pointer to the glyph name.   */
  /*                                                                       */
  /*              You must not modify the returned string!                 */
  /*                                                                       */
  /* <Output>                                                              */
  /*    TrueType error code.  0 means success.                             */
  /*                                                                       */
  EXPORT_FUNC
  TT_Error  TT_Get_PS_Name( TT_Face      face,
                            TT_UInt      index,
                            TT_String**  PSname )
  {
    TT_Error        error;
    TT_Post_Names*  names;

    if ( !face )
      return TT_Err_Invalid_Face_Handle;

    if ( index >= (TT_UInt)face->root.num_glyphs )
      return TT_Err_Invalid_Glyph_Index;

    names   = &face->postscript_names;

    /* `.notdef' by default */
    *PSname = (TT_String*)TT_Mac_Postscript_Names[0];

    switch ( face->postscript.FormatType )
    {
    case 0x00010000:
      if ( index < 258 )                    /* paranoid checking */
        *PSname = (TT_String*)TT_Mac_Postscript_Names[index];
      break;

    case 0x00020000:
      {
        TT_Post_20*  table = &names->names.format_20;


        if ( !names->loaded )
        {
          error = Load_Post_Names( face );
          if ( error )
            break;
        }

        if ( index < table->num_glyphs )
        {
          TT_UShort  name_index = table->glyph_indices[index];


          if ( name_index < 258 )
            *PSname = (TT_String*)TT_Mac_Postscript_Names[name_index];
          else
            *PSname = (TT_String*)table->glyph_names[name_index - 258];
        }
      }
      break;

    case 0x00028000:
      {
        TT_Post_25*  table = &names->names.format_25;


        if ( !names->loaded )
        {
          error = Load_Post_Names( face );
          if ( error )
            break;
        }

        if ( index < table->num_glyphs )    /* paranoid checking */
        {
          index  += table->offsets[index];
          *PSname = (TT_String*)TT_Mac_Postscript_Names[index];
        }
      }
      break;

    case 0x00030000:
      break;                                /* nothing to do */
    }

    return TT_Err_Ok;
  }


/* END */