shithub: freetype+ttf2subf

Download patch

ref: 08b7ad4418df8c81f0822c5f1edb6332cfa046a8
parent: 7504e48eaa5ceb61159d10d0c2ebbb64986c0a3f
author: David Turner <[email protected]>
date: Fri Jun 7 16:07:44 EDT 2002

* include/freetype/cache/ftccache.h, src/cache/ftccache.c,
          src/cache/ftccache.i, src/cache/ftcsbits.c: adding various
          experimental optimisations to the cache manager

        * src/type42/t42parse.c: removing duplicate function

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2002-06-07  Graham Asher  <[email protected]>
 
+        * include/freetype/cache/ftccache.h, src/cache/ftccache.c,
+          src/cache/ftccache.i, src/cache/ftcsbits.c: adding various
+          experimental optimisations to the cache manager
+
+        * src/type42/t42parse.c: removing duplicate function
+
         * src/base/ftobjs.c (FT_Render_Glyph_Internal): changed definition
           from FT_EXPORT_DEF to FT_BASE_DEF
 
--- a/include/freetype/cache/ftccache.h
+++ b/include/freetype/cache/ftccache.h
@@ -20,6 +20,12 @@
 #define __FTCCACHE_H__
 
 
+/* define to allow cache lookup inlining */
+#undef   FTC_CACHE_USE_INLINE
+
+/* define to use linear hash table */
+#undef   FTC_CACHE_USE_LINEAR_HASHING
+
 FT_BEGIN_HEADER
 
   /* handle to cache object */
@@ -174,8 +180,14 @@
     FT_UInt              cache_index;  /* in manager's table         */
     FT_Pointer           cache_data;   /* used by cache node methods */
 
+#ifdef FTC_CACHE_USE_LINEAR_HASHING
+    FT_UFast             p;
+    FT_UFast             mask;
+    FT_Long              slack;
+#else
     FT_UFast             nodes;
     FT_UFast             size;
+#endif
     FTC_Node*            buckets;
 
     FT_LruList_ClassRec  family_class;
@@ -289,7 +301,6 @@
                     FTC_Node  *anode );
 
  /* */
-
 
 FT_END_HEADER
 
--- a/src/cache/ftccache.c
+++ b/src/cache/ftccache.c
@@ -23,7 +23,22 @@
 
 #include "ftcerror.h"
 
+/* define for level-1 optimisations */
+#undef   OPT1
 
+
+
+#ifdef FTC_CACHE_USE_LINEAR_HASHING
+
+#define  FTC_HASH_MAX_LOAD  2
+#define  FTC_HASH_MIN_LOAD  1
+#define  FTC_HASH_SUB_LOAD  (FTC_HASH_MAX_LOAD-FTC_HASH_MIN_LOAD)
+
+/* this one _must_ be a power of 2 !! */
+#define  FTC_HASH_INITIAL_SIZE  8
+
+#endif /* FTC_CACHE_USE_LINEAR_HASHING */
+
   /*************************************************************************/
   /*************************************************************************/
   /*****                                                               *****/
@@ -59,11 +74,13 @@
 
     if ( first )
     {
-      node->mru_prev = first->mru_prev;
+      FTC_Node  last = first->mru_prev;
+      
+      node->mru_prev = last;
       node->mru_next = first;
 
-      first->mru_prev->mru_next = node;
-      first->mru_prev           = node;
+      last->mru_next  = node;
+      first->mru_prev = node;
     }
     else
     {
@@ -114,13 +131,105 @@
 
     if ( node != first )
     {
-      ftc_node_mru_unlink( node, manager );
-      ftc_node_mru_link( node, manager );
+      FTC_Node  prev = node->mru_prev;
+      FTC_Node  next = node->mru_next;
+      FTC_Node  last = first->mru_prev;
+
+      prev->mru_next = next;
+      next->mru_prev = prev;
+
+      node->mru_next  = first;
+      node->mru_prev  = last;
+      first->mru_prev = node;
+      last->mru_next  = node;
+
+      manager->nodes_list = node;
     }
   }
 
 
+#ifdef FTC_CACHE_USE_LINEAR_HASHING
+
   /* remove a node from its cache's hash table */
