| /***************************************************************************/ |
| /* */ |
| /* ftcsbits.c */ |
| /* */ |
| /* FreeType sbits manager (body). */ |
| /* */ |
| /* Copyright 2000-2001, 2002, 2003, 2004, 2005 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 "ftcint.h" |
| #include FT_CACHE_INTERNAL_SBITS_H |
| #include FT_INTERNAL_OBJECTS_H |
| #include FT_INTERNAL_DEBUG_H |
| #include FT_ERRORS_H |
| |
| #include "ftcerror.h" |
| |
| |
| /*************************************************************************/ |
| /*************************************************************************/ |
| /***** *****/ |
| /***** SBIT CACHE NODES *****/ |
| /***** *****/ |
| /*************************************************************************/ |
| /*************************************************************************/ |
| |
| |
| static FT_Error |
| ftc_sbit_copy_bitmap( FTC_SBit sbit, |
| FT_Bitmap* bitmap, |
| FT_Memory memory ) |
| { |
| FT_Error error; |
| FT_Int pitch = bitmap->pitch; |
| FT_ULong size; |
| |
| |
| if ( pitch < 0 ) |
| pitch = -pitch; |
| |
| size = (FT_ULong)( pitch * bitmap->rows ); |
| |
| if ( !FT_ALLOC( sbit->buffer, size ) ) |
| FT_MEM_COPY( sbit->buffer, bitmap->buffer, size ); |
| |
| return error; |
| } |
| |
| |
| FT_EXPORT_DEF( void ) |
| FTC_SNode_Free( FTC_SNode snode, |
| FTC_GCache cache ) |
| { |
| FTC_SBit sbit = snode->sbits; |
| FT_UInt count = snode->count; |
| FT_Memory memory = FTC_CACHE__MEMORY(cache); |
| |
| |
| for ( ; count > 0; sbit++, count-- ) |
| FT_FREE( sbit->buffer ); |
| |
| FTC_GNode_Done( FTC_GNODE( snode ) ); |
| |
| FT_FREE( snode ); |
| } |
| |
| |
| /* |
| * This function tries to load a small bitmap within a given FTC_SNode. |
| * Note that it returns a non-zero error code _only_ in the case of |
| * out-of-memory condition. For all other errors (e.g., corresponding |
| * to a bad font file), this function will mark the sbit as `unavailable' |
| * and return a value of 0. |
| * |
| * You should also read the comment within the @ftc_snode_equal |
| * function below to see how out-of-memory is handled during a lookup. |
| */ |
| static FT_Error |
| ftc_snode_load( FTC_SNode snode, |
| FTC_Manager manager, |
| FT_UInt gindex, |
| FT_ULong *asize ) |
| { |
| FT_Error error; |
| FTC_GNode gnode = FTC_GNODE( snode ); |
| FTC_Family family = gnode->family; |
| FT_Memory memory = manager->memory; |
| FT_Face face; |
| FTC_SBit sbit; |
| FTC_SCacheClass clazz; |
| |
| |
| if ( (FT_UInt)(gindex - gnode->gindex) >= snode->count ) |
| { |
| FT_ERROR(( "ftc_snode_load: invalid glyph index" )); |
| return FTC_Err_Invalid_Argument; |
| } |
| |
| sbit = snode->sbits + ( gindex - gnode->gindex ); |
| clazz = FTC_SCACHE__CLASS(FTC_FAMILY__CACHE(family)); |
| |
| sbit->buffer = 0; |
| |
| error = clazz->fam_load_glyph( family, gindex, manager, &face ); |
| if ( error ) |
| goto BadGlyph; |
| |
| { |
| FT_Int temp; |
| FT_GlyphSlot slot = face->glyph; |
| FT_Bitmap* bitmap = &slot->bitmap; |
| FT_Int xadvance, yadvance; |
| |
| |
| if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) |
| { |
| FT_ERROR(( "%s: glyph loaded didn't return a bitmap!\n", |
| "ftc_snode_load" )); |
| goto BadGlyph; |
| } |
| |
| /* Check that our values fit into 8-bit containers! */ |
| /* If this is not the case, our bitmap is too large */ |
| /* and we will leave it as `missing' with sbit.buffer = 0 */ |
| |
| #define CHECK_CHAR( d ) ( temp = (FT_Char)d, temp == d ) |
| #define CHECK_BYTE( d ) ( temp = (FT_Byte)d, temp == d ) |
| |
| /* horizontal advance in pixels */ |
| xadvance = ( slot->advance.x + 32 ) >> 6; |
| yadvance = ( slot->advance.y + 32 ) >> 6; |
| |
| if ( !CHECK_BYTE( bitmap->rows ) || |
| !CHECK_BYTE( bitmap->width ) || |
| !CHECK_CHAR( bitmap->pitch ) || |
| !CHECK_CHAR( slot->bitmap_left ) || |
| !CHECK_CHAR( slot->bitmap_top ) || |
| !CHECK_CHAR( xadvance ) || |
| !CHECK_CHAR( yadvance ) ) |
| goto BadGlyph; |
| |
| sbit->width = (FT_Byte)bitmap->width; |
| sbit->height = (FT_Byte)bitmap->rows; |
| sbit->pitch = (FT_Char)bitmap->pitch; |
| sbit->left = (FT_Char)slot->bitmap_left; |
| sbit->top = (FT_Char)slot->bitmap_top; |
| sbit->xadvance = (FT_Char)xadvance; |
| sbit->yadvance = (FT_Char)yadvance; |
| sbit->format = (FT_Byte)bitmap->pixel_mode; |
| sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1); |
| |
| /* copy the bitmap into a new buffer -- ignore error */ |
| error = ftc_sbit_copy_bitmap( sbit, bitmap, memory ); |
| |
| /* now, compute size */ |
| if ( asize ) |
| *asize = FT_ABS( sbit->pitch ) * sbit->height; |
| |
| } /* glyph loading successful */ |
| |
| /* ignore the errors that might have occurred -- */ |
| /* we mark unloaded glyphs with `sbit.buffer == 0' */ |
| /* and `width == 255', `height == 0' */ |
| /* */ |
| if ( error && error != FTC_Err_Out_Of_Memory ) |
| { |
| BadGlyph: |
| sbit->width = 255; |
| sbit->height = 0; |
| sbit->buffer = NULL; |
| error = 0; |
| if ( asize ) |
| *asize = 0; |
| } |
| |
| return error; |
| } |
| |
| |
| FT_EXPORT_DEF( FT_Error ) |
| FTC_SNode_New( FTC_SNode *psnode, |
| FTC_GNode gquery, |
| FTC_GCache cache ) |
| { |
| FT_Memory memory = FTC_CACHE__MEMORY(cache); |
| FT_Error error; |
| FTC_SNode snode = NULL; |
| FT_UInt gindex = gquery->gindex; |
| FTC_Family family = gquery->family; |
| |
| FTC_SCacheClass clazz = FTC_SCACHE__CLASS(cache); |
| FT_UInt total; |
| |
| |
| total = clazz->fam_get_count( family, FTC_CACHE__MANAGER(cache) ); |
| if ( total == 0 || gindex >= total ) |
| { |
| error = FT_Err_Invalid_Argument; |
| goto Exit; |
| } |
| |
| if ( !FT_NEW( snode ) ) |
| { |
| FT_UInt count, start; |
| |
| |
| start = gindex - ( gindex % FTC_SBIT_ITEMS_PER_NODE ); |
| count = total - start; |
| if ( count > FTC_SBIT_ITEMS_PER_NODE ) |
| count = FTC_SBIT_ITEMS_PER_NODE; |
| |
| FTC_GNode_Init( FTC_GNODE( snode ), start, family ); |
| |
| snode->count = count; |
| |
| error = ftc_snode_load( snode, |
| FTC_CACHE__MANAGER(cache), |
| gindex, |
| NULL ); |
| if ( error ) |
| { |
| FTC_SNode_Free( snode, cache ); |
| snode = NULL; |
| } |
| } |
| |
| Exit: |
| *psnode = snode; |
| return error; |
| } |
| |
| |
| |
| |
| FT_EXPORT_DEF( FT_ULong ) |
| FTC_SNode_Weight( FTC_SNode snode ) |
| { |
| FT_UInt count = snode->count; |
| FTC_SBit sbit = snode->sbits; |
| FT_Int pitch; |
| FT_ULong size; |
| |
| FT_ASSERT( snode->count <= FTC_SBIT_ITEMS_PER_NODE ); |
| |
| /* the node itself */ |
| size = sizeof ( *snode ); |
| |
| for ( ; count > 0; count--, sbit++ ) |
| { |
| if ( sbit->buffer ) |
| { |
| pitch = sbit->pitch; |
| if ( pitch < 0 ) |
| pitch = -pitch; |
| |
| /* add the size of a given glyph image */ |
| size += pitch * sbit->height; |
| } |
| } |
| |
| return size; |
| } |
| |
| |
| FT_EXPORT_DEF( FT_Bool ) |
| FTC_SNode_Equal( FTC_SNode snode, |
| FTC_GNode gquery, |
| FTC_Cache cache ) |
| { |
| FTC_GNode gnode = FTC_GNODE( snode ); |
| FT_UInt gindex = gquery->gindex; |
| FT_Bool result; |
| |
| |
| result = FT_BOOL( gnode->family == gquery->family && |
| (FT_UInt)( gindex - gnode->gindex ) < snode->count ); |
| if ( result ) |
| { |
| /* check if we need to load the glyph bitmap now */ |
| FTC_SBit sbit = snode->sbits + ( gindex - gnode->gindex ); |
| |
| |
| if ( sbit->buffer == NULL && sbit->width != 255 ) |
| { |
| FT_ULong size; |
| FT_Error error; |
| |
| |
| FTC_NODE_REF(snode); /* lock node to prevent flushing */ |
| /* in retry loop */ |
| |
| FTC_RETR_LOOP( cache->manager ) |
| { |
| error = ftc_snode_load( snode, cache->manager, gindex, &size ); |
| } |
| FTC_RETRY_END( error ); |
| |
| FTC_NODE(snode)->ref_count--; /* unlock the node */ |
| |
| if ( error ) |
| result = 0; |
| else |
| cache->manager->cur_weight += size; |
| } |
| } |
| |
| return result; |
| } |
| |
| |
| |
| |
| /* END */ |