/***************************************************************************/ /* */ /* 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 */