+  static FT_Error
+  ftc_node_hash_unlink( FTC_Node   node,
+                        FTC_Cache  cache )
+  {
+    FT_Error   error = 0;
+    FTC_Node  *pnode;
+    FT_UInt    index, num_buckets;
+
+    index = (FT_UInt)( node->hash & cache->mask );
+    if ( index < cache->p )
+      index = (FT_UInt)( node->hash & (2*cache->mask+1) );
+
+    pnode = cache->buckets + index;
+
+    for (;;)
+    {
+      if ( *pnode == NULL )
+      {
+        FT_ERROR(( "FreeType.cache.hash_unlink: unknown node!\n" ));
+        return 0;
+      }
+
+      if ( *pnode == node )
+      {
+        *pnode     = node->link;
+        node->link = NULL;
+        break;
+      }
+
+      pnode = &(*pnode)->link;
+    }
+
+    num_buckets = ( cache->p + cache->mask + 1) ;
+
+    if ( ++ cache->slack > (FT_Long)num_buckets*FTC_HASH_SUB_LOAD )
+    {
+      FT_UInt    p         = cache->p;
+      FT_UInt    mask      = cache->mask;
+      FT_UInt    old_index = p + mask;
+      FTC_Node*  pold;
+
+      FT_ASSERT( old_index >= FTC_HASH_INITIAL_SIZE );
+
+      if ( p == 0 )
+      {
+        FT_Memory  memory = cache->memory;
+
+
+        cache->mask >>= 1;
+        p             = cache->mask;
+
+        if ( FT_RENEW_ARRAY( cache->buckets, (mask+1)*2, (mask) ) )
+        {
+          FT_ERROR(( "FreeType.cache.hash_unlink: couldn't shunk buckets !\n" ));
+          goto Exit;
+        }
+      }
+      else
+        p--;
+
+      pnode = cache->buckets + p;
+      while ( *pnode )
+        pnode = &(*pnode)->link;
+
+      pold   = cache->buckets + old_index;
+      *pnode = *pold;
+      *pold  = NULL;
+
+      cache->slack -= FTC_HASH_MAX_LOAD;
+      cache->p      = p;
+    }
+
+  Exit:
+    return error;
+  }
+
+#else /* !FTC_CACHE_USE_LINEAR_HASHING */
+
+  /* remove a node from its cache's hash table */
   static void
   ftc_node_hash_unlink( FTC_Node   node,
                         FTC_Cache  cache )
@@ -127,7 +236,6 @@
   {
     FTC_Node  *pnode = cache->buckets + ( node->hash % cache->size );
 
-
     for (;;)
     {
       if ( *pnode == NULL )
@@ -149,8 +257,83 @@
     }
   }
 
+#endif /* !FTC_CACHE_USE_LINEAR_HASHING */
 
+
+#ifdef FTC_CACHE_USE_LINEAR_HASHING
+
   /* add a node to the "top" of its cache's hash table */
+  static FT_Error
+  ftc_node_hash_link( FTC_Node   node,
+                      FTC_Cache  cache )
+  {
+    FTC_Node  *pnode;
+    FT_UInt    index;
+    FT_Error   error = 0;
+
+    index = (FT_UInt)( node->hash & cache->mask );
+    if ( index < cache->p )
+      index = (FT_UInt)( node->hash & (2*cache->mask+1) );
+
+    pnode = cache->buckets + index;
+
+    node->link = *pnode;
+    *pnode     = node;
+
+    if ( --cache->slack < 0 )
+    {
+      FT_UInt    p     = cache->p;
+      FT_UInt    mask  = cache->mask;
+      FTC_Node   new_list;
+
+      /* split a single bucket */
+      new_list = NULL;
+      pnode    = cache->buckets + p;
+      for (;;)
+      {
+        node = *pnode;
+        if ( node == NULL )
+          break;
+
+        if ( node->hash & (mask+1) )
+        {
+          *pnode     = node->link;
+          node->link = new_list;
+          new_list   = node;
+        }
+        else
+          pnode = &node->link;
+      }
+
+      cache->buckets[ p + mask + 1 ] = new_list;
+
+      cache->slack += FTC_HASH_MAX_LOAD;
+
+      if ( p >= mask )
+      {
+        FT_Memory  memory = cache->memory;
+
+
+        if ( FT_RENEW_ARRAY( cache->buckets, (mask+1)*2, (mask+1)*4 ) )
+        {
+          FT_ERROR(( "FreeType.cache.hash_unlink: couldn't expand buckets !\n" ));
+          goto Exit;
+        }
+
+        cache->mask = 2*mask + 1;
+        cache->p    = 0;
+      }
+      else
+        cache->p = p + 1;
+    }
+
+  Exit:
+    return error;
+  }
+
+#else /* !FTC_CACHE_USE_LINEAR_HASHING */
+
+  /* add a node to the "top" of its cache's hash table */
   static void
   ftc_node_hash_link( FTC_Node   node,
                       FTC_Cache  cache )
