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