Home | History | Annotate | Download | only in cache
      1 /***************************************************************************/
      2 /*                                                                         */
      3 /*  ftcbasic.c                                                             */
      4 /*                                                                         */
      5 /*    The FreeType basic cache interface (body).                           */
      6 /*                                                                         */
      7 /*  Copyright 2003-2007, 2009-2011, 2013, 2014 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     {
    114       FT_TRACE1(( "ftc_basic_family_get_count: too large number of glyphs " ));
    115       FT_TRACE1(( "in this face, truncated\n", face->num_glyphs ));
    116     }
    117 
    118     if ( !error )
    119       result = (FT_UInt)face->num_glyphs;
    120 
    121     return result;
    122   }
    123 
    124 
    125   FT_CALLBACK_DEF( FT_Error )
    126   ftc_basic_family_load_bitmap( FTC_Family   ftcfamily,
    127                                 FT_UInt      gindex,
    128                                 FTC_Manager  manager,
    129                                 FT_Face     *aface )
    130   {
    131     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
    132     FT_Error         error;
    133     FT_Size          size;
    134 
    135 
    136     error = FTC_Manager_LookupSize( manager, &family->attrs.scaler, &size );
    137     if ( !error )
    138     {
    139       FT_Face  face = size->face;
    140 
    141 
    142       error = FT_Load_Glyph( face, gindex,
    143                              family->attrs.load_flags | FT_LOAD_RENDER );
    144       if ( !error )
    145         *aface = face;
    146     }
    147 
    148     return error;
    149   }
    150 
    151 
    152   FT_CALLBACK_DEF( FT_Error )
    153   ftc_basic_family_load_glyph( FTC_Family  ftcfamily,
    154                                FT_UInt     gindex,
    155                                FTC_Cache   cache,
    156                                FT_Glyph   *aglyph )
    157   {
    158     FTC_BasicFamily  family = (FTC_BasicFamily)ftcfamily;
    159     FT_Error         error;
    160     FTC_Scaler       scaler = &family->attrs.scaler;
    161     FT_Face          face;
    162     FT_Size          size;
    163 
    164 
    165     /* we will now load the glyph image */
    166     error = FTC_Manager_LookupSize( cache->manager,
    167                                     scaler,
    168                                     &size );
    169     if ( !error )
    170     {
    171       face = size->face;
    172 
    173       error = FT_Load_Glyph( face, gindex, family->attrs.load_flags );
    174       if ( !error )
    175       {
    176         if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP  ||
    177              face->glyph->format == FT_GLYPH_FORMAT_OUTLINE )
    178         {
    179           /* ok, copy it */
    180           FT_Glyph  glyph;
    181 
    182 
    183           error = FT_Get_Glyph( face->glyph, &glyph );
    184           if ( !error )
    185           {
    186             *aglyph = glyph;
    187             goto Exit;
    188           }
    189         }
    190         else
    191           error = FT_THROW( Invalid_Argument );
    192       }
    193     }
    194 
    195   Exit:
    196     return error;
    197   }
    198 
    199 
    200   FT_CALLBACK_DEF( FT_Bool )
    201   ftc_basic_gnode_compare_faceid( FTC_Node    ftcgnode,
    202                                   FT_Pointer  ftcface_id,
    203                                   FTC_Cache   cache,
    204                                   FT_Bool*    list_changed )
    205   {
    206     FTC_GNode        gnode   = (FTC_GNode)ftcgnode;
    207     FTC_FaceID       face_id = (FTC_FaceID)ftcface_id;
    208     FTC_BasicFamily  family  = (FTC_BasicFamily)gnode->family;
    209     FT_Bool          result;
    210 
    211 
    212     if ( list_changed )
    213       *list_changed = FALSE;
    214     result = FT_BOOL( family->attrs.scaler.face_id == face_id );
    215     if ( result )
    216     {
    217       /* we must call this function to avoid this node from appearing
    218        * in later lookups with the same face_id!
    219        */
    220       FTC_GNode_UnselectFamily( gnode, cache );
    221     }
    222     return result;
    223   }
    224 
    225 
    226  /*
    227   *
    228   * basic image cache
    229   *
    230   */
    231 
    232   static
    233   const FTC_IFamilyClassRec  ftc_basic_image_family_class =
    234   {
    235     {
    236       sizeof ( FTC_BasicFamilyRec ),
    237       ftc_basic_family_compare,
    238       ftc_basic_family_init,
    239       0,                        /* FTC_MruNode_ResetFunc */
    240       0                         /* FTC_MruNode_DoneFunc  */
    241     },
    242     ftc_basic_family_load_glyph
    243   };
    244 
    245 
    246   static
    247   const FTC_GCacheClassRec  ftc_basic_image_cache_class =
    248   {
    249     {
    250       ftc_inode_new,
    251       ftc_inode_weight,
    252       ftc_gnode_compare,
    253       ftc_basic_gnode_compare_faceid,
    254       ftc_inode_free,
    255 
    256       sizeof ( FTC_GCacheRec ),
    257       ftc_gcache_init,
    258       ftc_gcache_done
    259     },
    260     (FTC_MruListClass)&ftc_basic_image_family_class
    261   };
    262 
    263 
    264   /* documentation is in ftcache.h */
    265 
    266   FT_EXPORT_DEF( FT_Error )
    267   FTC_ImageCache_New( FTC_Manager      manager,
    268                       FTC_ImageCache  *acache )
    269   {
    270     return FTC_GCache_New( manager, &ftc_basic_image_cache_class,
    271                            (FTC_GCache*)acache );
    272   }
    273 
    274 
    275   /* documentation is in ftcache.h */
    276 
    277   FT_EXPORT_DEF( FT_Error )
    278   FTC_ImageCache_Lookup( FTC_ImageCache  cache,
    279                          FTC_ImageType   type,
    280                          FT_UInt         gindex,
    281                          FT_Glyph       *aglyph,
    282                          FTC_Node       *anode )
    283   {
    284     FTC_BasicQueryRec  query;
    285     FTC_Node           node = 0; /* make compiler happy */
    286     FT_Error           error;
    287     FT_PtrDist         hash;
    288 
    289 
    290     /* some argument checks are delayed to FTC_Cache_Lookup */
    291     if ( !aglyph )
    292     {
    293       error = FT_THROW( Invalid_Argument );
    294       goto Exit;
    295     }
    296 
    297     *aglyph = NULL;
    298     if ( anode )
    299       *anode  = NULL;
    300 
    301     {
    302       if ( (FT_ULong)(type->flags - FT_INT_MIN) > FT_UINT_MAX )
    303       {
    304         FT_TRACE1(( "FTC_ImageCache_Lookup: higher bits in load_flags" ));
    305         FT_TRACE1(( "0x%x are dropped\n", (type->flags & ~((FT_ULong)FT_UINT_MAX)) ));
    306       }
    307 
    308       query.attrs.scaler.face_id = type->face_id;
    309       query.attrs.scaler.width   = type->width;
    310       query.attrs.scaler.height  = type->height;
    311       query.attrs.load_flags     = (FT_UInt)type->flags;
    312     }
    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_PtrDist         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(), FT_Load_Char() take FT_UInt flags */
    378     if ( load_flags > FT_UINT_MAX )
    379     {
    380       FT_TRACE1(( "FTC_ImageCache_LookupScaler: higher bits in load_flags" ));
    381       FT_TRACE1(( "0x%x are dropped\n", (load_flags & ~((FT_ULong)FT_UINT_MAX)) ));
    382     }
    383 
    384     query.attrs.scaler     = scaler[0];
    385     query.attrs.load_flags = (FT_UInt)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   Exit:
    408     return error;
    409   }
    410 
    411 
    412   /*
    413    *
    414    * basic small bitmap cache
    415    *
    416    */
    417 
    418   static
    419   const FTC_SFamilyClassRec  ftc_basic_sbit_family_class =
    420   {
    421     {
    422       sizeof ( FTC_BasicFamilyRec ),
    423       ftc_basic_family_compare,
    424       ftc_basic_family_init,
    425       0,                            /* FTC_MruNode_ResetFunc */
    426       0                             /* FTC_MruNode_DoneFunc  */
    427     },
    428     ftc_basic_family_get_count,
    429     ftc_basic_family_load_bitmap
    430   };
    431 
    432 
    433   static
    434   const FTC_GCacheClassRec  ftc_basic_sbit_cache_class =
    435   {
    436     {
    437       ftc_snode_new,
    438       ftc_snode_weight,
    439       ftc_snode_compare,
    440       ftc_basic_gnode_compare_faceid,
    441       ftc_snode_free,
    442 
    443       sizeof ( FTC_GCacheRec ),
    444       ftc_gcache_init,
    445       ftc_gcache_done
    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 = 0; /* make compiler happy */
    474     FT_PtrDist         hash;
    475 
    476 
    477     if ( anode )
    478       *anode = NULL;
    479 
    480     /* other argument checks delayed to FTC_Cache_Lookup */
    481     if ( !ansbit )
    482       return FT_THROW( Invalid_Argument );
    483 
    484     *ansbit = NULL;
    485 
    486     {
    487       if ( (FT_ULong)(type->flags - FT_INT_MIN) > FT_UINT_MAX )
    488       {
    489         FT_TRACE1(( "FTC_ImageCache_Lookup: higher bits in load_flags" ));
    490         FT_TRACE1(( "0x%x are dropped\n", (type->flags & ~((FT_ULong)FT_UINT_MAX)) ));
    491       }
    492 
    493       query.attrs.scaler.face_id = type->face_id;
    494       query.attrs.scaler.width   = type->width;
    495       query.attrs.scaler.height  = type->height;
    496       query.attrs.load_flags     = (FT_UInt)type->flags;
    497     }
    498 
    499     query.attrs.scaler.pixel = 1;
    500     query.attrs.scaler.x_res = 0;  /* make compilers happy */
    501     query.attrs.scaler.y_res = 0;
    502 
    503     /* beware, the hash must be the same for all glyph ranges! */
    504     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
    505            gindex / FTC_SBIT_ITEMS_PER_NODE;
    506 
    507 #if 1  /* inlining is about 50% faster! */
    508     FTC_GCACHE_LOOKUP_CMP( cache,
    509                            ftc_basic_family_compare,
    510                            FTC_SNode_Compare,
    511                            hash, gindex,
    512                            &query,
    513                            node,
    514                            error );
    515 #else
    516     error = FTC_GCache_Lookup( FTC_GCACHE( cache ),
    517                                hash,
    518                                gindex,
    519                                FTC_GQUERY( &query ),
    520                                &node );
    521 #endif
    522     if ( error )
    523       goto Exit;
    524 
    525     *ansbit = FTC_SNODE( node )->sbits +
    526               ( gindex - FTC_GNODE( node )->gindex );
    527 
    528     if ( anode )
    529     {
    530       *anode = node;
    531       node->ref_count++;
    532     }
    533 
    534   Exit:
    535     return error;
    536   }
    537 
    538 
    539   /* documentation is in ftcache.h */
    540 
    541   FT_EXPORT_DEF( FT_Error )
    542   FTC_SBitCache_LookupScaler( FTC_SBitCache  cache,
    543                               FTC_Scaler     scaler,
    544                               FT_ULong       load_flags,
    545                               FT_UInt        gindex,
    546                               FTC_SBit      *ansbit,
    547                               FTC_Node      *anode )
    548   {
    549     FT_Error           error;
    550     FTC_BasicQueryRec  query;
    551     FTC_Node           node = 0; /* make compiler happy */
    552     FT_PtrDist         hash;
    553 
    554 
    555     if ( anode )
    556         *anode = NULL;
    557 
    558     /* other argument checks delayed to FTC_Cache_Lookup */
    559     if ( !ansbit || !scaler )
    560         return FT_THROW( Invalid_Argument );
    561 
    562     *ansbit = NULL;
    563 
    564     /* FT_Load_Glyph(), FT_Load_Char() take FT_UInt flags */
    565     if ( load_flags > FT_UINT_MAX )
    566     {
    567       FT_TRACE1(( "FTC_ImageCache_LookupScaler: higher bits in load_flags" ));
    568       FT_TRACE1(( "0x%x are dropped\n", (load_flags & ~((FT_ULong)FT_UINT_MAX)) ));
    569     }
    570 
    571     query.attrs.scaler     = scaler[0];
    572     query.attrs.load_flags = (FT_UInt)load_flags;
    573 
    574     /* beware, the hash must be the same for all glyph ranges! */
    575     hash = FTC_BASIC_ATTR_HASH( &query.attrs ) +
    576              gindex / FTC_SBIT_ITEMS_PER_NODE;
    577 
    578     FTC_GCACHE_LOOKUP_CMP( cache,
    579                            ftc_basic_family_compare,
    580                            FTC_SNode_Compare,
    581                            hash, gindex,
    582                            &query,
    583                            node,
    584                            error );
    585     if ( error )
    586       goto Exit;
    587 
    588     *ansbit = FTC_SNODE( node )->sbits +
    589               ( gindex - FTC_GNODE( node )->gindex );
    590 
    591     if ( anode )
    592     {
    593       *anode = node;
    594       node->ref_count++;
    595     }
    596 
    597   Exit:
    598     return error;
    599   }
    600 
    601 
    602 /* END */
    603