@@ -157,7 +340,6 @@
   {
     FTC_Node  *pnode = cache->buckets + ( node->hash % cache->size );
 
-
     node->link = *pnode;
     *pnode     = node;
 
@@ -164,7 +346,10 @@
     cache->nodes++;
   }
 
+#endif /* !FTC_CACHE_USE_LINEAR_HASHING */
 
+
+
   /* remove a node from the cache manager */
   FT_EXPORT_DEF( void )
   ftc_node_destroy( FTC_Node     node,
@@ -276,6 +461,11 @@
   /*************************************************************************/
   /*************************************************************************/
 
+#ifdef FTC_CACHE_USE_LINEAR_HASHING
+
+
+#else /* !FTC_CACHE_USE_LINEAR_HASHING */
+
 #define FTC_PRIMES_MIN  7
 #define FTC_PRIMES_MAX  13845163
 
@@ -388,6 +578,7 @@
     }
   }
 
+#endif /* !FTC_CACHE_USE_LINEAR_HASHING */
 
   FT_EXPORT_DEF( FT_Error )
   ftc_cache_init( FTC_Cache  cache )
@@ -397,6 +588,16 @@
     FT_Error         error;
 
 
+#ifdef FTC_CACHE_USE_LINEAR_HASHING
+
+    cache->p     = 0;
+    cache->mask  = FTC_HASH_INITIAL_SIZE-1;
+    cache->slack = FTC_HASH_INITIAL_SIZE*FTC_HASH_MAX_LOAD;
+
+    if ( FT_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE*2 ) )
+      goto Exit;
+
+#else /* !FTC_CACHE_USE_LINEAR_HASHING */
     cache->nodes = 0;
     cache->size  = FTC_PRIMES_MIN;
 
@@ -403,6 +604,8 @@
     if ( FT_NEW_ARRAY( cache->buckets, cache->size ) )
       goto Exit;
 
