tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ttpost.c (13262B)


      1 /****************************************************************************
      2 *
      3 * ttpost.c
      4 *
      5 *   PostScript name table processing for TrueType and OpenType fonts
      6 *   (body).
      7 *
      8 * Copyright (C) 1996-2025 by
      9 * David Turner, Robert Wilhelm, and Werner Lemberg.
     10 *
     11 * This file is part of the FreeType project, and may only be used,
     12 * modified, and distributed under the terms of the FreeType project
     13 * license, LICENSE.TXT.  By continuing to use, modify, or distribute
     14 * this file you indicate that you have read the license and
     15 * understand and accept it fully.
     16 *
     17 */
     18 
     19  /**************************************************************************
     20   *
     21   * The post table is not completely loaded by the core engine.  This
     22   * file loads the missing PS glyph names and implements an API to access
     23   * them.
     24   *
     25   */
     26 
     27 
     28 #include <freetype/internal/ftdebug.h>
     29 #include <freetype/internal/ftstream.h>
     30 #include <freetype/tttags.h>
     31 
     32 
     33 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
     34 
     35 #include "ttpost.h"
     36 
     37 #include "sferrors.h"
     38 
     39 
     40  /**************************************************************************
     41   *
     42   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
     43   * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
     44   * messages during execution.
     45   */
     46 #undef  FT_COMPONENT
     47 #define FT_COMPONENT  ttpost
     48 
     49 
     50  /* If this configuration macro is defined, we rely on the `psnames' */
     51  /* module to grab the glyph names.                                  */
     52 
     53 #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
     54 
     55 
     56 #include <freetype/internal/services/svpscmap.h>
     57 
     58 #define MAC_NAME( x )  (FT_String*)psnames->macintosh_name( (FT_UInt)(x) )
     59 
     60 
     61 #else /* !FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
     62 
     63 
     64   /* Otherwise, we ignore the `psnames' module, and provide our own  */
     65   /* table of Mac names.  Thus, it is possible to build a version of */
     66   /* FreeType without the Type 1 driver & psnames module.            */
     67 
     68 #define MAC_NAME( x )  (FT_String*)tt_post_default_names[x]
     69 
     70  /* the 258 default Mac PS glyph names; see file `tools/glnames.py' */
     71 
     72  static const FT_String* const  tt_post_default_names[258] =
     73  {
     74    /*   0 */
     75    ".notdef", ".null", "nonmarkingreturn", "space", "exclam",
     76    "quotedbl", "numbersign", "dollar", "percent", "ampersand",
     77    /*  10 */
     78    "quotesingle", "parenleft", "parenright", "asterisk", "plus",
     79    "comma", "hyphen", "period", "slash", "zero",
     80    /*  20 */
     81    "one", "two", "three", "four", "five",
     82    "six", "seven", "eight", "nine", "colon",
     83    /*  30 */
     84    "semicolon", "less", "equal", "greater", "question",
     85    "at", "A", "B", "C", "D",
     86    /*  40 */
     87    "E", "F", "G", "H", "I",
     88    "J", "K", "L", "M", "N",
     89    /*  50 */
     90    "O", "P", "Q", "R", "S",
     91    "T", "U", "V", "W", "X",
     92    /*  60 */
     93    "Y", "Z", "bracketleft", "backslash", "bracketright",
     94    "asciicircum", "underscore", "grave", "a", "b",
     95    /*  70 */
     96    "c", "d", "e", "f", "g",
     97    "h", "i", "j", "k", "l",
     98    /*  80 */
     99    "m", "n", "o", "p", "q",
    100    "r", "s", "t", "u", "v",
    101    /*  90 */
    102    "w", "x", "y", "z", "braceleft",
    103    "bar", "braceright", "asciitilde", "Adieresis", "Aring",
    104    /* 100 */
    105    "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis",
    106    "aacute", "agrave", "acircumflex", "adieresis", "atilde",
    107    /* 110 */
    108    "aring", "ccedilla", "eacute", "egrave", "ecircumflex",
    109    "edieresis", "iacute", "igrave", "icircumflex", "idieresis",
    110    /* 120 */
    111    "ntilde", "oacute", "ograve", "ocircumflex", "odieresis",
    112    "otilde", "uacute", "ugrave", "ucircumflex", "udieresis",
    113    /* 130 */
    114    "dagger", "degree", "cent", "sterling", "section",
    115    "bullet", "paragraph", "germandbls", "registered", "copyright",
    116    /* 140 */
    117    "trademark", "acute", "dieresis", "notequal", "AE",
    118    "Oslash", "infinity", "plusminus", "lessequal", "greaterequal",
    119    /* 150 */
    120    "yen", "mu", "partialdiff", "summation", "product",
    121    "pi", "integral", "ordfeminine", "ordmasculine", "Omega",
    122    /* 160 */
    123    "ae", "oslash", "questiondown", "exclamdown", "logicalnot",
    124    "radical", "florin", "approxequal", "Delta", "guillemotleft",
    125    /* 170 */
    126    "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde",
    127    "Otilde", "OE", "oe", "endash", "emdash",
    128    /* 180 */
    129    "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide",
    130    "lozenge", "ydieresis", "Ydieresis", "fraction", "currency",
    131    /* 190 */
    132    "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl",
    133    "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
    134    /* 200 */
    135    "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
    136    "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
    137    /* 210 */
    138    "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave",
    139    "dotlessi", "circumflex", "tilde", "macron", "breve",
    140    /* 220 */
    141    "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek",
    142    "caron", "Lslash", "lslash", "Scaron", "scaron",
    143    /* 230 */
    144    "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
    145    "Yacute", "yacute", "Thorn", "thorn", "minus",
    146    /* 240 */
    147    "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf",
    148    "onequarter", "threequarters", "franc", "Gbreve", "gbreve",
    149    /* 250 */
    150    "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute",
    151    "Ccaron", "ccaron", "dcroat",
    152  };
    153 
    154 
    155 #endif /* !FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
    156 
    157 
    158  static FT_Error
    159  load_format_20( TT_Post_Names  names,
    160                  FT_Stream      stream,
    161                  FT_UShort      num_glyphs,
    162                  FT_ULong       post_len )
    163  {
    164    FT_Memory   memory = stream->memory;
    165    FT_Error    error;
    166 
    167    FT_UShort   n;
    168    FT_UShort   num_names = 0;
    169 
    170    FT_UShort*  glyph_indices = NULL;
    171    FT_Byte**   name_strings  = NULL;
    172    FT_Byte*    q;
    173 
    174 
    175    if ( (FT_ULong)num_glyphs * 2 > post_len )
    176    {
    177      error = FT_THROW( Invalid_File_Format );
    178      goto Exit;
    179    }
    180 
    181    /* load the indices and note their maximum */
    182    if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) ||
    183         FT_FRAME_ENTER( num_glyphs * 2 )           )
    184      goto Fail;
    185 
    186    q = (FT_Byte*)stream->cursor;
    187 
    188    for ( n = 0; n < num_glyphs; n++ )
    189    {
    190      FT_UShort  idx = FT_NEXT_USHORT( q );
    191 
    192 
    193      if ( idx > num_names )
    194        num_names = idx;
    195 
    196      glyph_indices[n] = idx;
    197    }
    198 
    199    FT_FRAME_EXIT();
    200 
    201    /* compute number of names stored in the table */
    202    num_names = num_names > 257 ? num_names - 257 : 0;
    203 
    204    /* now load the name strings */
    205    if ( num_names )
    206    {
    207      FT_Byte*   p;
    208      FT_Byte*   p_end;
    209 
    210 
    211      post_len -= (FT_ULong)num_glyphs * 2;
    212 
    213      if ( FT_QALLOC( name_strings, num_names * sizeof ( FT_Byte* ) +
    214                                    post_len + 1 ) )
    215        goto Fail;
    216 
    217      p = (FT_Byte*)( name_strings + num_names );
    218      if ( FT_STREAM_READ( p, post_len ) )
    219        goto Fail;
    220 
    221      p_end = p + post_len;
    222 
    223      /* convert from Pascal- to C-strings and set pointers */
    224      for ( n = 0; p < p_end && n < num_names; n++ )
    225      {
    226        FT_UInt  len = *p;
    227 
    228 
    229        /* names in the Adobe Glyph List are shorter than 40 characters */
    230        if ( len >= 40U )
    231          FT_TRACE4(( "load_format_20: unusual %u-char name found\n", len ));
    232 
    233        *p++            = 0;
    234        name_strings[n] = p;
    235        p              += len;
    236      }
    237      *p_end = 0;
    238 
    239      /* deal with missing or insufficient string data */
    240      if ( n < num_names )
    241      {
    242        FT_TRACE4(( "load_format_20: %hu PostScript names are truncated\n",
    243                    (FT_UShort)( num_names - n ) ));
    244 
    245        for ( ; n < num_names; n++ )
    246          name_strings[n] = p_end;
    247      }
    248    }
    249 
    250    /* all right, set table fields and exit successfully */
    251    names->num_glyphs    = num_glyphs;
    252    names->num_names     = num_names;
    253    names->glyph_indices = glyph_indices;
    254    names->glyph_names   = name_strings;
    255 
    256    return FT_Err_Ok;
    257 
    258  Fail:
    259    FT_FREE( name_strings );
    260    FT_FREE( glyph_indices );
    261 
    262  Exit:
    263    return error;
    264  }
    265 
    266 
    267  static FT_Error
    268  load_format_25( TT_Post_Names  names,
    269                  FT_Stream      stream,
    270                  FT_UShort      num_glyphs,
    271                  FT_ULong       post_len )
    272  {
    273    FT_Memory  memory = stream->memory;
    274    FT_Error   error;
    275 
    276    FT_UShort   n;
    277    FT_UShort*  glyph_indices = NULL;
    278    FT_Byte*    q;
    279 
    280 
    281    /* check the number of glyphs, including the theoretical limit */
    282    if ( num_glyphs > post_len  ||
    283         num_glyphs > 258 + 128 )
    284    {
    285      error = FT_THROW( Invalid_File_Format );
    286      goto Exit;
    287    }
    288 
    289    /* load the indices and check their Mac range */
    290    if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) ||
    291         FT_FRAME_ENTER( num_glyphs )               )
    292      goto Fail;
    293 
    294    q = (FT_Byte*)stream->cursor;
    295 
    296    for ( n = 0; n < num_glyphs; n++ )
    297    {
    298      FT_Int  idx = n + FT_NEXT_CHAR( q );
    299 
    300 
    301      if ( idx < 0 || idx > 257 )
    302        idx = 0;
    303 
    304      glyph_indices[n] = (FT_UShort)idx;
    305    }
    306 
    307    FT_FRAME_EXIT();
    308 
    309    /* OK, set table fields and exit successfully */
    310    names->num_glyphs    = num_glyphs;
    311    names->glyph_indices = glyph_indices;
    312 
    313    return FT_Err_Ok;
    314 
    315  Fail:
    316    FT_FREE( glyph_indices );
    317 
    318  Exit:
    319    return error;
    320  }
    321 
    322 
    323  static FT_Error
    324  load_post_names( TT_Face  face )
    325  {
    326    FT_Error   error = FT_Err_Ok;
    327    FT_Stream  stream = face->root.stream;
    328    FT_Fixed   format = face->postscript.FormatType;
    329    FT_ULong   post_len;
    330    FT_UShort  num_glyphs;
    331 
    332 
    333    /* seek to the beginning of the PS names table */
    334    error = face->goto_table( face, TTAG_post, stream, &post_len );
    335    if ( error )
    336      goto Exit;
    337 
    338    /* UNDOCUMENTED!  The number of glyphs in this table can be smaller */
    339    /* than the value in the maxp table (cf. cyberbit.ttf).             */
    340    if ( post_len < 34                            ||
    341         FT_STREAM_SKIP( 32 )                     ||
    342         FT_READ_USHORT( num_glyphs )             ||
    343         num_glyphs > face->max_profile.numGlyphs ||
    344         num_glyphs == 0 )
    345      goto Exit;
    346 
    347    /* now read postscript names data */
    348    if ( format == 0x00020000L )
    349      error = load_format_20( &face->postscript_names, stream,
    350                              num_glyphs, post_len - 34 );
    351    else if ( format == 0x00025000L )
    352      error = load_format_25( &face->postscript_names, stream,
    353                              num_glyphs, post_len - 34 );
    354 
    355  Exit:
    356    face->postscript_names.loaded = 1;  /* even if failed */
    357    return error;
    358  }
    359 
    360 
    361  FT_LOCAL_DEF( void )
    362  tt_face_free_ps_names( TT_Face  face )
    363  {
    364    FT_Memory      memory = face->root.memory;
    365    TT_Post_Names  names  = &face->postscript_names;
    366 
    367 
    368    if ( names->num_glyphs )
    369    {
    370      FT_FREE( names->glyph_indices );
    371      names->num_glyphs = 0;
    372    }
    373 
    374    if ( names->num_names )
    375    {
    376      FT_FREE( names->glyph_names );
    377      names->num_names = 0;
    378    }
    379 
    380    names->loaded = 0;
    381  }
    382 
    383 
    384  /**************************************************************************
    385   *
    386   * @Function:
    387   *   tt_face_get_ps_name
    388   *
    389   * @Description:
    390   *   Get the PostScript glyph name of a glyph.
    391   *
    392   * @Input:
    393   *   face ::
    394   *     A handle to the parent face.
    395   *
    396   *   idx ::
    397   *     The glyph index.
    398   *
    399   * @InOut:
    400   *   PSname ::
    401   *     The address of a string pointer.  Undefined in case of
    402   *     error, otherwise it is a pointer to the glyph name.
    403   *
    404   *     You must not modify the returned string!
    405   *
    406   * @Output:
    407   *   FreeType error code.  0 means success.
    408   */
    409  FT_LOCAL_DEF( FT_Error )
    410  tt_face_get_ps_name( TT_Face      face,
    411                       FT_UInt      idx,
    412                       FT_String**  PSname )
    413  {
    414    FT_Error       error;
    415    FT_Fixed       format;
    416 
    417 #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
    418    FT_Service_PsCMaps  psnames;
    419 #endif
    420 
    421 
    422    if ( !face )
    423      return FT_THROW( Invalid_Face_Handle );
    424 
    425    if ( idx >= (FT_UInt)face->max_profile.numGlyphs )
    426      return FT_THROW( Invalid_Glyph_Index );
    427 
    428 #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
    429    psnames = (FT_Service_PsCMaps)face->psnames;
    430    if ( !psnames )
    431      return FT_THROW( Unimplemented_Feature );
    432 #endif
    433 
    434    /* `.notdef' by default */
    435    *PSname = MAC_NAME( 0 );
    436 
    437    format = face->postscript.FormatType;
    438 
    439    if ( format == 0x00020000L ||
    440         format == 0x00025000L )
    441    {
    442      TT_Post_Names  names = &face->postscript_names;
    443 
    444 
    445      if ( !names->loaded )
    446      {
    447        error = load_post_names( face );
    448        if ( error )
    449          goto End;
    450      }
    451 
    452      if ( idx < (FT_UInt)names->num_glyphs )
    453      {
    454        FT_UShort  name_index = names->glyph_indices[idx];
    455 
    456 
    457        if ( name_index < 258 )
    458          *PSname = MAC_NAME( name_index );
    459        else  /* only for version 2.0 */
    460          *PSname = (FT_String*)names->glyph_names[name_index - 258];
    461      }
    462    }
    463 
    464    /* version 1.0 is only valid with 258 glyphs */
    465    else if ( format == 0x00010000L              &&
    466              face->max_profile.numGlyphs == 258 )
    467      *PSname = MAC_NAME( idx );
    468 
    469    /* nothing to do for format == 0x00030000L */
    470 
    471  End:
    472    /* post format errors ignored */
    473    return FT_Err_Ok;
    474  }
    475 
    476 #else /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
    477 
    478  /* ANSI C doesn't like empty source files */
    479  typedef int  tt_post_dummy_;
    480 
    481 #endif /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
    482 
    483 
    484 /* END */