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