Edit

kc3-lang/freetype/src/cache/ftcglyph.c

Branch :

  • Show log

    Commit

  • Author : David Turner
    Date : 2000-10-28 13:17:11
    Hash : 4e4a4363
    Message : - completed the abstract chunk cache class - started implementin a "small-bitmaps" cache derived from it - (soon a "metrics" cache will be written too)

  • src/cache/ftcglyph.c
  • /***************************************************************************/
    /*                                                                         */
    /*  ftcglyph.c                                                             */
    /*                                                                         */
    /*    FreeType Glyph Image (FT_Glyph) cache (body).                        */
    /*                                                                         */
    /*  Copyright 2000 by                                                      */
    /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
    /*                                                                         */
    /*  This file is part of the FreeType project, and may only be used,       */
    /*  modified, and distributed under the terms of the FreeType project      */
    /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
    /*  this file you indicate that you have read the license and              */
    /*  understand and accept it fully.                                        */
    /*                                                                         */
    /***************************************************************************/
    
    
    #include <freetype/cache/ftcglyph.h>
    #include <freetype/fterrors.h>
    #include <freetype/internal/ftobjs.h>
    #include <freetype/internal/ftlist.h>
    #include <freetype/fterrors.h>
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                      GLYPH NODES                              *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
    
      /* create a new glyph node, setting its cache index and ref count */
      FT_EXPORT_FUNC( void )  FTC_GlyphNode_Init( FTC_GlyphNode  node,
                                                  FTC_GlyphSet   gset,
                                                  FT_UInt        gindex )
      {
        FTC_Glyph_Cache      cache = gset->cache;
        FTC_CacheNode_Data*  data  = FTC_CACHENODE_TO_DATA_P( &node->root );
    
    
        data->cache_index = (FT_UShort)cache->root.cache_index;
        data->ref_count   = (FT_Short) 0;
        node->gset_index  = (FT_UShort)gset->gset_index;
        node->glyph_index = (FT_UShort)gindex;
      }
    
    
      /* Important: This function is called from the cache manager to */
      /* destroy a given cache node during `cache compression'.  The  */
      /* second argument is always `cache.user_data'.  Thus be        */
      /* certain that the function FTC_Glyph_Cache_New() does indeed  */
      /* set its `user_data' field correctly, otherwise bad things    */
      /* will happen!                                                 */
    
      FT_EXPORT_FUNC( void )  FTC_GlyphNode_Destroy( FTC_GlyphNode    node,
                                                     FTC_Glyph_Cache  cache )
      {
        FT_LruNode    gset_lru = cache->gsets_lru->nodes + node->gset_index;
        FTC_GlyphSet  gset     = (FTC_GlyphSet)gset_lru->root.data;
        FT_UInt       hash     = node->glyph_index % gset->hash_size;
        
        /* remove the node from its gset's bucket list */
        {
          FTC_GlyphNode*  pnode = gset->buckets + hash;
          FTC_GlyphNode   cur;
          
          for (;;)
          {
            cur = *pnode;
            if (!cur)
            {
              /* that's very strange, this should not happen !! */
              FT_ERROR(( "FTC_GlyphNode_Destroy:"
                         " trying to delete an unlisted node !!!!" ));
              return;
            }
              
            if (cur == node)
            {
              *pnode = cur->gset_next;
              break;
            }
            pnode = &cur->gset_next;
          }
        }
    
        /* destroy the node */
        gset->clazz->destroy_node( node, gset );
      }
    
    
      /* Important: This function is called from the cache manager to */
      /* size a given cache node during `cache compression'.  The     */
      /* second argument is always `cache.user_data'.  Thus be        */
      /* certain that the function FTC_Glyph_Cache_New() does indeed  */
      /* set its `user_data' field correctly, otherwise bad things    */
      /* will happen!                                                 */
    
      FT_EXPORT_FUNC( FT_ULong )  FTC_GlyphNode_Size( FTC_GlyphNode    node,
                                                      FTC_Glyph_Cache  cache )
      {
        FT_LruNode    gset_lru = cache->gsets_lru->nodes + node->gset_index;
        FTC_GlyphSet  gset     = (FTC_GlyphSet)gset_lru->root.data;
    
    
        return gset->clazz->size_node( node, gset );
      }
    
    
      FT_CPLUSPLUS( const FTC_CacheNode_Class )  ftc_glyph_cache_node_class =
      {
        (FTC_CacheNode_SizeFunc)    FTC_GlyphNode_Size,
        (FTC_CacheNode_DestroyFunc) FTC_GlyphNode_Destroy
      };
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                      GLYPH QUEUES                             *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
    
      FT_EXPORT_FUNC( FT_Error )  FTC_GlyphSet_New( FTC_Glyph_Cache  cache,
                                                    FT_Pointer       type,
                                                    FTC_GlyphSet    *aset )
      {
        FT_Error        error;
        FT_Memory       memory  = cache->root.memory;
        FTC_Manager     manager = cache->root.manager;
        FTC_GlyphSet    gset   = 0;
    
        FTC_Glyph_Cache_Class*  gcache_class;
        FTC_GlyphSet_Class*     clazz;
    
    
        gcache_class = (FTC_Glyph_Cache_Class*)cache->root.clazz;
        clazz        = gcache_class->gset_class;
    
        *aset = 0;
    
        if ( ALLOC( gset, clazz->gset_byte_size ) )
          goto Exit;
    
        gset->cache     = cache;
        gset->manager   = manager;
        gset->memory    = memory;
        gset->hash_size = FTC_GSET_HASH_SIZE_DEFAULT;
        gset->clazz     = clazz;
    
        /* allocate buckets table */
        if ( ALLOC_ARRAY( gset->buckets, gset->hash_size, FTC_GlyphNode ) )
          goto Exit;
    
        /* initialize gset by type if needed */
        if ( clazz->init )
        {
          error = clazz->init( gset, type );
          if ( error )
            goto Exit;
        }
    
        *aset = gset;
    
      Exit:
        if ( error && gset )
        {
          FREE( gset->buckets );
          FREE( gset );
        }
    
        return error;
      }
    
    
      FT_EXPORT_FUNC( void )  FTC_GlyphSet_Destroy( FTC_GlyphSet  gset )
      {
        FTC_Glyph_Cache         cache        = gset->cache;
        FTC_Manager             manager      = cache->root.manager;
        FT_List                 glyphs_lru   = &manager->global_lru;
        FTC_GlyphNode*          bucket       = gset->buckets;
        FTC_GlyphNode*          bucket_limit = bucket + gset->hash_size;
        FT_Memory               memory       = cache->root.memory;
    
        FTC_GlyphSet_Class*  clazz = gset->clazz;
    
    
        /* for each bucket, free the list of glyph nodes */
        for ( ; bucket < bucket_limit; bucket++ )
        {
          FTC_GlyphNode   node = bucket[0];
          FTC_GlyphNode   next = 0;
          FT_ListNode     lrunode;
    
    
          for ( ; node; node = next )
          {
            next    = node->gset_next;
            lrunode = FTC_GLYPHNODE_TO_LRUNODE( node );
    
            manager->num_bytes -= clazz->size_node( node, gset );
    
            FT_List_Remove( glyphs_lru, lrunode );
    
            clazz->destroy_node( node, gset );
          }
    
          bucket[0] = 0;
        }
    
        if ( clazz->done )
          clazz->done( gset );
    
        FREE( gset->buckets );
        FREE( gset );
      }
    
    
      FT_EXPORT_FUNC( FT_Error )
      FTC_GlyphSet_Lookup_Node( FTC_GlyphSet    gset,
                                FT_UInt         glyph_index,
                                FTC_GlyphNode  *anode )
      {
        FTC_Glyph_Cache         cache      = gset->cache;
        FTC_Manager             manager    = cache->root.manager;
        FT_UInt                 hash_index = glyph_index % gset->hash_size;
        FTC_GlyphNode*          bucket     = gset->buckets + hash_index;
        FTC_GlyphNode*          pnode      = bucket;
        FTC_GlyphNode           node;
        FT_Error                error;
    
        FTC_GlyphSet_Class*  clazz = gset->clazz;
    
    
        *anode = 0;
        
        for ( ;; )
        {
          node = *pnode;
          if (!node)
            break;
            
          if ( node->glyph_index == glyph_index )
          {
            /* we found it! -- move glyph to start of the lists */
            *pnode          = node->gset_next;
            node->gset_next = bucket[0];
            bucket[0]       = node;
            
            FT_List_Up( &manager->global_lru, FTC_GLYPHNODE_TO_LRUNODE( node ) );
            *anode = node;
            return 0;
          }
          /* go to next node in bucket */
          pnode = &node->gset_next;
        }
    
        /* we didn't found the glyph image, we will now create a new one */
        error = clazz->new_node( gset, glyph_index, &node );
        if ( error )
          goto Exit;
    
        /* insert the node at the start of our bucket list */
        node->gset_next = bucket[0];
        bucket[0]       = node;
    
        /* insert the node at the start the global LRU glyph list */
        FT_List_Insert( &manager->global_lru, FTC_GLYPHNODE_TO_LRUNODE( node ) );
    
        manager->num_bytes += clazz->size_node( node, gset );
    
        if (manager->num_bytes > manager->max_bytes)
        {
          FTC_GlyphNode_Ref   ( node );
          FTC_Manager_Compress( manager );
          FTC_GlyphNode_Unref ( node );
        }
    
        *anode = node;
    
      Exit:
        return error;
      }
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                   GLYPH SETS LRU CALLBACKS                    *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
    
    #define FTC_GSET_LRU_GET_CACHE( lru )   \
              ( (FTC_Glyph_Cache)(lru)->user_data )
    
    #define FTC_GSET_LRU_GET_MANAGER( lru ) \
              FTC_GSET_LRU_GET_CACHE( lru )->manager
    
    #define FTC_LRUNODE_GSET( node )        \
              ( (FTC_GlyphSet)(node)->root.data )
    
    
      LOCAL_FUNC_X
      FT_Error  ftc_glyph_set_lru_init( FT_Lru      lru,
                                        FT_LruNode  node )
      {
        FTC_Glyph_Cache  cache = FTC_GSET_LRU_GET_CACHE( lru );
        FT_Error         error;
        FTC_GlyphSet     gset;
    
    
        error = FTC_GlyphSet_New( cache, (FT_Pointer)node->key, &gset );
        if ( !error )
        {
          /* good, now set the gset index within the gset object */
          gset->gset_index = node - lru->nodes;
          node->root.data  = gset;
        }
    
        return error;
      }
    
    
      LOCAL_FUNC_X
      void  ftc_glyph_set_lru_done( FT_Lru      lru,
                                    FT_LruNode  node )
      {
        FTC_GlyphSet  gset = FTC_LRUNODE_GSET( node );
    
        FT_UNUSED( lru );
    
    
        FTC_GlyphSet_Destroy( gset );
      }
    
    
      LOCAL_FUNC_X
      FT_Bool  ftc_glyph_set_lru_compare( FT_LruNode  node,
                                          FT_LruKey   key )
      {
        FTC_GlyphSet  gset = FTC_LRUNODE_GSET( node );
    
    
        return gset->clazz->compare( gset, (FT_Pointer)key );
      }
    
    
      FT_CPLUSPLUS( const FT_Lru_Class )  ftc_glyph_set_lru_class =
      {
        sizeof( FT_LruRec ),
        ftc_glyph_set_lru_init,
        ftc_glyph_set_lru_done,
        0,  /* no flush */
        ftc_glyph_set_lru_compare
      };
    
    
      /*************************************************************************/
      /*************************************************************************/
      /*****                                                               *****/
      /*****                GLYPH IMAGE CACHE OBJECTS                      *****/
      /*****                                                               *****/
      /*************************************************************************/
      /*************************************************************************/
    
    
      FT_EXPORT_FUNC( FT_Error )  FTC_Glyph_Cache_Init( FTC_Glyph_Cache  cache )
      {
        FT_Memory  memory = cache->root.memory;
        FT_Error   error;
    
    
        /* set up root node_class to be used by manager */
        cache->root.node_clazz =
          (FTC_CacheNode_Class*)&ftc_glyph_cache_node_class;
    
        /* The following is extremely important for ftc_destroy_glyph_image() */
        /* to work properly, as the second parameter that is sent to it       */
        /* through the cache manager is `user_data' and must be set to        */
        /* `cache' here.                                                      */
        /*                                                                    */
        cache->root.cache_user = cache;
    
        error = FT_Lru_New( &ftc_glyph_set_lru_class,
                            FTC_MAX_GLYPH_SETS,
                            cache,
                            memory,
                            1, /* pre_alloc == TRUE */
                            &cache->gsets_lru );
        return error;
      }
    
    
      FT_EXPORT_FUNC( void )  FTC_Glyph_Cache_Done( FTC_Glyph_Cache  cache )
      {
        /* discard glyph sets */
        FT_Lru_Done( cache->gsets_lru );
      }
    
    
    /* END */