Home | History | Annotate | Download | only in cache
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  ftcbasic.c                                                             */
      4 /*                                                                         */
      5 /*    The FreeType basic cache interface (body).                           */
      6 /*                                                                         */
      7 /*  Copyright 2003-2015 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 <ft2build.h>
     20 #include FT_INTERNAL_OBJECTS_H
     21 #include FT_INTERNAL_DEBUG_H
     22 #include FT_CACHE_H
     23 #include "ftcglyph.h"
     24 #include "ftcimage.h"
     25 #include "ftcsbits.h"
     26 
     27 #include "ftccback.h"
     28 #include "ftcerror.h"
     29 
     30 #define FT_COMPONENT  trace_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     if ( (FT_ULong)face->num_glyphs > FT_UINT_MAX || 0 > face->num_glyphs )
    113       FT_TRACE1(( "ftc_basic_family_get_count:"
    114                   " too large number of glyphs in this face, truncated\n",
    115                   face->num_glyphs ));
    116 
    117     if ( !error )
    118       result = (FT_UInt)face->num_glyphs;
    119 
    120     return result;
    121   }
    122 
    123 
    124   FT_CALLBACK_DEF( FT_Error )
    125   ftc_basic_family_load_bitmap( FTC_Family   ftcfamily,
    126                                 FT_UInt      gindex,
    127                                 FTC_Manager  manager,
    128                                 FT_Face     *aface )
    129   {
    130     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
    131     FT_Error         error;
    132     FT_Size          size;
    133 
    134 
    135     error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size );
    136     if ( !error )
    137     {
    138       FT_Face  face = size->face;
    139 
    140 
    141       error = FT_Load_Glyph(
    142                 face,
    143                 gindex,
    144                 (FT_Int)family->attrs.load_flags | FT_LOAD_RENDER );
    145       if ( !error )
    146         *aface = face;
    147     }
    148 
    149     return error;
    150   }
    151 
    152 
    153   FT_CALLBACK_DEF( FT_Error )
    154   ftc_basic_family_load_glyph( FTC_Family  ftcfamily,
    155                                FT_UInt     gindex,
    156                                FTC_Cache   cache,
    157                                FT_Glyph   *aglyph )
    158   {
    159     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
    160     FT_Error         error;
    161     FTC_Scaler       scaler = &family->attrs.scaler;
    162     FT_Face          face;
    163     FT_Size          size;
    164 
    165 
    166     /* we will now load the glyph image */
    167     error = FTC_Manager_LookupSize( cache->manager,
    168                                     scaler,
    169                                     &size );
    170     if ( !error )
    171     {
    172       face = size->face;
    173 
    174       error = FT_Load_Glyph( face,
    175                              gindex,
    176                              (FT_Int)family->attrs.load_flags );
    177       if ( !error )
    178       {
    179         if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP  ||
    180              face->glyph->format == FT_GLYPH_FORMAT_OUTLINE )
    181         {
    182           /* ok, copy it */
    183           FT_Glyph  glyph;
    184 
    185 
    186           error = FT_Get_Glyph( face->glyph, &glyph );
    187           if ( !error )
    188           {
    189             *aglyph = glyph;
    190             goto Exit;
    191           }
    192         }
    193         else
    194           error = FT_THROW( Invalid_Argument );
    195       }
    196     }
    197 
    198   Exit:
    199     return error;
    200   }
    201 
    202 
    203   FT_CALLBACK_DEF( FT_Bool )
    204   ftc_basic_gnode_compare_faceid( FTC_Node    ftcgnode,
    205                                   FT_Pointer  ftcface_id,
    206                                   FTC_Cache   cache,
    207                                   FT_Bool*    list_changed )
    208   {
    209     FTC_GNode        gnode   = (FTC_GNode)ftcgnode;
    210     FTC_FaceID       face_id = (FTC_FaceID)ftcface_id;
    211     FTC_BasicFamily  family  = (FTC_BasicFamily)gnode->family;
    212     FT_Bool          result;
    213 
    214 
    215     if ( list_changed )
    216       *list_changed = FALSE;
    217     result = FT_BOOL( family->attrs.scaler.face_id == face_id );
    218     if ( result )
    219     {
    220       /* we must call this function to avoid this node from appearing
    221        * in later lookups with the same face_id!
    222        */
    223       FTC_GNode_UnselectFamily( gnode, cache );
    224     }
    225     return result;
    226   }
    227 
    228 
    229  /*
    230   *
    231   * basic image cache
    232   *
    233   */
    234 
    235   static
    236   const FTC_IFamilyClassRec  ftc_basic_image_family_class =
    237   {
    238     {
    239       sizeof ( FTC_BasicFamilyRec ),
    240       ftc_basic_family_compare,
    241       ftc_basic_family_init,
    242       0,                        /* FTC_MruNode_ResetFunc */
    243       0                         /* FTC_MruNode_DoneFunc  */
    244     },
    245     ftc_basic_family_load_glyph
    246   };
    247 
    248 
    249   static
    250   const FTC_GCacheClassRec  ftc_basic_image_cache_class =
    251   {
    252     {
    253       ftc_inode_new,
    254       ftc_inode_weight,
    255       ftc_gnode_compare,
    256       ftc_basic_gnode_compare_faceid,
    257       ftc_inode_free,
    258 
    259       sizeof ( FTC_GCacheRec ),
    260       ftc_gcache_init,
    261       ftc_gcache_done
    262     },
    263     (FTC_MruListClass)&ftc_basic_image_family_class
    264   };
    265 
    266 
    267   /* documentation is in ftcache.h */
    268 
    269   FT_EXPORT_DEF( FT_Error )
    270   FTC_ImageCache_New( FTC_Manager      manager,
    271                       FTC_ImageCache  *acache )
    272   {
    273     return FTC_GCache_New( manager, &ftc_basic_image_cache_class,
    274                            (FTC_GCache*)acache );
    275   }
    276 
    277 
    278   /* documentation is in ftcache.h */
    279 
    280   FT_EXPORT_DEF( FT_Error )
    281   FTC_ImageCache_Lookup( FTC_ImageCache  cache,
    282                          FTC_ImageType   type,
    283                          FT_UInt         gindex,
    284                          FT_Glyph       *aglyph,
    285                          FTC_Node       *anode )
    286   {
    287     FTC_BasicQueryRec  query;
    288     FTC_Node           node = 0; /* make compiler happy */
    289     FT_Error           error;
    290     FT_Offset          hash;
    291 
    292 
    293     /* some argument checks are delayed to `FTC_Cache_Lookup' */
    294     if ( !aglyph )
    295     {
    296       error = FT_THROW( Invalid_Argument );
    297       goto Exit;
    298     }
    299 
    300     *aglyph = NULL;
    301     if ( anode )
    302       *anode  = NULL;
    303 
    304     if ( (FT_ULong)( type->flags - FT_INT_MIN ) > FT_UINT_MAX )
    305       FT_TRACE1(( "FTC_ImageCache_Lookup:"
    306                   " higher bits in load_flags 0x%x are dropped\n",
    307                   (FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) ));
    308 
    309     query.attrs.scaler.face_id = type->face_id;
    310     query.attrs.scaler.width   = type->width;
    311     query.attrs.scaler.height  = type->height;
    312     query.attrs.load_flags     = (FT_UInt)type->flags;
    313 
    314     query.attrs.scaler.pixel = 1;
    315     query.attrs.scaler.x_res = 0;  /* make compilers happy */
    316     query.attrs.scaler.y_res = 0;
    317 
    318     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
    319 
    320 #if 1  /* inlining is about 50% faster! */
    321     FTC_GCACHE_LOOKUP_CMP( cache,
    322                            ftc_basic_family_compare,
    323                            FTC_GNode_Compare,
    324                            hash, gindex,
    325                            &query,
    326                            node,
    327                            error );
    328 #else
    329     error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
    330                                hash, gindex,
    331                                FTC_GQUERY( &query ),
    332                                &node );
    333 #endif
    334     if ( !error )
    335     {
    336       *aglyph = FTC_INODE( node )->glyph;
    337 
    338       if ( anode )
    339       {
    340         *anode = node;
    341         node->ref_count++;
    342       }
    343     }
    344 
    345   Exit:
    346     return error;
    347   }
    348 
    349 
    350   /* documentation is in ftcache.h */
    351 
    352   FT_EXPORT_DEF( FT_Error )
    353   FTC_ImageCache_LookupScaler( FTC_ImageCache  cache,
    354                                FTC_Scaler      scaler,
    355                                FT_ULong        load_flags,
    356                                FT_UInt         gindex,
    357                                FT_Glyph       *aglyph,
    358                                FTC_Node       *anode )
    359   {
    360     FTC_BasicQueryRec  query;
    361     FTC_Node           node = 0; /* make compiler happy */
    362     FT_Error           error;
    363     FT_Offset          hash;
    364 
    365 
    366     /* some argument checks are delayed to `FTC_Cache_Lookup' */
    367     if ( !aglyph || !scaler )
    368     {
    369       error = FT_THROW( Invalid_Argument );
    370       goto Exit;
    371     }
    372 
    373     *aglyph = NULL;
    374     if ( anode )
    375       *anode  = NULL;
    376 
    377     /* `FT_Load_Glyph' and `FT_Load_Char' take FT_UInt flags */
    378     if ( load_flags > FT_UINT_MAX )
    379       FT_TRACE1(( "FTC_ImageCache_LookupScaler:"
    380                   " higher bits in load_flags 0x%x are dropped\n",
    381                   load_flags & ~((FT_ULong)FT_UINT_MAX) ));
    382 
    383     query.attrs.scaler     = scaler[0];
    384     query.attrs.load_flags = (FT_UInt)load_flags;
    385 
    386     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex;
    387 
    388     FTC_GCACHE_LOOKUP_CMP( cache,
    389                            ftc_basic_family_compare,
    390                            FTC_GNode_Compare,
    391                            hash, gindex,
    392                            &query,
    393                            node,
    394                            error );
    395     if ( !error )
    396     {
    397       *aglyph = FTC_INODE( node )->glyph;
    398 
    399       if ( anode )
    400       {
    401         *anode = node;
    402         node->ref_count++;
    403       }
    404     }
    405 
    406   Exit:
    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,
    423       ftc_basic_family_init,
    424       0,                            /* FTC_MruNode_ResetFunc */
    425       0                             /* FTC_MruNode_DoneFunc  */
    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,
    437       ftc_snode_weight,
    438       ftc_snode_compare,
    439       ftc_basic_gnode_compare_faceid,
    440       ftc_snode_free,
    441 
    442       sizeof ( FTC_GCacheRec ),
    443       ftc_gcache_init,
    444       ftc_gcache_done
    445     },
    446     (FTC_MruListClass)&ftc_basic_sbit_family_class
    447   };
    448 
    449 
    450   /* documentation is in ftcache.h */
    451 
    452   FT_EXPORT_DEF( FT_Error )
    453   FTC_SBitCache_New( FTC_Manager     manager,
    454                      FTC_SBitCache  *acache )
    455   {
    456     return FTC_GCache_New( manager, &ftc_basic_sbit_cache_class,
    457                            (FTC_GCache*)acache );
    458   }
    459 
    460 
    461   /* documentation is in ftcache.h */
    462 
    463   FT_EXPORT_DEF( FT_Error )
    464   FTC_SBitCache_Lookup( FTC_SBitCache  cache,
    465                         FTC_ImageType  type,
    466                         FT_UInt        gindex,
    467                         FTC_SBit      *ansbit,
    468                         FTC_Node      *anode )
    469   {
    470     FT_Error           error;
    471     FTC_BasicQueryRec  query;
    472     FTC_Node           node = 0; /* make compiler happy */
    473     FT_Offset          hash;
    474 
    475 
    476     if ( anode )
    477       *anode = NULL;
    478 
    479     /* other argument checks delayed to `FTC_Cache_Lookup' */
    480     if ( !ansbit )
    481       return FT_THROW( Invalid_Argument );
    482 
    483     *ansbit = NULL;
    484 
    485     if ( (FT_ULong)( type->flags - FT_INT_MIN ) > FT_UINT_MAX )
    486       FT_TRACE1(( "FTC_ImageCache_Lookup:"
    487                   " higher bits in load_flags 0x%x are dropped\n",
    488                   (FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) ));
    489 
    490     query.attrs.scaler.face_id = type->face_id;
    491     query.attrs.scaler.width   = type->width;
    492     query.attrs.scaler.height  = type->height;
    493     query.attrs.load_flags     = (FT_UInt)type->flags;
    494 
    495     query.attrs.scaler.pixel = 1;
    496     query.attrs.scaler.x_res = 0;  /* make compilers happy */
    497     query.attrs.scaler.y_res = 0;
    498 
    499     /* beware, the hash must be the same for all glyph ranges! */
    500     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
    501            gindex / FTC_SBIT_ITEMS_PER_NODE;
    502 
    503 #if 1  /* inlining is about 50% faster! */
    504     FTC_GCACHE_LOOKUP_CMP( cache,
    505                            ftc_basic_family_compare,
    506                            FTC_SNode_Compare,
    507                            hash, gindex,
    508                            &query,
    509                            node,
    510                            error );
    511 #else
    512     error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
    513                                hash,
    514                                gindex,
    515                                FTC_GQUERY( &query ),
    516                                &node );
    517 #endif
    518     if ( error )
    519       goto Exit;
    520 
    521     *ansbit = FTC_SNODE( node )->sbits +
    522               ( gindex - FTC_GNODE( node )->gindex );
    523 
    524     if ( anode )
    525     {
    526       *anode = node;
    527       node->ref_count++;
    528     }
    529 
    530   Exit:
    531     return error;
    532   }
    533 
    534 
    535   /* documentation is in ftcache.h */
    536 
    537   FT_EXPORT_DEF( FT_Error )
    538   FTC_SBitCache_LookupScaler( FTC_SBitCache  cache,
    539                               FTC_Scaler     scaler,
    540                               FT_ULong       load_flags,
    541                               FT_UInt        gindex,
    542                               FTC_SBit      *ansbit,
    543                               FTC_Node      *anode )
    544   {
    545     FT_Error           error;
    546     FTC_BasicQueryRec  query;
    547     FTC_Node           node = 0; /* make compiler happy */
    548     FT_Offset          hash;
    549 
    550 
    551     if ( anode )
    552         *anode = NULL;
    553 
    554     /* other argument checks delayed to `FTC_Cache_Lookup' */
    555     if ( !ansbit || !scaler )
    556         return FT_THROW( Invalid_Argument );
    557 
    558     *ansbit = NULL;
    559 
    560     /* `FT_Load_Glyph' and `FT_Load_Char' take FT_UInt flags */
    561     if ( load_flags > FT_UINT_MAX )
    562       FT_TRACE1(( "FTC_ImageCache_LookupScaler:"
    563                   " higher bits in load_flags 0x%x are dropped\n",
    564                   load_flags & ~((FT_ULong)FT_UINT_MAX) ));
    565 
    566     query.attrs.scaler     = scaler[0];
    567     query.attrs.load_flags = (FT_UInt)load_flags;
    568 
    569     /* beware, the hash must be the same for all glyph ranges! */
    570     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
    571              gindex / FTC_SBIT_ITEMS_PER_NODE;
    572 
    573     FTC_GCACHE_LOOKUP_CMP( cache,
    574                            ftc_basic_family_compare,
    575                            FTC_SNode_Compare,
    576                            hash, gindex,
    577                            &query,
    578                            node,
    579                            error );
    580     if ( error )
    581       goto Exit;
    582 
    583     *ansbit = FTC_SNODE( node )->sbits +
    584               ( gindex - FTC_GNODE( node )->gindex );
    585 
    586     if ( anode )
    587     {
    588       *anode = node;
    589       node->ref_count++;
    590     }
    591 
    592   Exit:
    593     return error;
    594   }
    595 
    596 
    597 /* END */
    598