tor-browser

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

afglobal.c (14304B)


      1 /****************************************************************************
      2 *
      3 * afglobal.c
      4 *
      5 *   Auto-fitter routines to compute global hinting values (body).
      6 *
      7 * Copyright (C) 2003-2025 by
      8 * David Turner, Robert Wilhelm, and Werner Lemberg.
      9 *
     10 * This file is part of the FreeType project, and may only be used,
     11 * modified, and distributed under the terms of the FreeType project
     12 * license, LICENSE.TXT.  By continuing to use, modify, or distribute
     13 * this file you indicate that you have read the license and
     14 * understand and accept it fully.
     15 *
     16 */
     17 
     18 
     19 #include "afglobal.h"
     20 #include "afranges.h"
     21 #include "afshaper.h"
     22 #include "afws-decl.h"
     23 #include <freetype/internal/ftdebug.h>
     24 
     25 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
     26 #  include "afgsub.h"
     27 #  include "ft-hb-ft.h"
     28 #endif
     29 
     30 
     31  /**************************************************************************
     32   *
     33   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
     34   * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
     35   * messages during execution.
     36   */
     37 #undef  FT_COMPONENT
     38 #define FT_COMPONENT  afglobal
     39 
     40 
     41 #include "aferrors.h"
     42 
     43 
     44 #undef  SCRIPT
     45 #define SCRIPT( s, S, d, h, H, ss )         \
     46          AF_DEFINE_SCRIPT_CLASS(           \
     47            af_ ## s ## _script_class,      \
     48            AF_SCRIPT_ ## S,                \
     49            af_ ## s ## _uniranges,         \
     50            af_ ## s ## _nonbase_uniranges, \
     51            AF_ ## H,                       \
     52            ss )
     53 
     54 #include "afscript.h"
     55 
     56 
     57 #undef  STYLE
     58 #define STYLE( s, S, d, ws, sc, ss, c )  \
     59          AF_DEFINE_STYLE_CLASS(         \
     60            af_ ## s ## _style_class,    \
     61            AF_STYLE_ ## S,              \
     62            ws,                          \
     63            sc,                          \
     64            ss,                          \
     65            c )
     66 
     67 #include "afstyles.h"
     68 
     69 
     70 #undef  WRITING_SYSTEM
     71 #define WRITING_SYSTEM( ws, WS )               \
     72          &af_ ## ws ## _writing_system_class,
     73 
     74  FT_LOCAL_ARRAY_DEF( AF_WritingSystemClass )
     75  af_writing_system_classes[] =
     76  {
     77 
     78 #include "afws-iter.h"
     79 
     80    NULL  /* do not remove */
     81  };
     82 
     83 
     84 #undef  SCRIPT
     85 #define SCRIPT( s, S, d, h, H, ss )   \
     86          &af_ ## s ## _script_class,
     87 
     88  FT_LOCAL_ARRAY_DEF( AF_ScriptClass )
     89  af_script_classes[] =
     90  {
     91 
     92 #include "afscript.h"
     93 
     94    NULL  /* do not remove */
     95  };
     96 
     97 
     98 #undef  STYLE
     99 #define STYLE( s, S, d, ws, sc, ss, c ) \
    100          &af_ ## s ## _style_class,
    101 
    102  FT_LOCAL_ARRAY_DEF( AF_StyleClass )
    103  af_style_classes[] =
    104  {
    105 
    106 #include "afstyles.h"
    107 
    108    NULL  /* do not remove */
    109  };
    110 
    111 
    112 #ifdef FT_DEBUG_LEVEL_TRACE
    113 
    114 #undef  STYLE
    115 #define STYLE( s, S, d, ws, sc, ss, c )  #s,
    116 
    117  FT_LOCAL_ARRAY_DEF( char* )
    118  af_style_names[] =
    119  {
    120 
    121 #include "afstyles.h"
    122 
    123  };
    124 
    125 #endif /* FT_DEBUG_LEVEL_TRACE */
    126 
    127 
    128  /* Compute the style index of each glyph within a given face. */
    129 
    130  static FT_Error
    131  af_face_globals_compute_style_coverage( AF_FaceGlobals  globals )
    132  {
    133    FT_Error    error;
    134    FT_Face     face        = globals->face;
    135    FT_CharMap  old_charmap = face->charmap;
    136    FT_UShort*  gstyles     = globals->glyph_styles;
    137    FT_UShort   ss;
    138    FT_UShort   dflt        = 0xFFFFU; /* a non-valid value */
    139    FT_UInt     i;
    140 
    141 
    142    /* the value AF_STYLE_UNASSIGNED means `uncovered glyph' */
    143    for ( i = 0; i < globals->glyph_count; i++ )
    144      gstyles[i] = AF_STYLE_UNASSIGNED;
    145 
    146    error = FT_Select_Charmap( face, FT_ENCODING_UNICODE );
    147    if ( error )
    148    {
    149      /*
    150       * Ignore this error; we simply use the fallback style.
    151       * XXX: Shouldn't we rather disable hinting?
    152       */
    153      error = FT_Err_Ok;
    154      goto Exit;
    155    }
    156 
    157    /* scan each style in a Unicode charmap */
    158    for ( ss = 0; af_style_classes[ss]; ss++ )
    159    {
    160      AF_StyleClass       style_class =
    161                            af_style_classes[ss];
    162      AF_ScriptClass      script_class =
    163                            af_script_classes[style_class->script];
    164      AF_Script_UniRange  range;
    165 
    166 
    167      if ( !script_class->script_uni_ranges )
    168        continue;
    169 
    170      /*
    171       * Scan all Unicode points in the range and set the corresponding
    172       * glyph style index.
    173       */
    174      if ( style_class->coverage == AF_COVERAGE_DEFAULT )
    175      {
    176        if ( style_class->script == globals->module->default_script )
    177          dflt = ss;
    178 
    179        for ( range = script_class->script_uni_ranges;
    180              range->first != 0;
    181              range++ )
    182        {
    183          FT_ULong  charcode = range->first;
    184          FT_UInt   gindex;
    185 
    186 
    187          gindex = FT_Get_Char_Index( face, charcode );
    188 
    189          if ( gindex != 0                                                &&
    190               gindex < globals->glyph_count                              &&
    191               ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED )
    192            gstyles[gindex] = ss | AF_HAS_CMAP_ENTRY;
    193 
    194          for (;;)
    195          {
    196            charcode = FT_Get_Next_Char( face, charcode, &gindex );
    197 
    198            if ( gindex == 0 || charcode > range->last )
    199              break;
    200 
    201            if ( gindex < globals->glyph_count                              &&
    202                 ( gstyles[gindex] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED )
    203              gstyles[gindex] = ss | AF_HAS_CMAP_ENTRY;
    204          }
    205        }
    206 
    207        /* do the same for the script's non-base characters */
    208        for ( range = script_class->script_uni_nonbase_ranges;
    209              range->first != 0;
    210              range++ )
    211        {
    212          FT_ULong  charcode = range->first;
    213          FT_UInt   gindex;
    214 
    215 
    216          gindex = FT_Get_Char_Index( face, charcode );
    217 
    218          if ( gindex != 0                               &&
    219               gindex < globals->glyph_count             &&
    220               ( gstyles[gindex] & AF_STYLE_MASK ) == ss )
    221            gstyles[gindex] |= AF_NONBASE;
    222 
    223          for (;;)
    224          {
    225            charcode = FT_Get_Next_Char( face, charcode, &gindex );
    226 
    227            if ( gindex == 0 || charcode > range->last )
    228              break;
    229 
    230            if ( gindex < globals->glyph_count             &&
    231                 ( gstyles[gindex] & AF_STYLE_MASK ) == ss )
    232              gstyles[gindex] |= AF_NONBASE;
    233          }
    234        }
    235      }
    236      else
    237      {
    238        /* get glyphs not directly addressable by cmap */
    239        af_shaper_get_coverage( globals, style_class, gstyles, 0 );
    240      }
    241    }
    242 
    243    /* handle the remaining default OpenType features ... */
    244    for ( ss = 0; af_style_classes[ss]; ss++ )
    245    {
    246      AF_StyleClass  style_class = af_style_classes[ss];
    247 
    248 
    249      if ( style_class->coverage == AF_COVERAGE_DEFAULT )
    250        af_shaper_get_coverage( globals, style_class, gstyles, 0 );
    251    }
    252 
    253    /* ... and finally the default OpenType features of the default script */
    254    af_shaper_get_coverage( globals, af_style_classes[dflt], gstyles, 1 );
    255 
    256    /* mark ASCII digits */
    257    for ( i = 0x30; i <= 0x39; i++ )
    258    {
    259      FT_UInt  gindex = FT_Get_Char_Index( face, i );
    260 
    261 
    262      if ( gindex != 0 && gindex < globals->glyph_count )
    263        gstyles[gindex] |= AF_DIGIT;
    264    }
    265 
    266  Exit:
    267    /*
    268     * By default, all uncovered glyphs are set to the fallback style.
    269     * XXX: Shouldn't we disable hinting or do something similar?
    270     */
    271    if ( globals->module->fallback_style != AF_STYLE_UNASSIGNED )
    272    {
    273      FT_UInt  nn;
    274 
    275 
    276      for ( nn = 0; nn < globals->glyph_count; nn++ )
    277      {
    278        if ( ( gstyles[nn] & AF_STYLE_MASK ) == AF_STYLE_UNASSIGNED )
    279        {
    280          gstyles[nn] &= ~AF_STYLE_MASK;
    281          gstyles[nn] |= globals->module->fallback_style;
    282        }
    283      }
    284    }
    285 
    286 #ifdef FT_DEBUG_LEVEL_TRACE
    287 
    288    FT_TRACE4(( "\n" ));
    289    FT_TRACE4(( "style coverage\n" ));
    290    FT_TRACE4(( "==============\n" ));
    291    FT_TRACE4(( "\n" ));
    292 
    293    for ( ss = 0; af_style_classes[ss]; ss++ )
    294    {
    295      AF_StyleClass  style_class = af_style_classes[ss];
    296      FT_UInt        count       = 0;
    297      FT_UInt        idx;
    298 
    299 
    300      FT_TRACE4(( "%s:\n", af_style_names[style_class->style] ));
    301 
    302      for ( idx = 0; idx < globals->glyph_count; idx++ )
    303      {
    304        if ( ( gstyles[idx] & AF_STYLE_MASK ) == style_class->style )
    305        {
    306          if ( !( count % 10 ) )
    307            FT_TRACE4(( " " ));
    308 
    309          FT_TRACE4(( " %u", idx ));
    310          count++;
    311 
    312          if ( !( count % 10 ) )
    313            FT_TRACE4(( "\n" ));
    314        }
    315      }
    316 
    317      if ( !count )
    318        FT_TRACE4(( "  (none)\n" ));
    319      if ( count % 10 )
    320        FT_TRACE4(( "\n" ));
    321    }
    322 
    323 #endif /* FT_DEBUG_LEVEL_TRACE */
    324 
    325    face->charmap = old_charmap;
    326    return error;
    327  }
    328 
    329 
    330  FT_LOCAL_DEF( FT_Error )
    331  af_face_globals_new( FT_Face          face,
    332                       AF_FaceGlobals  *aglobals,
    333                       AF_Module        module )
    334  {
    335    FT_Error        error;
    336    FT_Memory       memory;
    337    AF_FaceGlobals  globals = NULL;
    338 
    339 
    340    memory = face->memory;
    341 
    342    /* we allocate an AF_FaceGlobals structure together */
    343    /* with the glyph_styles array                      */
    344    if ( FT_QALLOC( globals,
    345                    sizeof ( *globals ) +
    346                      (FT_ULong)face->num_glyphs * sizeof ( FT_UShort ) ) )
    347      goto Exit;
    348 
    349    FT_ZERO( &globals->metrics );
    350 
    351    globals->face                      = face;
    352    globals->glyph_count               = (FT_UInt)face->num_glyphs;
    353    /* right after the globals structure come the glyph styles */
    354    globals->glyph_styles              = (FT_UShort*)( globals + 1 );
    355    globals->module                    = module;
    356    globals->stem_darkening_for_ppem   = 0;
    357    globals->darken_x                  = 0;
    358    globals->darken_y                  = 0;
    359    globals->standard_vertical_width   = 0;
    360    globals->standard_horizontal_width = 0;
    361    globals->scale_down_factor         = 0;
    362 
    363 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
    364    if ( ft_hb_enabled ( globals ) )
    365    {
    366      globals->hb_font = ft_hb_ft_font_create( globals );
    367      globals->hb_buf  = hb( buffer_create )();
    368 
    369      af_parse_gsub( globals );
    370    }
    371    else
    372    {
    373      globals->hb_font = NULL;
    374      globals->hb_buf  = NULL;
    375 
    376      globals->gsub                          = NULL;
    377      globals->gsub_lookups_single_alternate = NULL;
    378    }
    379 #endif
    380 
    381    error = af_face_globals_compute_style_coverage( globals );
    382    if ( error )
    383    {
    384      af_face_globals_free( globals );
    385      globals = NULL;
    386    }
    387    else
    388      globals->increase_x_height = AF_PROP_INCREASE_X_HEIGHT_MAX;
    389 
    390  Exit:
    391    *aglobals = globals;
    392    return error;
    393  }
    394 
    395 
    396  FT_LOCAL_DEF( void )
    397  af_face_globals_free( void*  globals_ )
    398  {
    399    AF_FaceGlobals  globals = (AF_FaceGlobals)globals_;
    400 
    401 
    402    if ( globals )
    403    {
    404      FT_Memory  memory = globals->face->memory;
    405      FT_UInt    nn;
    406 
    407 
    408      for ( nn = 0; nn < AF_STYLE_MAX; nn++ )
    409      {
    410        if ( globals->metrics[nn] )
    411        {
    412          AF_StyleClass          style_class =
    413            af_style_classes[nn];
    414          AF_WritingSystemClass  writing_system_class =
    415            af_writing_system_classes[style_class->writing_system];
    416 
    417 
    418          if ( writing_system_class->style_metrics_done )
    419            writing_system_class->style_metrics_done( globals->metrics[nn] );
    420 
    421          FT_FREE( globals->metrics[nn] );
    422        }
    423      }
    424 
    425 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
    426      if ( ft_hb_enabled ( globals ) )
    427      {
    428        hb( font_destroy )( globals->hb_font );
    429        hb( buffer_destroy )( globals->hb_buf );
    430 
    431        FT_FREE( globals->gsub );
    432        FT_FREE( globals->gsub_lookups_single_alternate );
    433      }
    434 #endif
    435 
    436      /* no need to free `globals->glyph_styles'; */
    437      /* it is part of the `globals' array        */
    438      FT_FREE( globals );
    439    }
    440  }
    441 
    442 
    443  FT_LOCAL_DEF( FT_Error )
    444  af_face_globals_get_metrics( AF_FaceGlobals    globals,
    445                               FT_UInt           gindex,
    446                               FT_UInt           options,
    447                               AF_StyleMetrics  *ametrics )
    448  {
    449    AF_StyleMetrics  metrics = NULL;
    450 
    451    AF_Style               style = (AF_Style)options;
    452    AF_WritingSystemClass  writing_system_class;
    453    AF_StyleClass          style_class;
    454 
    455    FT_Error  error = FT_Err_Ok;
    456 
    457 
    458    if ( gindex >= globals->glyph_count )
    459    {
    460      error = FT_THROW( Invalid_Argument );
    461      goto Exit;
    462    }
    463 
    464    /* if we have a forced style (via `options'), use it, */
    465    /* otherwise look into `glyph_styles' array           */
    466    if ( style == AF_STYLE_NONE_DFLT || style + 1 >= AF_STYLE_MAX )
    467      style = (AF_Style)( globals->glyph_styles[gindex] &
    468                          AF_STYLE_UNASSIGNED           );
    469 
    470  Again:
    471    style_class          = af_style_classes[style];
    472    writing_system_class = af_writing_system_classes
    473                             [style_class->writing_system];
    474 
    475    metrics = globals->metrics[style];
    476    if ( !metrics )
    477    {
    478      /* create the global metrics object if necessary */
    479      FT_Memory  memory = globals->face->memory;
    480 
    481 
    482      if ( FT_ALLOC( metrics, writing_system_class->style_metrics_size ) )
    483        goto Exit;
    484 
    485      metrics->style_class = style_class;
    486      metrics->globals     = globals;
    487 
    488      if ( writing_system_class->style_metrics_init )
    489      {
    490        error = writing_system_class->style_metrics_init( metrics,
    491                                                          globals->face );
    492        if ( error )
    493        {
    494          if ( writing_system_class->style_metrics_done )
    495            writing_system_class->style_metrics_done( metrics );
    496 
    497          FT_FREE( metrics );
    498 
    499          /* internal error code -1 indicates   */
    500          /* that no blue zones have been found */
    501          if ( error == -1 )
    502          {
    503            style = (AF_Style)( globals->glyph_styles[gindex] &
    504                                AF_STYLE_UNASSIGNED           );
    505            /* IMPORTANT: Clear the error code, see
    506             * https://gitlab.freedesktop.org/freetype/freetype/-/issues/1063
    507             */
    508            error = FT_Err_Ok;
    509            goto Again;
    510          }
    511 
    512          goto Exit;
    513        }
    514      }
    515 
    516      globals->metrics[style] = metrics;
    517    }
    518 
    519  Exit:
    520    *ametrics = metrics;
    521 
    522    return error;
    523  }
    524 
    525 
    526  FT_LOCAL_DEF( FT_Bool )
    527  af_face_globals_is_digit( AF_FaceGlobals  globals,
    528                            FT_UInt         gindex )
    529  {
    530    if ( gindex < globals->glyph_count )
    531      return FT_BOOL( globals->glyph_styles[gindex] & AF_DIGIT );
    532 
    533    return FT_BOOL( 0 );
    534  }
    535 
    536 
    537 /* END */