ftc_inode_free( FTC_Node ftcinode, FTC_Cache cache ) { FTC_INode inode = (FTC_INode)ftcinode; FT_Memory memory = cache->memory; if ( inode->glyph ) { FT_Done_Glyph( inode->glyph ); inode->glyph = NULL; } FTC_GNode_Done( FTC_GNODE( inode ), cache ); FT_FREE( inode ); }
ftc_snode_free( FTC_Node ftcsnode, FTC_Cache cache ) { FTC_SNode snode = (FTC_SNode)ftcsnode; FTC_SBit sbit = snode->sbits; FT_UInt count = snode->count; FT_Memory memory = cache->memory; for ( ; count > 0; sbit++, count-- ) FT_FREE( sbit->buffer ); FTC_GNode_Done( FTC_GNODE( snode ), cache ); FT_FREE( snode ); }
ftc_snode_compare( FTC_Node ftcsnode, FT_Pointer ftcgquery, FTC_Cache cache, FT_Bool* list_changed ) { FTC_SNode snode = (FTC_SNode)ftcsnode; FTC_GQuery gquery = (FTC_GQuery)ftcgquery; FTC_GNode gnode = FTC_GNODE( snode ); FT_UInt gindex = gquery->gindex; FT_Bool result; if (list_changed) *list_changed = FALSE; 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 ); /* * The following code illustrates what to do when you want to * perform operations that may fail within a lookup function. * * Here, we want to load a small bitmap on-demand; we thus * need to call the `ftc_snode_load' function which may return * a non-zero error code only when we are out of memory (OOM). * * The correct thing to do is to use @FTC_CACHE_TRYLOOP and * @FTC_CACHE_TRYLOOP_END in order to implement a retry loop * that is capable of flushing the cache incrementally when * an OOM errors occur. * * However, we need to `lock' the node before this operation to * prevent it from being flushed within the loop. * * When we exit the loop, we unlock the node, then check the `error' * variable. If it is non-zero, this means that the cache was * completely flushed and that no usable memory was found to load * the bitmap. * * We then prefer to return a value of 0 (i.e., NO MATCH). This * ensures that the caller will try to allocate a new node. * This operation consequently _fail_ and the lookup function * returns the appropriate OOM error code. * * Note that `buffer == NULL && width == 255' is a hack used to * tag `unavailable' bitmaps in the array. We should never try * to load these. * */ if ( sbit->buffer == NULL && sbit->width == 255 ) { FT_ULong size; FT_Error error; ftcsnode->ref_count++; /* lock node to prevent flushing */ /* in retry loop */ FTC_CACHE_TRYLOOP( cache ) { error = ftc_snode_load( snode, cache->manager, gindex, &size ); } FTC_CACHE_TRYLOOP_END( list_changed ); ftcsnode->ref_count--; /* unlock the node */ if ( error ) result = 0; else cache->manager->cur_weight += size; } }
/* * 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_compare * 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_SFamilyClass clazz; if ( (FT_UInt)(gindex - gnode->gindex) >= snode->count ) { FT_ERROR(( "ftc_snode_load: invalid glyph index" )); return FT_THROW( Invalid_Argument ); } sbit = snode->sbits + ( gindex - gnode->gindex ); clazz = (FTC_SFamilyClass)family->clazz; sbit->buffer = 0; error = clazz->family_load_glyph( family, gindex, manager, &face ); if ( error ) goto BadGlyph; { FT_Int temp; FT_GlyphSlot slot = face->glyph; FT_Bitmap* bitmap = &slot->bitmap; FT_Pos xadvance, yadvance; /* FT_GlyphSlot->advance.{x|y} */ if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) { FT_TRACE0(( "ftc_snode_load:" " glyph loaded didn't return a bitmap\n" )); goto BadGlyph; } /* Check whether 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, (FT_Int) temp == (FT_Int) d ) #define CHECK_BYTE( d ) ( temp = (FT_Byte)d, (FT_UInt)temp == (FT_UInt)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 ) ) { FT_TRACE2(( "ftc_snode_load:" " glyph too large for small bitmap cache\n")); 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_ULong)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 && FT_ERR_NEQ( error, Out_Of_Memory ) ) { BadGlyph: sbit->width = 255; sbit->height = 0; sbit->buffer = NULL; error = FT_Err_Ok; if ( asize ) *asize = 0; } return error; }
FTC_SBitCache_Lookup( FTC_SBitCache cache, FTC_ImageType type, FT_UInt gindex, FTC_SBit *ansbit, FTC_Node *anode ) { FT_Error error; FTC_BasicQueryRec query; FTC_Node node = 0; /* make compiler happy */ FT_UInt32 hash; if ( anode ) *anode = NULL; /* other argument checks delayed to FTC_Cache_Lookup */ if ( !ansbit ) return FTC_Err_Invalid_Argument; *ansbit = NULL; #if defined( FT_CONFIG_OPTION_OLD_INTERNALS ) && ( FT_INT_MAX > 0xFFFFU ) /* This one is a major hack used to detect whether we are passed a * regular FTC_ImageType handle, or a legacy FTC_OldImageDesc one. */ if ( (FT_ULong)type->width >= 0x10000L ) { FTC_OldImageDesc desc = (FTC_OldImageDesc)type; query.attrs.scaler.face_id = desc->font.face_id; query.attrs.scaler.width = desc->font.pix_width; query.attrs.scaler.height = desc->font.pix_height; query.attrs.load_flags = desc->flags; } else #endif /* FT_CONFIG_OPTION_OLD_INTERNALS */ { if ( (FT_ULong)(type->flags - FT_INT_MIN) > FT_UINT_MAX ) { FT_TRACE1(( "FTC_ImageCache_Lookup: higher bits in load_flags" )); FT_TRACE1(( "0x%x are dropped\n", (type->flags & ~((FT_ULong)FT_UINT_MAX)) )); } query.attrs.scaler.face_id = type->face_id; query.attrs.scaler.width = type->width; query.attrs.scaler.height = type->height; query.attrs.load_flags = (FT_UInt)type->flags; } query.attrs.scaler.pixel = 1; query.attrs.scaler.x_res = 0; /* make compilers happy */ query.attrs.scaler.y_res = 0; /* beware, the hash must be the same for all glyph ranges! */ hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex / FTC_SBIT_ITEMS_PER_NODE; #if 1 /* inlining is about 50% faster! */ FTC_GCACHE_LOOKUP_CMP( cache, ftc_basic_family_compare, FTC_SNode_Compare, hash, gindex, &query, node, error ); #else error = FTC_GCache_Lookup( FTC_GCACHE( cache ), hash, gindex, FTC_GQUERY( &query ), &node ); #endif if ( error ) goto Exit; *ansbit = FTC_SNODE( node )->sbits + ( gindex - FTC_GNODE( node )->gindex ); if ( anode ) { *anode = node; node->ref_count++; } Exit: return error; }
FTC_SBitCache_Lookup( FTC_SBitCache cache, FTC_ImageType type, FT_UInt gindex, FTC_SBit *ansbit, FTC_Node *anode ) { FT_Error error; FTC_BasicQueryRec query; FTC_SNode node = 0; /* make compiler happy */ FT_UInt32 hash; if ( anode ) *anode = NULL; /* other argument checks delayed to FTC_Cache_Lookup */ if ( !ansbit ) return FTC_Err_Invalid_Argument; *ansbit = NULL; query.attrs.scaler.face_id = type->face_id; query.attrs.scaler.width = type->width; query.attrs.scaler.height = type->height; query.attrs.scaler.pixel = 1; query.attrs.load_flags = type->flags; query.attrs.scaler.x_res = 0; /* make compilers happy */ query.attrs.scaler.y_res = 0; /* beware, the hash must be the same for all glyph ranges! */ hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex / FTC_SBIT_ITEMS_PER_NODE; #if 1 /* inlining is about 50% faster! */ FTC_GCACHE_LOOKUP_CMP( cache, ftc_basic_family_compare, FTC_SNode_Compare, hash, gindex, &query, node, error ); #else error = FTC_GCache_Lookup( FTC_GCACHE( cache ), hash, gindex, FTC_GQUERY( &query ), (FTC_Node*)&node ); #endif if ( error ) goto Exit; *ansbit = node->sbits + ( gindex - FTC_GNODE( node )->gindex ); if ( anode ) { *anode = FTC_NODE( node ); FTC_NODE( node )->ref_count++; } Exit: return error; }
FTC_SBitCache_LookupScaler( FTC_SBitCache cache, FTC_Scaler scaler, FT_ULong load_flags, FT_UInt gindex, FTC_SBit *ansbit, FTC_Node *anode ) { FT_Error error; FTC_BasicQueryRec query; FTC_Node node = 0; /* make compiler happy */ FT_Offset hash; if ( anode ) *anode = NULL; /* other argument checks delayed to `FTC_Cache_Lookup' */ if ( !ansbit || !scaler ) return FT_THROW( Invalid_Argument ); *ansbit = NULL; /* * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt', * but public `FT_Face->face_flags' is of type `FT_Long'. * * On long > int systems, higher bits of load_flags cannot be handled. */ #if FT_ULONG_MAX > FT_UINT_MAX if ( load_flags > FT_UINT_MAX ) FT_TRACE1(( "FTC_ImageCache_LookupScaler:" " higher bits in load_flags 0x%x are dropped\n", load_flags & ~((FT_ULong)FT_UINT_MAX) )); #endif query.attrs.scaler = scaler[0]; query.attrs.load_flags = (FT_UInt)load_flags; /* beware, the hash must be the same for all glyph ranges! */ hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex / FTC_SBIT_ITEMS_PER_NODE; FTC_GCACHE_LOOKUP_CMP( cache, ftc_basic_family_compare, FTC_SNode_Compare, hash, gindex, &query, node, error ); if ( error ) goto Exit; *ansbit = FTC_SNODE( node )->sbits + ( gindex - FTC_GNODE( node )->gindex ); if ( anode ) { *anode = node; node->ref_count++; } Exit: return error; }
FTC_SBitCache_Lookup( FTC_SBitCache cache, FTC_ImageType type, FT_UInt gindex, FTC_SBit *ansbit, FTC_Node *anode ) { FT_Error error; FTC_BasicQueryRec query; FTC_Node node = 0; /* make compiler happy */ FT_Offset hash; if ( anode ) *anode = NULL; /* other argument checks delayed to `FTC_Cache_Lookup' */ if ( !ansbit ) return FT_THROW( Invalid_Argument ); *ansbit = NULL; /* * Internal `FTC_BasicAttr->load_flags' is of type `FT_UInt', * but public `FT_ImageType->flags' is of type `FT_Int32'. * * On 16bit systems, higher bits of type->flags cannot be handled. */ #if 0xFFFFFFFFUL > FT_UINT_MAX if ( (type->flags & (FT_ULong)FT_UINT_MAX) ) FT_TRACE1(( "FTC_ImageCache_Lookup:" " higher bits in load_flags 0x%x are dropped\n", (FT_ULong)type->flags & ~((FT_ULong)FT_UINT_MAX) )); #endif query.attrs.scaler.face_id = type->face_id; query.attrs.scaler.width = type->width; query.attrs.scaler.height = type->height; query.attrs.load_flags = (FT_UInt)type->flags; query.attrs.scaler.pixel = 1; query.attrs.scaler.x_res = 0; /* make compilers happy */ query.attrs.scaler.y_res = 0; /* beware, the hash must be the same for all glyph ranges! */ hash = FTC_BASIC_ATTR_HASH( &query.attrs ) + gindex / FTC_SBIT_ITEMS_PER_NODE; #if 1 /* inlining is about 50% faster! */ FTC_GCACHE_LOOKUP_CMP( cache, ftc_basic_family_compare, FTC_SNode_Compare, hash, gindex, &query, node, error ); #else error = FTC_GCache_Lookup( FTC_GCACHE( cache ), hash, gindex, FTC_GQUERY( &query ), &node ); #endif if ( error ) goto Exit; *ansbit = FTC_SNODE( node )->sbits + ( gindex - FTC_GNODE( node )->gindex ); if ( anode ) { *anode = node; node->ref_count++; } Exit: return error; }