misc/libfreetype/src/cache/ftcsbits.c
changeset 9372 915436ff64ab
parent 9371 f3840de881bd
child 9373 b769a8e38cbd
equal deleted inserted replaced
9371:f3840de881bd 9372:915436ff64ab
     1 /***************************************************************************/
       
     2 /*                                                                         */
       
     3 /*  ftcsbits.c                                                             */
       
     4 /*                                                                         */
       
     5 /*    FreeType sbits manager (body).                                       */
       
     6 /*                                                                         */
       
     7 /*  Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2009, 2010, 2011 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_CACHE_H
       
    21 #include "ftcsbits.h"
       
    22 #include FT_INTERNAL_OBJECTS_H
       
    23 #include FT_INTERNAL_DEBUG_H
       
    24 #include FT_ERRORS_H
       
    25 
       
    26 #include "ftccback.h"
       
    27 #include "ftcerror.h"
       
    28 
       
    29 #undef  FT_COMPONENT
       
    30 #define FT_COMPONENT  trace_cache
       
    31 
       
    32 
       
    33   /*************************************************************************/
       
    34   /*************************************************************************/
       
    35   /*****                                                               *****/
       
    36   /*****                     SBIT CACHE NODES                          *****/
       
    37   /*****                                                               *****/
       
    38   /*************************************************************************/
       
    39   /*************************************************************************/
       
    40 
       
    41 
       
    42   static FT_Error
       
    43   ftc_sbit_copy_bitmap( FTC_SBit    sbit,
       
    44                         FT_Bitmap*  bitmap,
       
    45                         FT_Memory   memory )
       
    46   {
       
    47     FT_Error  error;
       
    48     FT_Int    pitch = bitmap->pitch;
       
    49     FT_ULong  size;
       
    50 
       
    51 
       
    52     if ( pitch < 0 )
       
    53       pitch = -pitch;
       
    54 
       
    55     size = (FT_ULong)( pitch * bitmap->rows );
       
    56 
       
    57     if ( !FT_ALLOC( sbit->buffer, size ) )
       
    58       FT_MEM_COPY( sbit->buffer, bitmap->buffer, size );
       
    59 
       
    60     return error;
       
    61   }
       
    62 
       
    63 
       
    64   FT_LOCAL_DEF( void )
       
    65   ftc_snode_free( FTC_Node   ftcsnode,
       
    66                   FTC_Cache  cache )
       
    67   {
       
    68     FTC_SNode  snode  = (FTC_SNode)ftcsnode;
       
    69     FTC_SBit   sbit   = snode->sbits;
       
    70     FT_UInt    count  = snode->count;
       
    71     FT_Memory  memory = cache->memory;
       
    72 
       
    73 
       
    74     for ( ; count > 0; sbit++, count-- )
       
    75       FT_FREE( sbit->buffer );
       
    76 
       
    77     FTC_GNode_Done( FTC_GNODE( snode ), cache );
       
    78 
       
    79     FT_FREE( snode );
       
    80   }
       
    81 
       
    82 
       
    83   FT_LOCAL_DEF( void )
       
    84   FTC_SNode_Free( FTC_SNode  snode,
       
    85                   FTC_Cache  cache )
       
    86   {
       
    87     ftc_snode_free( FTC_NODE( snode ), cache );
       
    88   }
       
    89 
       
    90 
       
    91   /*
       
    92    *  This function tries to load a small bitmap within a given FTC_SNode.
       
    93    *  Note that it returns a non-zero error code _only_ in the case of
       
    94    *  out-of-memory condition.  For all other errors (e.g., corresponding
       
    95    *  to a bad font file), this function will mark the sbit as `unavailable'
       
    96    *  and return a value of 0.
       
    97    *
       
    98    *  You should also read the comment within the @ftc_snode_compare
       
    99    *  function below to see how out-of-memory is handled during a lookup.
       
   100    */
       
   101   static FT_Error
       
   102   ftc_snode_load( FTC_SNode    snode,
       
   103                   FTC_Manager  manager,
       
   104                   FT_UInt      gindex,
       
   105                   FT_ULong    *asize )
       
   106   {
       
   107     FT_Error          error;
       
   108     FTC_GNode         gnode  = FTC_GNODE( snode );
       
   109     FTC_Family        family = gnode->family;
       
   110     FT_Memory         memory = manager->memory;
       
   111     FT_Face           face;
       
   112     FTC_SBit          sbit;
       
   113     FTC_SFamilyClass  clazz;
       
   114 
       
   115 
       
   116     if ( (FT_UInt)(gindex - gnode->gindex) >= snode->count )
       
   117     {
       
   118       FT_ERROR(( "ftc_snode_load: invalid glyph index" ));
       
   119       return FTC_Err_Invalid_Argument;
       
   120     }
       
   121 
       
   122     sbit  = snode->sbits + ( gindex - gnode->gindex );
       
   123     clazz = (FTC_SFamilyClass)family->clazz;
       
   124 
       
   125     sbit->buffer = 0;
       
   126 
       
   127     error = clazz->family_load_glyph( family, gindex, manager, &face );
       
   128     if ( error )
       
   129       goto BadGlyph;
       
   130 
       
   131     {
       
   132       FT_Int        temp;
       
   133       FT_GlyphSlot  slot   = face->glyph;
       
   134       FT_Bitmap*    bitmap = &slot->bitmap;
       
   135       FT_Pos        xadvance, yadvance; /* FT_GlyphSlot->advance.{x|y} */
       
   136 
       
   137 
       
   138       if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
       
   139       {
       
   140         FT_TRACE0(( "ftc_snode_load:"
       
   141                     " glyph loaded didn't return a bitmap\n" ));
       
   142         goto BadGlyph;
       
   143       }
       
   144 
       
   145       /* Check that our values fit into 8-bit containers!       */
       
   146       /* If this is not the case, our bitmap is too large       */
       
   147       /* and we will leave it as `missing' with sbit.buffer = 0 */
       
   148 
       
   149 #define CHECK_CHAR( d )  ( temp = (FT_Char)d, temp == d )
       
   150 #define CHECK_BYTE( d )  ( temp = (FT_Byte)d, temp == d )
       
   151 
       
   152       /* horizontal advance in pixels */
       
   153       xadvance = ( slot->advance.x + 32 ) >> 6;
       
   154       yadvance = ( slot->advance.y + 32 ) >> 6;
       
   155 
       
   156       if ( !CHECK_BYTE( bitmap->rows  )     ||
       
   157            !CHECK_BYTE( bitmap->width )     ||
       
   158            !CHECK_CHAR( bitmap->pitch )     ||
       
   159            !CHECK_CHAR( slot->bitmap_left ) ||
       
   160            !CHECK_CHAR( slot->bitmap_top  ) ||
       
   161            !CHECK_CHAR( xadvance )          ||
       
   162            !CHECK_CHAR( yadvance )          )
       
   163       {
       
   164         FT_TRACE2(( "ftc_snode_load:"
       
   165                     " glyph too large for small bitmap cache\n"));
       
   166         goto BadGlyph;
       
   167       }
       
   168 
       
   169       sbit->width     = (FT_Byte)bitmap->width;
       
   170       sbit->height    = (FT_Byte)bitmap->rows;
       
   171       sbit->pitch     = (FT_Char)bitmap->pitch;
       
   172       sbit->left      = (FT_Char)slot->bitmap_left;
       
   173       sbit->top       = (FT_Char)slot->bitmap_top;
       
   174       sbit->xadvance  = (FT_Char)xadvance;
       
   175       sbit->yadvance  = (FT_Char)yadvance;
       
   176       sbit->format    = (FT_Byte)bitmap->pixel_mode;
       
   177       sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1);
       
   178 
       
   179       /* copy the bitmap into a new buffer -- ignore error */
       
   180       error = ftc_sbit_copy_bitmap( sbit, bitmap, memory );
       
   181 
       
   182       /* now, compute size */
       
   183       if ( asize )
       
   184         *asize = FT_ABS( sbit->pitch ) * sbit->height;
       
   185 
       
   186     } /* glyph loading successful */
       
   187 
       
   188     /* ignore the errors that might have occurred --   */
       
   189     /* we mark unloaded glyphs with `sbit.buffer == 0' */
       
   190     /* and `width == 255', `height == 0'               */
       
   191     /*                                                 */
       
   192     if ( error && error != FTC_Err_Out_Of_Memory )
       
   193     {
       
   194     BadGlyph:
       
   195       sbit->width  = 255;
       
   196       sbit->height = 0;
       
   197       sbit->buffer = NULL;
       
   198       error        = FTC_Err_Ok;
       
   199       if ( asize )
       
   200         *asize = 0;
       
   201     }
       
   202 
       
   203     return error;
       
   204   }
       
   205 
       
   206 
       
   207   FT_LOCAL_DEF( FT_Error )
       
   208   FTC_SNode_New( FTC_SNode  *psnode,
       
   209                  FTC_GQuery  gquery,
       
   210                  FTC_Cache   cache )
       
   211   {
       
   212     FT_Memory   memory = cache->memory;
       
   213     FT_Error    error;
       
   214     FTC_SNode   snode  = NULL;
       
   215     FT_UInt     gindex = gquery->gindex;
       
   216     FTC_Family  family = gquery->family;
       
   217 
       
   218     FTC_SFamilyClass  clazz = FTC_CACHE__SFAMILY_CLASS( cache );
       
   219     FT_UInt           total;
       
   220     FT_UInt           node_count;
       
   221 
       
   222 
       
   223     total = clazz->family_get_count( family, cache->manager );
       
   224     if ( total == 0 || gindex >= total )
       
   225     {
       
   226       error = FTC_Err_Invalid_Argument;
       
   227       goto Exit;
       
   228     }
       
   229 
       
   230     if ( !FT_NEW( snode ) )
       
   231     {
       
   232       FT_UInt  count, start;
       
   233 
       
   234 
       
   235       start = gindex - ( gindex % FTC_SBIT_ITEMS_PER_NODE );
       
   236       count = total - start;
       
   237       if ( count > FTC_SBIT_ITEMS_PER_NODE )
       
   238         count = FTC_SBIT_ITEMS_PER_NODE;
       
   239 
       
   240       FTC_GNode_Init( FTC_GNODE( snode ), start, family );
       
   241 
       
   242       snode->count = count;
       
   243       for ( node_count = 0; node_count < count; node_count++ )
       
   244       {
       
   245         snode->sbits[node_count].width = 255;
       
   246       }
       
   247 
       
   248       error = ftc_snode_load( snode,
       
   249                               cache->manager,
       
   250                               gindex,
       
   251                               NULL );
       
   252       if ( error )
       
   253       {
       
   254         FTC_SNode_Free( snode, cache );
       
   255         snode = NULL;
       
   256       }
       
   257     }
       
   258 
       
   259   Exit:
       
   260     *psnode = snode;
       
   261     return error;
       
   262   }
       
   263 
       
   264 
       
   265   FT_LOCAL_DEF( FT_Error )
       
   266   ftc_snode_new( FTC_Node   *ftcpsnode,
       
   267                  FT_Pointer  ftcgquery,
       
   268                  FTC_Cache   cache )
       
   269   {
       
   270     FTC_SNode  *psnode = (FTC_SNode*)ftcpsnode;
       
   271     FTC_GQuery  gquery = (FTC_GQuery)ftcgquery;
       
   272 
       
   273 
       
   274     return FTC_SNode_New( psnode, gquery, cache );
       
   275   }
       
   276 
       
   277 
       
   278   FT_LOCAL_DEF( FT_Offset )
       
   279   ftc_snode_weight( FTC_Node   ftcsnode,
       
   280                     FTC_Cache  cache )
       
   281   {
       
   282     FTC_SNode  snode = (FTC_SNode)ftcsnode;
       
   283     FT_UInt    count = snode->count;
       
   284     FTC_SBit   sbit  = snode->sbits;
       
   285     FT_Int     pitch;
       
   286     FT_Offset  size;
       
   287 
       
   288     FT_UNUSED( cache );
       
   289 
       
   290 
       
   291     FT_ASSERT( snode->count <= FTC_SBIT_ITEMS_PER_NODE );
       
   292 
       
   293     /* the node itself */
       
   294     size = sizeof ( *snode );
       
   295 
       
   296     for ( ; count > 0; count--, sbit++ )
       
   297     {
       
   298       if ( sbit->buffer )
       
   299       {
       
   300         pitch = sbit->pitch;
       
   301         if ( pitch < 0 )
       
   302           pitch = -pitch;
       
   303 
       
   304         /* add the size of a given glyph image */
       
   305         size += pitch * sbit->height;
       
   306       }
       
   307     }
       
   308 
       
   309     return size;
       
   310   }
       
   311 
       
   312 
       
   313 #if 0
       
   314 
       
   315   FT_LOCAL_DEF( FT_Offset )
       
   316   FTC_SNode_Weight( FTC_SNode  snode )
       
   317   {
       
   318     return ftc_snode_weight( FTC_NODE( snode ), NULL );
       
   319   }
       
   320 
       
   321 #endif /* 0 */
       
   322 
       
   323 
       
   324   FT_LOCAL_DEF( FT_Bool )
       
   325   ftc_snode_compare( FTC_Node    ftcsnode,
       
   326                      FT_Pointer  ftcgquery,
       
   327                      FTC_Cache   cache,
       
   328                      FT_Bool*    list_changed )
       
   329   {
       
   330     FTC_SNode   snode  = (FTC_SNode)ftcsnode;
       
   331     FTC_GQuery  gquery = (FTC_GQuery)ftcgquery;
       
   332     FTC_GNode   gnode  = FTC_GNODE( snode );
       
   333     FT_UInt     gindex = gquery->gindex;
       
   334     FT_Bool     result;
       
   335 
       
   336 
       
   337     if (list_changed)
       
   338       *list_changed = FALSE;
       
   339     result = FT_BOOL( gnode->family == gquery->family                    &&
       
   340                       (FT_UInt)( gindex - gnode->gindex ) < snode->count );
       
   341     if ( result )
       
   342     {
       
   343       /* check if we need to load the glyph bitmap now */
       
   344       FTC_SBit  sbit = snode->sbits + ( gindex - gnode->gindex );
       
   345 
       
   346 
       
   347       /*
       
   348        *  The following code illustrates what to do when you want to
       
   349        *  perform operations that may fail within a lookup function.
       
   350        *
       
   351        *  Here, we want to load a small bitmap on-demand; we thus
       
   352        *  need to call the `ftc_snode_load' function which may return
       
   353        *  a non-zero error code only when we are out of memory (OOM).
       
   354        *
       
   355        *  The correct thing to do is to use @FTC_CACHE_TRYLOOP and
       
   356        *  @FTC_CACHE_TRYLOOP_END in order to implement a retry loop
       
   357        *  that is capable of flushing the cache incrementally when
       
   358        *  an OOM errors occur.
       
   359        *
       
   360        *  However, we need to `lock' the node before this operation to
       
   361        *  prevent it from being flushed within the loop.
       
   362        *
       
   363        *  When we exit the loop, we unlock the node, then check the `error'
       
   364        *  variable.  If it is non-zero, this means that the cache was
       
   365        *  completely flushed and that no usable memory was found to load
       
   366        *  the bitmap.
       
   367        *
       
   368        *  We then prefer to return a value of 0 (i.e., NO MATCH).  This
       
   369        *  ensures that the caller will try to allocate a new node.
       
   370        *  This operation consequently _fail_ and the lookup function
       
   371        *  returns the appropriate OOM error code.
       
   372        *
       
   373        *  Note that `buffer == NULL && width == 255' is a hack used to
       
   374        *  tag `unavailable' bitmaps in the array.  We should never try
       
   375        *  to load these.
       
   376        *
       
   377        */
       
   378 
       
   379       if ( sbit->buffer == NULL && sbit->width == 255 )
       
   380       {
       
   381         FT_ULong  size;
       
   382         FT_Error  error;
       
   383 
       
   384 
       
   385         ftcsnode->ref_count++;  /* lock node to prevent flushing */
       
   386                                 /* in retry loop                 */
       
   387 
       
   388         FTC_CACHE_TRYLOOP( cache )
       
   389         {
       
   390           error = ftc_snode_load( snode, cache->manager, gindex, &size );
       
   391         }
       
   392         FTC_CACHE_TRYLOOP_END( list_changed );
       
   393 
       
   394         ftcsnode->ref_count--;  /* unlock the node */
       
   395 
       
   396         if ( error )
       
   397           result = 0;
       
   398         else
       
   399           cache->manager->cur_weight += size;
       
   400       }
       
   401     }
       
   402 
       
   403     return result;
       
   404   }
       
   405 
       
   406 
       
   407 #ifdef FTC_INLINE
       
   408 
       
   409   FT_LOCAL_DEF( FT_Bool )
       
   410   FTC_SNode_Compare( FTC_SNode   snode,
       
   411                      FTC_GQuery  gquery,
       
   412                      FTC_Cache   cache,
       
   413                      FT_Bool*    list_changed )
       
   414   {
       
   415     return ftc_snode_compare( FTC_NODE( snode ), gquery,
       
   416                               cache, list_changed );
       
   417   }
       
   418 
       
   419 #endif
       
   420 
       
   421 /* END */