ftcsbits.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  ftcsbits.c                                                             */
00004 /*                                                                         */
00005 /*    FreeType sbits manager (body).                                       */
00006 /*                                                                         */
00007 /*  Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2009 by             */
00008 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00009 /*                                                                         */
00010 /*  This file is part of the FreeType project, and may only be used,       */
00011 /*  modified, and distributed under the terms of the FreeType project      */
00012 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00013 /*  this file you indicate that you have read the license and              */
00014 /*  understand and accept it fully.                                        */
00015 /*                                                                         */
00016 /***************************************************************************/
00017 
00018 
00019 #include <ft2build.h>
00020 #include FT_CACHE_H
00021 #include "ftcsbits.h"
00022 #include FT_INTERNAL_OBJECTS_H
00023 #include FT_INTERNAL_DEBUG_H
00024 #include FT_ERRORS_H
00025 
00026 #include "ftccback.h"
00027 #include "ftcerror.h"
00028 
00029 #undef  FT_COMPONENT
00030 #define FT_COMPONENT  trace_cache
00031 
00032 
00033   /*************************************************************************/
00034   /*************************************************************************/
00035   /*****                                                               *****/
00036   /*****                     SBIT CACHE NODES                          *****/
00037   /*****                                                               *****/
00038   /*************************************************************************/
00039   /*************************************************************************/
00040 
00041 
00042   static FT_Error
00043   ftc_sbit_copy_bitmap( FTC_SBit    sbit,
00044                         FT_Bitmap*  bitmap,
00045                         FT_Memory   memory )
00046   {
00047     FT_Error  error;
00048     FT_Int    pitch = bitmap->pitch;
00049     FT_ULong  size;
00050 
00051 
00052     if ( pitch < 0 )
00053       pitch = -pitch;
00054 
00055     size = (FT_ULong)( pitch * bitmap->rows );
00056 
00057     if ( !FT_ALLOC( sbit->buffer, size ) )
00058       FT_MEM_COPY( sbit->buffer, bitmap->buffer, size );
00059 
00060     return error;
00061   }
00062 
00063 
00064   FT_LOCAL_DEF( void )
00065   ftc_snode_free( FTC_Node   ftcsnode,
00066                   FTC_Cache  cache )
00067   {
00068     FTC_SNode  snode  = (FTC_SNode)ftcsnode;
00069     FTC_SBit   sbit   = snode->sbits;
00070     FT_UInt    count  = snode->count;
00071     FT_Memory  memory = cache->memory;
00072 
00073 
00074     for ( ; count > 0; sbit++, count-- )
00075       FT_FREE( sbit->buffer );
00076 
00077     FTC_GNode_Done( FTC_GNODE( snode ), cache );
00078 
00079     FT_FREE( snode );
00080   }
00081 
00082 
00083   FT_LOCAL_DEF( void )
00084   FTC_SNode_Free( FTC_SNode  snode,
00085                   FTC_Cache  cache )
00086   {
00087     ftc_snode_free( FTC_NODE( snode ), cache );
00088   }
00089 
00090 
00091   /*
00092    *  This function tries to load a small bitmap within a given FTC_SNode.
00093    *  Note that it returns a non-zero error code _only_ in the case of
00094    *  out-of-memory condition.  For all other errors (e.g., corresponding
00095    *  to a bad font file), this function will mark the sbit as `unavailable'
00096    *  and return a value of 0.
00097    *
00098    *  You should also read the comment within the @ftc_snode_compare
00099    *  function below to see how out-of-memory is handled during a lookup.
00100    */
00101   static FT_Error
00102   ftc_snode_load( FTC_SNode    snode,
00103                   FTC_Manager  manager,
00104                   FT_UInt      gindex,
00105                   FT_ULong    *asize )
00106   {
00107     FT_Error          error;
00108     FTC_GNode         gnode  = FTC_GNODE( snode );
00109     FTC_Family        family = gnode->family;
00110     FT_Memory         memory = manager->memory;
00111     FT_Face           face;
00112     FTC_SBit          sbit;
00113     FTC_SFamilyClass  clazz;
00114 
00115 
00116     if ( (FT_UInt)(gindex - gnode->gindex) >= snode->count )
00117     {
00118       FT_ERROR(( "ftc_snode_load: invalid glyph index" ));
00119       return FTC_Err_Invalid_Argument;
00120     }
00121 
00122     sbit  = snode->sbits + ( gindex - gnode->gindex );
00123     clazz = (FTC_SFamilyClass)family->clazz;
00124 
00125     sbit->buffer = 0;
00126 
00127     error = clazz->family_load_glyph( family, gindex, manager, &face );
00128     if ( error )
00129       goto BadGlyph;
00130 
00131     {
00132       FT_Int        temp;
00133       FT_GlyphSlot  slot   = face->glyph;
00134       FT_Bitmap*    bitmap = &slot->bitmap;
00135       FT_Pos        xadvance, yadvance; /* FT_GlyphSlot->advance.{x|y} */
00136 
00137 
00138       if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
00139       {
00140         FT_TRACE0(( "ftc_snode_load:"
00141                     " glyph loaded didn't return a bitmap\n" ));
00142         goto BadGlyph;
00143       }
00144 
00145       /* Check that our values fit into 8-bit containers!       */
00146       /* If this is not the case, our bitmap is too large       */
00147       /* and we will leave it as `missing' with sbit.buffer = 0 */
00148 
00149 #define CHECK_CHAR( d )  ( temp = (FT_Char)d, temp == d )
00150 #define CHECK_BYTE( d )  ( temp = (FT_Byte)d, temp == d )
00151 
00152       /* horizontal advance in pixels */
00153       xadvance = ( slot->advance.x + 32 ) >> 6;
00154       yadvance = ( slot->advance.y + 32 ) >> 6;
00155 
00156       if ( !CHECK_BYTE( bitmap->rows  )     ||
00157            !CHECK_BYTE( bitmap->width )     ||
00158            !CHECK_CHAR( bitmap->pitch )     ||
00159            !CHECK_CHAR( slot->bitmap_left ) ||
00160            !CHECK_CHAR( slot->bitmap_top  ) ||
00161            !CHECK_CHAR( xadvance )          ||
00162            !CHECK_CHAR( yadvance )          )
00163         goto BadGlyph;
00164 
00165       sbit->width     = (FT_Byte)bitmap->width;
00166       sbit->height    = (FT_Byte)bitmap->rows;
00167       sbit->pitch     = (FT_Char)bitmap->pitch;
00168       sbit->left      = (FT_Char)slot->bitmap_left;
00169       sbit->top       = (FT_Char)slot->bitmap_top;
00170       sbit->xadvance  = (FT_Char)xadvance;
00171       sbit->yadvance  = (FT_Char)yadvance;
00172       sbit->format    = (FT_Byte)bitmap->pixel_mode;
00173       sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1);
00174 
00175       /* copy the bitmap into a new buffer -- ignore error */
00176       error = ftc_sbit_copy_bitmap( sbit, bitmap, memory );
00177 
00178       /* now, compute size */
00179       if ( asize )
00180         *asize = FT_ABS( sbit->pitch ) * sbit->height;
00181 
00182     } /* glyph loading successful */
00183 
00184     /* ignore the errors that might have occurred --   */
00185     /* we mark unloaded glyphs with `sbit.buffer == 0' */
00186     /* and `width == 255', `height == 0'               */
00187     /*                                                 */
00188     if ( error && error != FTC_Err_Out_Of_Memory )
00189     {
00190     BadGlyph:
00191       sbit->width  = 255;
00192       sbit->height = 0;
00193       sbit->buffer = NULL;
00194       error        = 0;
00195       if ( asize )
00196         *asize = 0;
00197     }
00198 
00199     return error;
00200   }
00201 
00202 
00203   FT_LOCAL_DEF( FT_Error )
00204   FTC_SNode_New( FTC_SNode  *psnode,
00205                  FTC_GQuery  gquery,
00206                  FTC_Cache   cache )
00207   {
00208     FT_Memory   memory = cache->memory;
00209     FT_Error    error;
00210     FTC_SNode   snode  = NULL;
00211     FT_UInt     gindex = gquery->gindex;
00212     FTC_Family  family = gquery->family;
00213 
00214     FTC_SFamilyClass  clazz = FTC_CACHE__SFAMILY_CLASS( cache );
00215     FT_UInt           total;
00216 
00217 
00218     total = clazz->family_get_count( family, cache->manager );
00219     if ( total == 0 || gindex >= total )
00220     {
00221       error = FT_Err_Invalid_Argument;
00222       goto Exit;
00223     }
00224 
00225     if ( !FT_NEW( snode ) )
00226     {
00227       FT_UInt  count, start;
00228 
00229 
00230       start = gindex - ( gindex % FTC_SBIT_ITEMS_PER_NODE );
00231       count = total - start;
00232       if ( count > FTC_SBIT_ITEMS_PER_NODE )
00233         count = FTC_SBIT_ITEMS_PER_NODE;
00234 
00235       FTC_GNode_Init( FTC_GNODE( snode ), start, family );
00236 
00237       snode->count = count;
00238 
00239       error = ftc_snode_load( snode,
00240                               cache->manager,
00241                               gindex,
00242                               NULL );
00243       if ( error )
00244       {
00245         FTC_SNode_Free( snode, cache );
00246         snode = NULL;
00247       }
00248     }
00249 
00250   Exit:
00251     *psnode = snode;
00252     return error;
00253   }
00254 
00255 
00256   FT_LOCAL_DEF( FT_Error )
00257   ftc_snode_new( FTC_Node   *ftcpsnode,
00258                  FT_Pointer  ftcgquery,
00259                  FTC_Cache   cache )
00260   {
00261     FTC_SNode  *psnode = (FTC_SNode*)ftcpsnode;
00262     FTC_GQuery  gquery = (FTC_GQuery)ftcgquery;
00263 
00264 
00265     return FTC_SNode_New( psnode, gquery, cache );
00266   }
00267 
00268 
00269   FT_LOCAL_DEF( FT_Offset )
00270   ftc_snode_weight( FTC_Node   ftcsnode,
00271                     FTC_Cache  cache )
00272   {
00273     FTC_SNode  snode = (FTC_SNode)ftcsnode;
00274     FT_UInt    count = snode->count;
00275     FTC_SBit   sbit  = snode->sbits;
00276     FT_Int     pitch;
00277     FT_Offset  size;
00278 
00279     FT_UNUSED( cache );
00280 
00281 
00282     FT_ASSERT( snode->count <= FTC_SBIT_ITEMS_PER_NODE );
00283 
00284     /* the node itself */
00285     size = sizeof ( *snode );
00286 
00287     for ( ; count > 0; count--, sbit++ )
00288     {
00289       if ( sbit->buffer )
00290       {
00291         pitch = sbit->pitch;
00292         if ( pitch < 0 )
00293           pitch = -pitch;
00294 
00295         /* add the size of a given glyph image */
00296         size += pitch * sbit->height;
00297       }
00298     }
00299 
00300     return size;
00301   }
00302 
00303 
00304 #if 0
00305 
00306   FT_LOCAL_DEF( FT_Offset )
00307   FTC_SNode_Weight( FTC_SNode  snode )
00308   {
00309     return ftc_snode_weight( FTC_NODE( snode ), NULL );
00310   }
00311 
00312 #endif /* 0 */
00313 
00314 
00315   FT_LOCAL_DEF( FT_Bool )
00316   ftc_snode_compare( FTC_Node    ftcsnode,
00317                      FT_Pointer  ftcgquery,
00318                      FTC_Cache   cache )
00319   {
00320     FTC_SNode   snode  = (FTC_SNode)ftcsnode;
00321     FTC_GQuery  gquery = (FTC_GQuery)ftcgquery;
00322     FTC_GNode   gnode  = FTC_GNODE( snode );
00323     FT_UInt     gindex = gquery->gindex;
00324     FT_Bool     result;
00325 
00326 
00327     result = FT_BOOL( gnode->family == gquery->family                    &&
00328                       (FT_UInt)( gindex - gnode->gindex ) < snode->count );
00329     if ( result )
00330     {
00331       /* check if we need to load the glyph bitmap now */
00332       FTC_SBit  sbit = snode->sbits + ( gindex - gnode->gindex );
00333 
00334 
00335       /*
00336        *  The following code illustrates what to do when you want to
00337        *  perform operations that may fail within a lookup function.
00338        *
00339        *  Here, we want to load a small bitmap on-demand; we thus
00340        *  need to call the `ftc_snode_load' function which may return
00341        *  a non-zero error code only when we are out of memory (OOM).
00342        *
00343        *  The correct thing to do is to use @FTC_CACHE_TRYLOOP and
00344        *  @FTC_CACHE_TRYLOOP_END in order to implement a retry loop
00345        *  that is capable of flushing the cache incrementally when
00346        *  an OOM errors occur.
00347        *
00348        *  However, we need to `lock' the node before this operation to
00349        *  prevent it from being flushed within the loop.
00350        *
00351        *  When we exit the loop, we unlock the node, then check the `error'
00352        *  variable.  If it is non-zero, this means that the cache was
00353        *  completely flushed and that no usable memory was found to load
00354        *  the bitmap.
00355        *
00356        *  We then prefer to return a value of 0 (i.e., NO MATCH).  This
00357        *  ensures that the caller will try to allocate a new node.
00358        *  This operation consequently _fail_ and the lookup function
00359        *  returns the appropriate OOM error code.
00360        *
00361        *  Note that `buffer == NULL && width == 255' is a hack used to
00362        *  tag `unavailable' bitmaps in the array.  We should never try
00363        *  to load these.
00364        *
00365        */
00366 
00367       if ( sbit->buffer == NULL && sbit->width != 255 )
00368       {
00369         FT_ULong  size;
00370         FT_Error  error;
00371 
00372 
00373         ftcsnode->ref_count++;  /* lock node to prevent flushing */
00374                                 /* in retry loop                 */
00375 
00376         FTC_CACHE_TRYLOOP( cache )
00377         {
00378           error = ftc_snode_load( snode, cache->manager, gindex, &size );
00379         }
00380         FTC_CACHE_TRYLOOP_END();
00381 
00382         ftcsnode->ref_count--;  /* unlock the node */
00383 
00384         if ( error )
00385           result = 0;
00386         else
00387           cache->manager->cur_weight += size;
00388       }
00389     }
00390 
00391     return result;
00392   }
00393 
00394 
00395   FT_LOCAL_DEF( FT_Bool )
00396   FTC_SNode_Compare( FTC_SNode   snode,
00397                      FTC_GQuery  gquery,
00398                      FTC_Cache   cache )
00399   {
00400     return ftc_snode_compare( FTC_NODE( snode ), gquery, cache );
00401   }
00402 
00403 
00404 /* END */

Generated on Tue Jul 5 14:13:45 2011 for ROOT_528-00b_version by  doxygen 1.5.1