shithub: freetype+ttf2subf

ref: 3d99f79669fb9a8a489339985975bdb55d1a7a73
dir: /src/psnames/psdriver.c/

View raw version
#include <freetype/internal/psnames.h>
#include <freetype/internal/ftobjs.h>
#include <psdriver.h>
#include <stdlib.h>

#ifndef FT_CONFIG_OPTION_NO_POSTSCRIPT_NAMES

/* see the python script "freetype2/docs/glnames.py" which is used */
/* to generate the following tables...                             */
#include <pstables.h>

#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
 /* return the Unicode value corresponding to a given glyph. Note that */
 /* we do deal with glyph variants by detecting a non-initial dot      */
 /* in the name, as in "A.swash" or "e.final", etc..                   */
 /*                                                                    */
  static
  FT_ULong  PS_Unicode_Value( const char* glyph_name )
  {
    FT_Int  n;
    char    first = glyph_name[0];
    char    temp[64];

    /* if the name begins with "uni", then the glyph name may be a */
    /* hard-coded unicode character code..                         */
    if ( glyph_name[0] == 'u' &&
         glyph_name[1] == 'n' &&
         glyph_name[2] == 'i' )
    {
      /* determine wether the following characters are hexadecimal */
      FT_Int      count;
      FT_ULong    value = 0;
      const char* p     = glyph_name + 4;

      for ( count = 4;count > 0; count--, p++ )
      {
        char           c = *p;
        unsigned char  d;

        d = (unsigned char)c-'0';
        if (d >= 10)
        {
          d = (unsigned char)c - 'A';
          if ( d >= 6 )
            d = 16;
          else
            d += 10;
        }
        /* exit if one non-uppercase-hexadecimal character was found */
        if (d >= 16)
          break;

        value = (value << 4) + d;
        if (count == 0)
          return value;
      }
    }

    /* look for a non-initial dot in the glyph name in order to */
    /* sort-out variants like "A.swash", "e.final", etc..       */
    {
      const char*  p;
      int          len;

      p = glyph_name;
      while ( *p && *p != '.' ) p++;
      len = p-glyph_name;

      if ( *p && len < 64 )
      {
        strncpy( temp, glyph_name, len );
        temp[len]  = 0;
        glyph_name = temp;
      }
    }

    /* now, lookup the glyph in the Adobe Glyph List */
    for ( n = 0; n < NUM_ADOBE_GLYPHS; n++ )
    {
      const char*  name = t1_standard_glyphs[n];

      if ( first == name[0] && strcmp( glyph_name, name ) == 0 )
        return names_to_unicode[n];
    }
    /* not found, there is probably no Unicode value for this glyph name */
    return 0;
  }


 /* qsort callback to sort the unicode map */
  static
  int  compare_uni_maps( const void* a, const void* b )
  {
    PS_UniMap*  map1 = (PS_UniMap*)a;
    PS_UniMap*  map2 = (PS_UniMap*)b;

    return ( map1->unicode < map2->unicode ? -1 :
             map1->unicode > map2->unicode ?  1 : 0 );
  }


 /* Builds a table that maps Unicode values to glyph indices */
  static
  FT_Error  PS_Build_Unicode_Table( FT_Memory     memory,
                                    FT_UInt       num_glyphs,
                                    const char**  glyph_names,
                                    PS_Unicodes  *table )
  {
    FT_Error  error;

    /* we first allocate the table */
    table->num_maps = 0;
    table->maps     = 0;

    if ( !ALLOC_ARRAY( table->maps, num_glyphs, PS_UniMap ) )
    {
      FT_UInt     n;
      FT_UInt     count;
      PS_UniMap*  map;
      FT_ULong    uni_char;

      map = table->maps;
      for ( n = 0; n < num_glyphs; n++ )
      {
        const char*  gname = glyph_names[n];
        if (gname)
        {
          uni_char = PS_Unicode_Value(gname);
          if (uni_char && uni_char != 0xFFFF)
          {
            map->unicode     = uni_char;
            map->glyph_index = n;
            map++;
          }
        }
      }

      /* now, compress the table a bit */
      count = map - table->maps;
      if ( count > 0 && REALLOC( table->maps,
                                 num_glyphs*sizeof(PS_UniMap),
                                 count*sizeof(PS_UniMap) ) )
      {
        count = 0;
      }

      if (count == 0)
      {
        FREE( table->maps );
        if (!error)
          error = FT_Err_Invalid_Argument;  /* no unicode chars here !! */
      }
      else
        /* sort the table in increasing order of unicode values */
        qsort( table->maps, count, sizeof(PS_UniMap), compare_uni_maps );

      table->num_maps = count;
    }
    return error;
  }

  static
  FT_UInt  PS_Lookup_Unicode( PS_Unicodes*  table,
                              FT_ULong      unicode )
  {
    PS_UniMap  *min, *max, *mid;
    /* perform a binary search on the table */
    min = table->maps;
    max = min + table->num_maps - 1;

    while (min <= max)
    {
      mid = min + (max-min)/2;
      if ( mid->unicode == unicode )
        return mid->glyph_index;

      if (min == max)
        break;

      if ( mid->unicode < unicode ) min = mid+1;
                               else max = mid-1;
    }

    return 0xFFFF;
  }

#endif

  static
  const char*  PS_Macintosh_Name( FT_UInt  name_index )
  {
    if (name_index >= 258)
      name_index = 0;

    return standard_glyph_names[ mac_standard_names[name_index] ];
  }


  static
  const char*  PS_Standard_Strings( FT_UInt  sid )
  {
    return (sid < NUM_STD_GLYPHS ? t1_standard_glyphs[sid] : 0);
  }

  static const  PSNames_Interface  psnames_interface =
  {
#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
    (PS_Unicode_Value_Func)     PS_Unicode_Value,
    (PS_Build_Unicodes_Func)    PS_Build_Unicode_Table,
    (PS_Lookup_Unicode_Func)    PS_Lookup_Unicode,
#else
    0,
    0,
    0,
#endif

    (PS_Macintosh_Name_Func)    PS_Macintosh_Name,
    (PS_Adobe_Std_Strings_Func) PS_Standard_Strings,

    t1_standard_encoding,
    t1_expert_encoding
  };


  const FT_DriverInterface  psnames_driver_interface =
  {
    sizeof(FT_DriverRec),
    0,
    0,
    0,

    "psnames",  /* driver name                         */
    100,        /* driver version                      */
    200,        /* driver requires FreeType 2 or above */

    (void*)&psnames_interface,
    0, 0, 0, 0,
    0, 0, 0, 0,
    0, 0, 0, 0,
    0, 0,
  };

#else

  const FT_DriverInterface  psnames_driver_interface =
  {
    0,
    0,
    0,
    0,

    0,
    100,        /* driver version                      */
    200,        /* driver requires FreeType 2 or above */

    0,
  };

#endif  /* !FT_CONFIG_OPTION_NO_POSTSCRIPT_NAMES */