+#endif /* !FTC_CACHE_USE_LINEAR_HASHING */
+
     /* now, initialize the lru list of families for this cache */
     if ( clazz->family_size > 0 )
     {
@@ -442,9 +645,15 @@
       FTC_Cache_Class  clazz   = cache->clazz;
       FTC_Manager      manager = cache->manager;
       FT_UFast         i;
+      FT_UInt          count;
 
+#ifdef FTC_CACHE_USE_LINEAR_HASHING
+      count = cache->p + cache->mask + 1;
+#else
+      count = cache->size;
+#endif
 
-      for ( i = 0; i < cache->size; i++ )
+      for ( i = 0; i < count; i++ )
       {
         FTC_Node  *pnode = cache->buckets + i, next, node = *pnode;
 
@@ -469,8 +678,11 @@
         cache->buckets[i] = NULL;
       }
 
+#ifdef FTC_CACHE_USE_LINEAR_HASHING
+      cache->p = 0;
+#else
       cache->nodes = 0;
-
+#endif
       /* destroy the families */
       if ( cache->families )
         FT_LruList_Reset( cache->families );
@@ -489,7 +701,12 @@
       ftc_cache_clear( cache );
 
       FT_FREE( cache->buckets );
+#ifdef FTC_CACHE_USE_LINEAR_HASHING
+      cache->mask  = 0;
+      cache->slack = 0;
+#else
       cache->size = 0;
+#endif
 
       if ( cache->families )
       {
@@ -508,7 +725,7 @@
                     FTC_Query   query,
                     FTC_Node   *anode )
   {
-    FT_Error    error;
+    FT_Error    error = 0;
     FT_LruNode  lru;
 
 
@@ -520,14 +737,69 @@
     query->hash   = 0;
     query->family = NULL;
 
+#ifdef OPT1
+    {
+      /* first of all, find the relevant family */
+      FT_LruList              list  = cache->families;
+      FT_LruNode              fam, *pfam;
+      FT_LruNode_CompareFunc  compare = list->clazz->node_compare;
+
+      pfam = &list->nodes;
+      for (;;)
+      {
+        fam = *pfam;
+        if ( fam == NULL )
+        {
+          error = FT_LruList_Lookup( list, query, &lru );
+          if ( error )
+            goto Exit;
+
+          goto Skip;
+        }
+
+        if ( compare( fam, query, list->data ) )
+          break;
+
+        pfam = &fam->next;
+      }
+
+      FT_ASSERT( fam != NULL );
+
+      /* move to top of list when needed */
+      if ( fam != list->nodes )
+      {
+        *pfam       = fam->next;
+        fam->next   = list->nodes;
+        list->nodes = fam;
+      }
+
+      lru = fam;
+
+    Skip:
+    }
+#else
     error = FT_LruList_Lookup( cache->families, query, &lru );
     if ( !error )
+#endif
     {
       FTC_Family  family = (FTC_Family) lru;
       FT_UFast    hash    = query->hash;
-      FTC_Node*   bucket  = cache->buckets + (hash % cache->size);
+      FTC_Node*   bucket;
 
 
+#ifdef FTC_CACHE_USE_LINEAR_HASHING
+      FT_UInt  index;
+
+      index = hash & cache->mask;
+      if ( index < cache->p )
+        index = hash & (cache->mask*2+1);
+
+      bucket  = cache->buckets + index;
+#else
+      bucket  = cache->buckets + (hash % cache->size);
+#endif
+
+
       if ( query->family     != family                        ||
            family->fam_index >= cache->manager->families.size )
       {
@@ -551,8 +823,14 @@
           if ( node == NULL )
             break;
 
+#ifdef OPT1
+          if ( node->hash == hash                            &&
+               (FT_UInt)node->fam_index == family->fam_index &&
+               compare( node, query, cache ) )
+#else
           if ( (FT_UInt)node->fam_index == family->fam_index &&
                compare( node, query, cache ) )
+#endif
           {
             /* move to head of bucket list */
             if ( pnode != bucket )
@@ -596,7 +874,18 @@
           goto Exit;
         }
 
+#ifdef FTC_CACHE_USE_LINEAR_HASHING
+        error = ftc_node_hash_link( node, cache );
+        if ( error )
+        {
+          clazz->node_done( node, cache );
+          FT_FREE( node );
+          goto Exit;
+        }
+#else
         ftc_node_hash_link( node, cache );
+#endif
+
         ftc_node_mru_link( node, cache->manager );
 
         cache->manager->cur_weight += clazz->node_weight( node, cache );
@@ -609,9 +898,11 @@
           node->ref_count--;
         }
 
+#ifndef FTC_CACHE_USE_LINEAR_HASHING
         /* try to resize the hash table if appropriate */
         if ( FTC_CACHE_RESIZE_TEST( cache ) )
           ftc_cache_resize( cache );
+#endif
 
         *anode = node;
       }
--- a/src/cache/ftcsbits.c
+++ b/src/cache/ftcsbits.c
@@ -63,8 +63,8 @@
     FTC_ImageDesc       desc;
 
   } FTC_SBitFamilyRec;
- 
-  
+
+
 #define FTC_SBIT_FAMILY( x )         ( (FTC_SBitFamily)( x ) )
 #define FTC_SBIT_FAMILY_MEMORY( x )  FTC_GLYPH_FAMILY_MEMORY( &( x )->cset )
 
@@ -462,6 +462,23 @@
 
   /* documentation is in ftcsbits.h */
 
+#ifdef FTC_CACHE_USE_INLINE
+
+#  define GEN_CACHE_FAMILY_COMPARE(f,q,c)  \
+             ftc_sbit_family_compare( (FTC_SBitFamily)(f), (FTC_SBitQuery)(q) )
+
+#  define GEN_CACHE_NODE_COMPARE(n,q,c)  \
+             ftc_sbit_node_compare( (FTC_SBitNode)(n), (FTC_SBitQuery)(q), c )
+
+#  define GEN_CACHE_LOOKUP          ftc_sbit_cache_lookup
+#  include "ftccache.i"
+
+#else  /* !FTC_CACHE_USE_INLINE */
+
+#  define ftc_sbit_cache_lookup  ftc_cache_lookup
+
+#endif /* !FTC_CACHE_USE_INLINE */
+
   FT_EXPORT_DEF( FT_Error )
   FTC_SBitCache_Lookup( FTC_SBitCache   cache,
                         FTC_ImageDesc*  desc,
@@ -486,9 +503,9 @@
     squery.gquery.gindex = gindex;
     squery.desc          = *desc;
 
-    error = ftc_cache_lookup( FTC_CACHE( cache ),
-                              FTC_QUERY( &squery ),
-                              (FTC_Node*)&node );
+    error = ftc_sbit_cache_lookup( FTC_CACHE( cache ),
+                                   FTC_QUERY( &squery ),
+                                   (FTC_Node*)&node );
     if ( !error )
     {
       *ansbit = node->sbits + ( gindex - FTC_GLYPH_NODE( node )->item_start );
@@ -520,11 +537,11 @@
                          FTC_SBit        *ansbit )
   {
     FTC_ImageDesc  desc0;
-    
 
+
     if ( !desc )
       return FTC_Err_Invalid_Argument;
-      
+
     desc0.font = desc->font;
     desc0.type = (FT_UInt32)desc->image_type;
 
--- a/src/type42/t42parse.c
+++ b/src/type42/t42parse.c
@@ -970,114 +970,3 @@
   }
 
 
-  FT_LOCAL_DEF( FT_Error )
-  T42_Open_Face( T42_Face  face )
-  {
-    T42_LoaderRec  loader;
-    T42_Parser     parser;
-    T1_Font        type1 = &face->type1;
-    FT_Memory      memory = face->root.memory;
-    FT_Error       error;
-
-    PSAux_Service  psaux  = (PSAux_Service)face->psaux;
-
-
-    t42_loader_init( &loader, face );
-
-    parser = &loader.parser;
-
-    if ( FT_ALLOC( face->ttf_data, 12 ) )
-      goto Exit;
-
-    error = t42_parser_init( parser,
-                             face->root.stream,
-                             memory,
-                             psaux);
-    if ( error )
-      goto Exit;
-
-    error = t42_parse_dict( face, &loader, parser->base_dict, parser->base_len );
-
-    if ( type1->font_type != 42 )
-    {
-      error = FT_Err_Unknown_File_Format;
-      goto Exit;
-    }
-
-    /* now, propagate the charstrings and glyphnames tables */
-    /* to the Type1 data                                    */
-    type1->num_glyphs = loader.num_glyphs;
-
-    if ( !loader.charstrings.init ) {
-      FT_ERROR(( "T42_Open_Face: no charstrings array in face!\n" ));
-      error = FT_Err_Invalid_File_Format;
-    }
-
-    loader.charstrings.init   = 0;
-    type1->charstrings_block = loader.charstrings.block;
-    type1->charstrings       = loader.charstrings.elements;
-    type1->charstrings_len   = loader.charstrings.lengths;
-
-    /* we copy the glyph names `block' and `elements' fields; */
-    /* the `lengths' field must be released later             */
-    type1->glyph_names_block   = loader.glyph_names.block;
-    type1->glyph_names         = (FT_String**)loader.glyph_names.elements;
-    loader.glyph_names.block    = 0;
-    loader.glyph_names.elements = 0;
-
-    /* we must now build type1.encoding when we have a custom array */
-    if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY )
-    {
-      FT_Int    charcode, idx, min_char, max_char;
-      FT_Byte*  char_name;
-      FT_Byte*  glyph_name;
-
-
-      /* OK, we do the following: for each element in the encoding   */
-      /* table, look up the index of the glyph having the same name  */
-      /* as defined in the CharStrings array.                        */
-      /* The index is then stored in type1.encoding.char_index, and  */
-      /* the name in type1.encoding.char_name                        */
-
-      min_char = +32000;
-      max_char = -32000;
-
-      charcode = 0;
-      for ( ; charcode < loader.encoding_table.max_elems; charcode++ )
-      {
-        type1->encoding.char_index[charcode] = 0;
-        type1->encoding.char_name [charcode] = (char *)".notdef";
-
-        char_name = loader.encoding_table.elements[charcode];
-        if ( char_name )
-          for ( idx = 0; idx < type1->num_glyphs; idx++ )
-          {
-            glyph_name = (FT_Byte*)type1->glyph_names[idx];
-            if ( ft_strcmp( (const char*)char_name,
-                            (const char*)glyph_name ) == 0 )
-            {
-              type1->encoding.char_index[charcode] = (FT_UShort)idx;
-              type1->encoding.char_name [charcode] = (char*)glyph_name;
-
-              /* Change min/max encoded char only if glyph name is */
-              /* not /.notdef                                      */
-              if ( ft_strcmp( (const char*)".notdef",
-                              (const char*)glyph_name ) != 0 )
-              {
-                if ( charcode < min_char ) min_char = charcode;
-                if ( charcode > max_char ) max_char = charcode;
-              }
-              break;
-            }
-          }
-      }
-      type1->encoding.code_first = min_char;
-      type1->encoding.code_last  = max_char;
-      type1->encoding.num_chars  = loader.num_chars;
-    }
-
-  Exit:
-    t42_loader_done( &loader );
-    return error;
-  }
-