tor-browser

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

ftcbasic.c (16761B)


      1 /****************************************************************************
      2 *
      3 * ftcbasic.c
      4 *
      5 *   The FreeType basic cache interface (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 <freetype/internal/ftobjs.h>
     20 #include <freetype/internal/ftdebug.h>
     21 #include <freetype/ftcache.h>
     22 #include "ftcglyph.h"
     23 #include "ftcimage.h"
     24 #include "ftcsbits.h"
     25 
     26 #include "ftccback.h"
     27 #include "ftcerror.h"
     28 
     29 #undef  FT_COMPONENT
     30 #define FT_COMPONENT  cache
     31 
     32 
     33  /*
     34   * Basic Families
     35   *
     36   */
     37  typedef struct  FTC_BasicAttrRec_
     38  {
     39    FTC_ScalerRec  scaler;
     40    FT_Int32       load_flags;
     41 
     42  } FTC_BasicAttrRec, *FTC_BasicAttrs;
     43 
     44 #define FTC_BASIC_ATTR_COMPARE( a, b )                                 \
     45          FT_BOOL( FTC_SCALER_COMPARE( &(a)->scaler, &(b)->scaler ) && \
     46                   (a)->load_flags == (b)->load_flags               )
     47 
     48 #define FTC_BASIC_ATTR_HASH( a )                  \
     49          ( FTC_SCALER_HASH( &(a)->scaler ) +     \
     50            (FT_Offset)( 31 * (a)->load_flags ) )
     51 
     52 
     53  typedef struct  FTC_BasicQueryRec_
     54  {
     55    FTC_GQueryRec     gquery;
     56    FTC_BasicAttrRec  attrs;
     57 
     58  } FTC_BasicQueryRec, *FTC_BasicQuery;
     59 
     60 
     61  typedef struct  FTC_BasicFamilyRec_
     62  {
     63    FTC_FamilyRec     family;
     64    FTC_BasicAttrRec  attrs;
     65 
     66  } FTC_BasicFamilyRec, *FTC_BasicFamily;
     67 
     68 
     69  FT_CALLBACK_DEF( FT_Bool )
     70  ftc_basic_family_compare( FTC_MruNode  ftcfamily,
     71                            FT_Pointer   ftcquery )
     72  {
     73    FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
     74    FTC_BasicQuery   query  = (FTC_BasicQuery)ftcquery;
     75 
     76 
     77    return FTC_BASIC_ATTR_COMPARE( &family->attrs, &query->attrs );
     78  }
     79 
     80 
     81  FT_CALLBACK_DEF( FT_Error )
     82  ftc_basic_family_init( FTC_MruNode  ftcfamily,
     83                         FT_Pointer   ftcquery,
     84                         FT_Pointer   ftccache )
     85  {
     86    FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
     87    FTC_BasicQuery   query  = (FTC_BasicQuery)ftcquery;
     88    FTC_Cache        cache  = (FTC_Cache)ftccache;
     89 
     90 
     91    FTC_Family_Init( FTC_FAMILY( family ), cache );
     92    family->attrs = query->attrs;
     93    return 0;
     94  }
     95 
     96 
     97  FT_CALLBACK_DEF( FT_UInt )
     98  ftc_basic_family_get_count( FTC_Family   ftcfamily,
     99                              FTC_Manager  manager )
    100  {
    101    FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
    102    FT_Error         error;
    103    FT_Face          face;
    104    FT_UInt          result = 0;
    105 
    106 
    107    error = FTC_Manager_LookupFace( manager, family->attrs.scaler.face_id,
    108                                    &face );
    109 
    110    if ( error || !face )
    111      return result;
    112 
    113 #ifdef FT_DEBUG_LEVEL_TRACE
    114    if ( (FT_ULong)face->num_glyphs > FT_UINT_MAX || 0 > face->num_glyphs )
    115    {
    116      FT_TRACE1(( "ftc_basic_family_get_count:"
    117                  " the number of glyphs in this face is %ld,\n",
    118                  face->num_glyphs ));
    119      FT_TRACE1(( "                           "
    120                  " which is too much and thus truncated\n" ));
    121    }
    122 #endif
    123 
    124    result = (FT_UInt)face->num_glyphs;
    125 
    126    return result;
    127  }
    128 
    129 
    130  FT_CALLBACK_DEF( FT_Error )
    131  ftc_basic_family_load_bitmap( FTC_Family   ftcfamily,
    132                                FT_UInt      gindex,
    133                                FTC_Manager  manager,
    134                                FT_Face     *aface )
    135  {
    136    FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
    137    FT_Error         error;
    138    FT_Size          size;
    139 
    140 
    141    error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size );
    142    if ( !error )
    143    {
    144      FT_Face  face = size->face;
    145 
    146 
    147      error = FT_Load_Glyph( face,
    148                             gindex,
    149                             family->attrs.load_flags | FT_LOAD_RENDER );
    150      if ( !error )
    151        *aface = face;
    152    }
    153 
    154    return error;
    155  }
    156 
    157 
    158  FT_CALLBACK_DEF( FT_Error )
    159  ftc_basic_family_load_glyph( FTC_Family  ftcfamily,
    160                               FT_UInt     gindex,
    161                               FTC_Cache   cache,
    162                               FT_Glyph   *aglyph )
    163  {
    164    FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
    165    FT_Error         error;
    166    FTC_Scaler       scaler = &family->attrs.scaler;
    167    FT_Face          face;
    168    FT_Size          size;
    169 
    170 
    171    /* we will now load the glyph image */
    172    error = FTC_Manager_LookupSize( cache->manager,
    173                                    scaler,
    174                                    &size );
    175    if ( !error )
    176    {
    177      face = size->face;
    178 
    179      error = FT_Load_Glyph( face, gindex, family->attrs.load_flags );
    180      if ( !error )
    181      {
    182        if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP  ||
    183             face->glyph->format == FT_GLYPH_FORMAT_OUTLINE ||
    184             face->glyph->format == FT_GLYPH_FORMAT_SVG     )
    185        {
    186          /* ok, copy it */
    187          FT_Glyph  glyph;
    188 
    189 
    190          error = FT_Get_Glyph( face->glyph, &glyph );
    191          if ( !error )
    192          {
    193            *aglyph = glyph;
    194            goto Exit;
    195          }
    196        }
    197        else
    198          error = FT_THROW( Invalid_Argument );
    199      }
    200    }
    201 
    202  Exit:
    203    return error;
    204  }
    205 
    206 
    207  FT_CALLBACK_DEF( FT_Bool )
    208  ftc_basic_gnode_compare_faceid( FTC_Node    ftcgnode,
    209                                  FT_Pointer  ftcface_id,
    210                                  FTC_Cache   cache,
    211                                  FT_Bool*    list_changed )
    212  {
    213    FTC_GNode        gnode   = (FTC_GNode)ftcgnode;
    214    FTC_FaceID       face_id = (FTC_FaceID)ftcface_id;
    215    FTC_BasicFamily  family  = (FTC_BasicFamily)gnode->family;
    216    FT_Bool          result;
    217 
    218 
    219    if ( list_changed )
    220      *list_changed = FALSE;
    221    result = FT_BOOL( family->attrs.scaler.face_id == face_id );
    222    if ( result )
    223    {
    224      /* we must call this function to avoid this node from appearing
    225       * in later lookups with the same face_id!
    226       */
    227      FTC_GNode_UnselectFamily( gnode, cache );
    228    }
    229    return result;
    230  }
    231 
    232 
    233 /*
    234  *
    235  * basic image cache
    236  *
    237  */
    238 
    239  static
    240  const FTC_IFamilyClassRec  ftc_basic_image_family_class =
    241  {
    242    {
    243      sizeof ( FTC_BasicFamilyRec ),
    244 
    245      ftc_basic_family_compare, /* FTC_MruNode_CompareFunc  node_compare */
    246      ftc_basic_family_init,    /* FTC_MruNode_InitFunc     node_init    */
    247      NULL                      /* FTC_MruNode_DoneFunc     node_done    */
    248    },
    249 
    250    ftc_basic_family_load_glyph /* FTC_IFamily_LoadGlyphFunc  family_load_glyph */
    251  };
    252 
    253 
    254  static
    255  const FTC_GCacheClassRec  ftc_basic_image_cache_class =
    256  {
    257    {
    258      ftc_inode_new,                  /* FTC_Node_NewFunc      node_new           */
    259      ftc_inode_weight,               /* FTC_Node_WeightFunc   node_weight        */
    260      ftc_gnode_compare,              /* FTC_Node_CompareFunc  node_compare       */
    261      ftc_basic_gnode_compare_faceid, /* FTC_Node_CompareFunc  node_remove_faceid */
    262      ftc_inode_free,                 /* FTC_Node_FreeFunc     node_free          */
    263 
    264      sizeof ( FTC_GCacheRec ),
    265      ftc_gcache_init,                /* FTC_Cache_InitFunc    cache_init         */
    266      ftc_gcache_done                 /* FTC_Cache_DoneFunc    cache_done         */
    267    },
    268 
    269    (FTC_MruListClass)&ftc_basic_image_family_class
    270  };
    271 
    272 
    273  /* documentation is in ftcache.h */
    274 
    275  FT_EXPORT_DEF( FT_Error )
    276  FTC_ImageCache_New( FTC_Manager      manager,
    277                      FTC_ImageCache  *acache )
    278  {
    279    return FTC_GCache_New( manager, &ftc_basic_image_cache_class,
    280                           (FTC_GCache*)acache );
    281  }
    282 
    283 
    284  /* documentation is in ftcache.h */
    285 
    286  FT_EXPORT_DEF( FT_Error )
    287  FTC_ImageCache_Lookup( FTC_ImageCache  cache,
    288                         FTC_ImageType   type,
    289                         FT_UInt         gindex,
    290                         FT_Glyph       *aglyph,
    291                         FTC_Node       *anode )
    292  {
    293    FT_Error           error;
    294    FTC_BasicQueryRec  query;
    295    FTC_Node           node = NULL;  /* make compiler happy */
    296    FT_Offset          hash;
    297 
    298 
    299    /* other argument checks delayed to `FTC_Cache_Lookup' */
    300    if ( !aglyph )
    301      return FT_THROW( Invalid_Argument );
    302 
    303    *aglyph = NULL;
    304    if ( anode )
    305      *anode = NULL;
    306 
    307    query.attrs.scaler.face_id = type->face_id;
    308    query.attrs.scaler.width   = type->width;
    309    query.attrs.scaler.height  = type->height;
    310    query.attrs.load_flags     = type->flags;
    311 
    312    query.attrs.scaler.pixel = 1;
    313    query.attrs.scaler.x_res = 0;  /* make compilers happy */
    314    query.attrs.scaler.y_res = 0;
    315 
    316    hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
    317 
    318 #ifdef FTC_INLINE  /* inlining is about 50% faster! */
    319    FTC_GCACHE_LOOKUP_CMP( cache,
    320                           ftc_basic_family_compare,
    321                           ftc_gnode_compare,
    322                           hash, gindex,
    323                           &query,
    324                           node,
    325                           error );
    326 #else
    327    error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
    328                               hash, gindex,
    329                               FTC_GQUERY( &query ),
    330                               &node );
    331 #endif
    332    if ( !error )
    333    {
    334      *aglyph = FTC_INODE( node )->glyph;
    335 
    336      if ( anode )
    337      {
    338        *anode = node;
    339        node->ref_count++;
    340      }
    341    }
    342 
    343    return error;
    344  }
    345 
    346 
    347  /* documentation is in ftcache.h */
    348 
    349  FT_EXPORT_DEF( FT_Error )
    350  FTC_ImageCache_LookupScaler( FTC_ImageCache  cache,
    351                               FTC_Scaler      scaler,
    352                               FT_ULong        load_flags,
    353                               FT_UInt         gindex,
    354                               FT_Glyph       *aglyph,
    355                               FTC_Node       *anode )
    356  {
    357    FT_Error           error;
    358    FTC_BasicQueryRec  query;
    359    FTC_Node           node = NULL;  /* make compiler happy */
    360    FT_Offset          hash;
    361 
    362 
    363    /* other argument checks delayed to `FTC_Cache_Lookup' */
    364    if ( !aglyph || !scaler )
    365      return FT_THROW( Invalid_Argument );
    366 
    367    *aglyph = NULL;
    368    if ( anode )
    369      *anode = NULL;
    370 
    371    /*
    372     * Internal `FTC_BasicAttr->load_flags' is of type `FT_Int32',
    373     * but public `FT_Face->face_flags' is of type `FT_Long'.
    374     *
    375     * On long > int systems, higher bits of load_flags cannot be handled.
    376     */
    377 #if FT_ULONG_MAX > 0xFFFFFFFFUL
    378    if ( load_flags > 0xFFFFFFFFUL )
    379      FT_TRACE1(( "FTC_ImageCache_LookupScaler:"
    380                  " higher bits in load_flags 0x%lx are dropped\n",
    381                  load_flags & ~0xFFFFFFFFUL ));
    382 #endif
    383 
    384    query.attrs.scaler     = scaler[0];
    385    query.attrs.load_flags = (FT_Int32)load_flags;
    386 
    387    hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
    388 
    389    FTC_GCACHE_LOOKUP_CMP( cache,
    390                           ftc_basic_family_compare,
    391                           ftc_gnode_compare,
    392                           hash, gindex,
    393                           &query,
    394                           node,
    395                           error );
    396    if ( !error )
    397    {
    398      *aglyph = FTC_INODE( node )->glyph;
    399 
    400      if ( anode )
    401      {
    402        *anode = node;
    403        node->ref_count++;
    404      }
    405    }
    406 
    407    return error;
    408  }
    409 
    410 
    411  /*
    412   *
    413   * basic small bitmap cache
    414   *
    415   */
    416 
    417  static
    418  const FTC_SFamilyClassRec  ftc_basic_sbit_family_class =
    419  {
    420    {
    421      sizeof ( FTC_BasicFamilyRec ),
    422      ftc_basic_family_compare,     /* FTC_MruNode_CompareFunc  node_compare */
    423      ftc_basic_family_init,        /* FTC_MruNode_InitFunc     node_init    */
    424      NULL                          /* FTC_MruNode_DoneFunc     node_done    */
    425    },
    426 
    427    ftc_basic_family_get_count,
    428    ftc_basic_family_load_bitmap
    429  };
    430 
    431 
    432  static
    433  const FTC_GCacheClassRec  ftc_basic_sbit_cache_class =
    434  {
    435    {
    436      ftc_snode_new,                  /* FTC_Node_NewFunc      node_new           */
    437      ftc_snode_weight,               /* FTC_Node_WeightFunc   node_weight        */
    438      ftc_snode_compare,              /* FTC_Node_CompareFunc  node_compare       */
    439      ftc_basic_gnode_compare_faceid, /* FTC_Node_CompareFunc  node_remove_faceid */
    440      ftc_snode_free,                 /* FTC_Node_FreeFunc     node_free          */
    441 
    442      sizeof ( FTC_GCacheRec ),
    443      ftc_gcache_init,                /* FTC_Cache_InitFunc    cache_init         */
    444      ftc_gcache_done                 /* FTC_Cache_DoneFunc    cache_done         */
    445    },
    446 
    447    (FTC_MruListClass)&ftc_basic_sbit_family_class
    448  };
    449 
    450 
    451  /* documentation is in ftcache.h */
    452 
    453  FT_EXPORT_DEF( FT_Error )
    454  FTC_SBitCache_New( FTC_Manager     manager,
    455                     FTC_SBitCache  *acache )
    456  {
    457    return FTC_GCache_New( manager, &ftc_basic_sbit_cache_class,
    458                           (FTC_GCache*)acache );
    459  }
    460 
    461 
    462  /* documentation is in ftcache.h */
    463 
    464  FT_EXPORT_DEF( FT_Error )
    465  FTC_SBitCache_Lookup( FTC_SBitCache  cache,
    466                        FTC_ImageType  type,
    467                        FT_UInt        gindex,
    468                        FTC_SBit      *ansbit,
    469                        FTC_Node      *anode )
    470  {
    471    FT_Error           error;
    472    FTC_BasicQueryRec  query;
    473    FTC_Node           node = NULL;  /* make compiler happy */
    474    FT_Offset          hash;
    475 
    476 
    477    /* other argument checks delayed to `FTC_Cache_Lookup' */
    478    if ( !ansbit )
    479      return FT_THROW( Invalid_Argument );
    480 
    481    *ansbit = NULL;
    482    if ( anode )
    483      *anode = NULL;
    484 
    485    query.attrs.scaler.face_id = type->face_id;
    486    query.attrs.scaler.width   = type->width;
    487    query.attrs.scaler.height  = type->height;
    488    query.attrs.load_flags     = type->flags;
    489 
    490    query.attrs.scaler.pixel = 1;
    491    query.attrs.scaler.x_res = 0;  /* make compilers happy */
    492    query.attrs.scaler.y_res = 0;
    493 
    494    /* beware, the hash must be the same for all glyph ranges! */
    495    hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
    496           gindex / FTC_SBIT_ITEMS_PER_NODE;
    497 
    498 #ifdef FTC_INLINE  /* inlining is about 50% faster! */
    499    FTC_GCACHE_LOOKUP_CMP( cache,
    500                           ftc_basic_family_compare,
    501                           ftc_snode_compare,
    502                           hash, gindex,
    503                           &query,
    504                           node,
    505                           error );
    506 #else
    507    error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
    508                               hash,
    509                               gindex,
    510                               FTC_GQUERY( &query ),
    511                               &node );
    512 #endif
    513    if ( error )
    514      goto Exit;
    515 
    516    *ansbit = FTC_SNODE( node )->sbits +
    517              ( gindex - FTC_GNODE( node )->gindex );
    518 
    519    if ( anode )
    520    {
    521      *anode = node;
    522      node->ref_count++;
    523    }
    524 
    525  Exit:
    526    return error;
    527  }
    528 
    529 
    530  /* documentation is in ftcache.h */
    531 
    532  FT_EXPORT_DEF( FT_Error )
    533  FTC_SBitCache_LookupScaler( FTC_SBitCache  cache,
    534                              FTC_Scaler     scaler,
    535                              FT_ULong       load_flags,
    536                              FT_UInt        gindex,
    537                              FTC_SBit      *ansbit,
    538                              FTC_Node      *anode )
    539  {
    540    FT_Error           error;
    541    FTC_BasicQueryRec  query;
    542    FTC_Node           node = NULL;  /* make compiler happy */
    543    FT_Offset          hash;
    544 
    545 
    546    /* other argument checks delayed to `FTC_Cache_Lookup' */
    547    if ( !ansbit || !scaler )
    548      return FT_THROW( Invalid_Argument );
    549 
    550    *ansbit = NULL;
    551    if ( anode )
    552      *anode = NULL;
    553 
    554    /*
    555     * Internal `FTC_BasicAttr->load_flags' is of type `FT_Int32',
    556     * but public `FT_Face->face_flags' is of type `FT_Long'.
    557     *
    558     * On long > int systems, higher bits of load_flags cannot be handled.
    559     */
    560 #if FT_ULONG_MAX > 0xFFFFFFFFUL
    561    if ( load_flags > 0xFFFFFFFFUL )
    562      FT_TRACE1(( "FTC_ImageCache_LookupScaler:"
    563                  " higher bits in load_flags 0x%lx are dropped\n",
    564                  load_flags & ~0xFFFFFFFFUL ));
    565 #endif
    566 
    567    query.attrs.scaler     = scaler[0];
    568    query.attrs.load_flags = (FT_Int32)load_flags;
    569 
    570    /* beware, the hash must be the same for all glyph ranges! */
    571    hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
    572             gindex / FTC_SBIT_ITEMS_PER_NODE;
    573 
    574    FTC_GCACHE_LOOKUP_CMP( cache,
    575                           ftc_basic_family_compare,
    576                           ftc_snode_compare,
    577                           hash, gindex,
    578                           &query,
    579                           node,
    580                           error );
    581    if ( error )
    582      goto Exit;
    583 
    584    *ansbit = FTC_SNODE( node )->sbits +
    585              ( gindex - FTC_GNODE( node )->gindex );
    586 
    587    if ( anode )
    588    {
    589      *anode = node;
    590      node->ref_count++;
    591    }
    592 
    593  Exit:
    594    return error;
    595  }
    596 
    597 
    598 /* END */