static void ft_glyphslot_clear( FT_GlyphSlot slot ) { /* free bitmap if needed */ if ( slot->flags & FT_GLYPH_OWN_BITMAP ) { FT_Memory memory = FT_FACE_MEMORY( slot->face ); FT_FREE( slot->bitmap.buffer ); slot->flags &= ~FT_GLYPH_OWN_BITMAP; } /* clear all public fields in the glyph slot */ FT_ZERO( &slot->metrics ); FT_ZERO( &slot->outline ); FT_ZERO( &slot->bitmap ); slot->bitmap_left = 0; slot->bitmap_top = 0; slot->num_subglyphs = 0; slot->subglyphs = 0; slot->control_data = 0; slot->control_len = 0; slot->other = 0; slot->format = ft_glyph_format_none; slot->linearHoriAdvance = 0; slot->linearVertAdvance = 0; }
af_loader_init( AF_Loader loader, AF_GlyphHints hints ) { FT_ZERO( loader ); loader->hints = hints; }
cf2_getSeacComponent( CFF_Decoder* decoder, CF2_UInt code, CF2_Buffer buf ) { CF2_Int gid; FT_Byte* charstring; FT_ULong len; FT_Error error; FT_ASSERT( decoder ); FT_ZERO( buf ); gid = cff_lookup_glyph_by_stdcharcode( decoder->cff, code ); if ( gid < 0 ) return FT_THROW( Invalid_Glyph_Format ); error = cff_get_glyph_data( decoder->builder.face, gid, &charstring, &len ); /* TODO: for now, just pass the FreeType error through */ if ( error ) return error; /* assume input has been validated */ FT_ASSERT( charstring + len >= charstring ); buf->start = charstring; buf->end = charstring + len; buf->ptr = buf->start; return FT_Err_Ok; }
tt_glyphzone_new( FT_Memory memory, FT_UShort maxPoints, FT_Short maxContours, TT_GlyphZone zone ) { FT_Error error; FT_ZERO( zone ); zone->memory = memory; if ( FT_NEW_ARRAY( zone->org, maxPoints ) || FT_NEW_ARRAY( zone->cur, maxPoints ) || FT_NEW_ARRAY( zone->orus, maxPoints ) || FT_NEW_ARRAY( zone->tags, maxPoints ) || FT_NEW_ARRAY( zone->contours, maxContours ) ) { tt_glyphzone_done( zone ); } else { zone->max_points = maxPoints; zone->max_contours = maxContours; } return error; }
cf2_hintmask_init( CF2_HintMask hintmask, FT_Error* error ) { FT_ZERO( hintmask ); hintmask->error = error; }
int main( int argc, char** argv ) { FT_Library library; FT_StreamRec stream; FT_Error error = FT_Err_Ok; AFM_FontInfoRec fi; if ( argc < 2 ) return FT_ERR( Invalid_Argument ); error = FT_Init_FreeType( &library ); if ( error ) return error; FT_ZERO( &stream ); error = FT_Stream_Open( &stream, argv[1] ); if ( error ) goto Exit; stream.memory = library->memory; FT_ZERO( &fi ); error = parse_afm( library, &stream, &fi ); if ( !error ) { FT_Memory memory = library->memory; dump_fontinfo( &fi ); if ( fi.KernPairs ) FT_FREE( fi.KernPairs ); if ( fi.TrackKerns ) FT_FREE( fi.TrackKerns ); } else printf( "parse error\n" ); FT_Stream_Close( &stream ); Exit: FT_Done_FreeType( library ); return error; }
af_loader_init( AF_Loader loader, FT_Memory memory ) { FT_ZERO( loader ); af_glyph_hints_init( &loader->hints, memory ); return FT_GlyphLoader_New( memory, &loader->gloader ); }
af_loader_init( AF_Loader loader, AF_GlyphHints hints ) { FT_ZERO( loader ); loader->hints = hints; #ifdef FT_DEBUG_AUTOFIT _af_debug_hints = loader->hints; #endif }
pfr_glyph_init( PFR_Glyph glyph, FT_GlyphLoader loader ) { FT_ZERO( glyph ); glyph->loader = loader; glyph->path_begun = 0; FT_GlyphLoader_Rewind( loader ); }
af_loader_init( AF_Loader loader, FT_Memory memory ) { FT_ZERO( loader ); af_glyph_hints_init( &loader->hints, memory ); #ifdef FT_DEBUG_AUTOFIT _af_debug_hints = &loader->hints; #endif return FT_GlyphLoader_New( memory, &loader->gloader ); }
af_loader_load_glyph( AF_Loader loader, FT_Face face, FT_UInt gindex, FT_UInt32 load_flags ) { FT_Error error; FT_Size size = face->size; AF_ScalerRec scaler; if ( !size ) return AF_Err_Invalid_Argument; FT_ZERO( &scaler ); scaler.face = face; scaler.x_scale = size->metrics.x_scale; scaler.x_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */ scaler.y_scale = size->metrics.y_scale; scaler.y_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */ scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags ); scaler.flags = 0; /* XXX: fix this */ error = af_loader_reset( loader, face ); if ( !error ) { AF_ScriptMetrics metrics; error = af_face_globals_get_metrics( loader->globals, gindex, &metrics ); if ( !error ) { loader->metrics = metrics; if ( metrics->clazz->script_metrics_scale ) metrics->clazz->script_metrics_scale( metrics, &scaler ); else metrics->scaler = scaler; load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM; load_flags &= ~FT_LOAD_RENDER; error = metrics->clazz->script_hints_init( &loader->hints, metrics ); if ( error ) goto Exit; error = af_loader_load_g( loader, &scaler, gindex, load_flags, 0 ); } } Exit: return error; }
FT_Stream_OpenLZW( FT_Stream stream, FT_Stream source ) { FT_Error error; FT_Memory memory; FT_LZWFile zip = NULL; if ( !stream || !source ) { error = FT_THROW( Invalid_Stream_Handle ); goto Exit; } memory = source->memory; /* * Check the header right now; this prevents allocation of a huge * LZWFile object (400 KByte of heap memory) if not necessary. * * Did I mention that you should never use .Z compressed font * files? */ error = ft_lzw_check_header( source ); if ( error ) goto Exit; FT_ZERO( stream ); stream->memory = memory; if ( !FT_NEW( zip ) ) { error = ft_lzw_file_init( zip, stream, source ); if ( error ) { FT_FREE( zip ); goto Exit; } stream->descriptor.pointer = zip; } stream->size = 0x7FFFFFFFL; /* don't know the real size! */ stream->pos = 0; stream->base = 0; stream->read = ft_lzw_stream_io; stream->close = ft_lzw_stream_close; Exit: return error; }
static void t42_glyphslot_clear( FT_GlyphSlot slot ) { /* free bitmap if needed */ ft_glyphslot_free_bitmap( slot ); /* clear all public fields in the glyph slot */ FT_ZERO( &slot->metrics ); FT_ZERO( &slot->outline ); FT_ZERO( &slot->bitmap ); slot->bitmap_left = 0; slot->bitmap_top = 0; slot->num_subglyphs = 0; slot->subglyphs = 0; slot->control_data = 0; slot->control_len = 0; slot->other = 0; slot->format = FT_GLYPH_FORMAT_NONE; slot->linearHoriAdvance = 0; slot->linearVertAdvance = 0; }
af_loader_init( AF_Module module ) { AF_Loader loader = module->loader; FT_Memory memory = module->root.library->memory; FT_ZERO( loader ); af_glyph_hints_init( &loader->hints, memory ); #ifdef FT_DEBUG_AUTOFIT _af_debug_hints = &loader->hints; #endif return FT_GlyphLoader_New( memory, &loader->gloader ); }
FT_Stream_OpenBzip2( FT_Stream stream, FT_Stream source ) { FT_Error error; FT_Memory memory; FT_BZip2File zip = NULL; if ( !stream || !source ) { error = FT_THROW( Invalid_Stream_Handle ); goto Exit; } memory = source->memory; /* * check the header right now; this prevents allocating unnecessary * objects when we don't need them */ error = ft_bzip2_check_header( source ); if ( error ) goto Exit; FT_ZERO( stream ); stream->memory = memory; if ( !FT_QNEW( zip ) ) { error = ft_bzip2_file_init( zip, stream, source ); if ( error ) { FT_FREE( zip ); goto Exit; } stream->descriptor.pointer = zip; } stream->size = 0x7FFFFFFFL; /* don't know the real size! */ stream->pos = 0; stream->base = 0; stream->read = ft_bzip2_stream_io; stream->close = ft_bzip2_stream_close; Exit: return error; }
cf2_initLocalRegionBuffer( CFF_Decoder* decoder, CF2_UInt idx, CF2_Buffer buf ) { FT_ASSERT( decoder && ( decoder->locals || decoder->num_locals == 0 ) ); FT_ZERO( buf ); idx += decoder->locals_bias; if ( idx >= decoder->num_locals ) return TRUE; /* error */ buf->start = buf->ptr = decoder->locals[idx]; buf->end = decoder->locals[idx + 1]; return FALSE; /* success */ }
af_loader_init( AF_Loader loader, FT_Memory memory ) { FT_Error error; FT_ZERO( loader ); af_glyph_hints_init( &loader->hints, memory ); error = FT_GlyphLoader_New( memory, &loader->gloader ); if ( !error ) { error = FT_GlyphLoader_CreateExtra( loader->gloader ); if ( error ) { FT_GlyphLoader_Done( loader->gloader ); loader->gloader = NULL; } } return error; }
static FT_MemTable ft_mem_table_new( FT_Memory memory ) { FT_MemTable table; table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) ); if ( !table ) goto Exit; FT_ZERO( table ); table->size = FT_MEM_SIZE_MIN; table->nodes = 0; table->memory = memory; table->memory_user = memory->user; table->alloc = memory->alloc; table->realloc = memory->realloc; table->free = memory->free; table->buckets = (FT_MemNode *) memory->alloc( memory, table->size * (FT_Long)sizeof ( FT_MemNode ) ); if ( table->buckets ) FT_ARRAY_ZERO( table->buckets, table->size ); else { memory->free( memory, table ); table = NULL; } Exit: return table; }
cff_font_load( FT_Stream stream, FT_Int face_index, CFF_Font font, FT_Bool pure_cff ) { static const FT_Frame_Field cff_header_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE CFF_FontRec FT_FRAME_START( 4 ), FT_FRAME_BYTE( version_major ), FT_FRAME_BYTE( version_minor ), FT_FRAME_BYTE( header_size ), FT_FRAME_BYTE( absolute_offsize ), FT_FRAME_END }; FT_Error error; FT_Memory memory = stream->memory; FT_ULong base_offset; CFF_FontRecDict dict; FT_ZERO( font ); font->stream = stream; font->memory = memory; dict = &font->top_font.font_dict; base_offset = FT_STREAM_POS(); /* read CFF font header */ if ( FT_STREAM_READ_FIELDS( cff_header_fields, font ) ) goto Exit; /* check format */ if ( font->version_major != 1 || font->header_size < 4 || font->absolute_offsize > 4 ) { FT_TRACE2(( "[not a CFF font header!]\n" )); error = CFF_Err_Unknown_File_Format; goto Exit; } /* skip the rest of the header */ if ( FT_STREAM_SKIP( font->header_size - 4 ) ) goto Exit; /* read the name, top dict, string and global subrs index */ if ( FT_SET_ERROR( cff_index_init( &font->name_index, stream, 0 ) ) || FT_SET_ERROR( cff_index_init( &font->font_dict_index, stream, 0 ) ) || FT_SET_ERROR( cff_index_init( &font->string_index, stream, 0 ) ) || FT_SET_ERROR( cff_index_init( &font->global_subrs_index, stream, 1 ) ) ) goto Exit; /* well, we don't really forget the `disabled' fonts... */ font->num_faces = font->name_index.count; if ( face_index >= (FT_Int)font->num_faces ) { FT_ERROR(( "cff_font_load: incorrect face index = %d\n", face_index )); error = CFF_Err_Invalid_Argument; } /* in case of a font format check, simply exit now */ if ( face_index < 0 ) goto Exit; /* now, parse the top-level font dictionary */ error = cff_subfont_load( &font->top_font, &font->font_dict_index, face_index, stream, base_offset ); if ( error ) goto Exit; if ( FT_STREAM_SEEK( base_offset + dict->charstrings_offset ) ) goto Exit; error = cff_index_init( &font->charstrings_index, stream, 0 ); if ( error ) goto Exit; /* now, check for a CID font */ if ( dict->cid_registry != 0xFFFFU ) { CFF_IndexRec fd_index; CFF_SubFont sub; FT_UInt idx; /* this is a CID-keyed font, we must now allocate a table of */ /* sub-fonts, then load each of them separately */ if ( FT_STREAM_SEEK( base_offset + dict->cid_fd_array_offset ) ) goto Exit; error = cff_index_init( &fd_index, stream, 0 ); if ( error ) goto Exit; if ( fd_index.count > CFF_MAX_CID_FONTS ) { FT_ERROR(( "cff_font_load: FD array too large in CID font\n" )); goto Fail_CID; } /* allocate & read each font dict independently */ font->num_subfonts = fd_index.count; if ( FT_NEW_ARRAY( sub, fd_index.count ) ) goto Fail_CID; /* set up pointer table */ for ( idx = 0; idx < fd_index.count; idx++ ) font->subfonts[idx] = sub + idx; /* now load each subfont independently */ for ( idx = 0; idx < fd_index.count; idx++ ) { sub = font->subfonts[idx]; error = cff_subfont_load( sub, &fd_index, idx, stream, base_offset ); if ( error ) goto Fail_CID; } /* now load the FD Select array */ error = CFF_Load_FD_Select( &font->fd_select, font->charstrings_index.count, stream, base_offset + dict->cid_fd_select_offset ); Fail_CID: cff_index_done( &fd_index ); if ( error ) goto Exit; } else font->num_subfonts = 0; /* read the charstrings index now */ if ( dict->charstrings_offset == 0 ) { FT_ERROR(( "cff_font_load: no charstrings offset!\n" )); error = CFF_Err_Unknown_File_Format; goto Exit; } /* explicit the global subrs */ font->num_global_subrs = font->global_subrs_index.count; font->num_glyphs = font->charstrings_index.count; error = cff_index_get_pointers( &font->global_subrs_index, &font->global_subrs ) ; if ( error ) goto Exit; /* read the Charset and Encoding tables if available */ if ( font->num_glyphs > 0 ) { FT_Bool invert = FT_BOOL( dict->cid_registry != 0xFFFFU && pure_cff ); error = cff_charset_load( &font->charset, font->num_glyphs, stream, base_offset, dict->charset_offset, invert ); if ( error ) goto Exit; /* CID-keyed CFFs don't have an encoding */ if ( dict->cid_registry == 0xFFFFU ) { error = cff_encoding_load( &font->encoding, &font->charset, font->num_glyphs, stream, base_offset, dict->encoding_offset ); if ( error ) goto Exit; } else /* CID-keyed fonts only need CIDs */ FT_FREE( font->charset.sids ); } /* get the font name (/CIDFontName for CID-keyed fonts, */ /* /FontName otherwise) */ font->font_name = cff_index_get_name( &font->name_index, face_index ); Exit: return error; }
static FT_Error tt_face_load_bdf_props( TT_Face face, FT_Stream stream ) { TT_BDF bdf = &face->bdf; FT_ULong length; FT_Error error; FT_ZERO( bdf ); error = tt_face_goto_table( face, TTAG_BDF, stream, &length ); if ( error || length < 8 || FT_FRAME_EXTRACT( length, bdf->table ) ) { error = FT_THROW( Invalid_Table ); goto Exit; } bdf->table_end = bdf->table + length; { FT_Byte* p = bdf->table; FT_UInt version = FT_NEXT_USHORT( p ); FT_UInt num_strikes = FT_NEXT_USHORT( p ); FT_ULong strings = FT_NEXT_ULONG ( p ); FT_UInt count; FT_Byte* strike; if ( version != 0x0001 || strings < 8 || ( strings - 8 ) / 4 < num_strikes || strings + 1 > length ) { goto BadTable; } bdf->num_strikes = num_strikes; bdf->strings = bdf->table + strings; bdf->strings_size = length - strings; count = bdf->num_strikes; p = bdf->table + 8; strike = p + count * 4; for ( ; count > 0; count-- ) { FT_UInt num_items = FT_PEEK_USHORT( p + 2 ); /* * We don't need to check the value sets themselves, since this * is done later. */ strike += 10 * num_items; p += 4; } if ( strike > bdf->strings ) goto BadTable; } bdf->loaded = 1; Exit: return error; BadTable: FT_FRAME_RELEASE( bdf->table ); FT_ZERO( bdf ); error = FT_THROW( Invalid_Table ); goto Exit; }
FT_Stream_OpenGzip( FT_Stream stream, FT_Stream source ) { FT_Error error; FT_Memory memory = source->memory; FT_GZipFile zip; /* * check the header right now; this prevents allocating un-necessary * objects when we don't need them */ error = ft_gzip_check_header( source ); if ( error ) goto Exit; FT_ZERO( stream ); stream->memory = memory; if ( !FT_QNEW( zip ) ) { error = ft_gzip_file_init( zip, stream, source ); if ( error ) { FT_FREE( zip ); goto Exit; } stream->descriptor.pointer = zip; } /* * We use the following trick to try to dramatically improve the * performance while dealing with small files. If the original stream * size is less than a certain threshold, we try to load the whole font * file into memory. This saves us from using the 32KB buffer needed * to inflate the file, plus the two 4KB intermediate input/output * buffers used in the `FT_GZipFile' structure. */ { FT_ULong zip_size = ft_gzip_get_uncompressed_size( source ); if ( zip_size != 0 && zip_size < 40 * 1024 ) { FT_Byte* zip_buff; if ( !FT_ALLOC( zip_buff, zip_size ) ) { FT_ULong count; count = ft_gzip_file_io( zip, 0, zip_buff, zip_size ); if ( count == zip_size ) { ft_gzip_file_done( zip ); FT_FREE( zip ); stream->descriptor.pointer = NULL; stream->size = zip_size; stream->pos = 0; stream->base = zip_buff; stream->read = NULL; stream->close = ft_gzip_stream_close; goto Exit; } ft_gzip_file_io( zip, 0, NULL, 0 ); FT_FREE( zip_buff ); } error = 0; } } stream->size = 0x7FFFFFFFL; /* don't know the real size! */ stream->pos = 0; stream->base = 0; stream->read = ft_gzip_stream_io; stream->close = ft_gzip_stream_close; Exit: return error; }
ah_outline_compute_segments( AH_Outline outline ) { int dimension; AH_Segment segments; FT_Int* p_num_segments; AH_Direction segment_dir; AH_Direction major_dir; segments = outline->horz_segments; p_num_segments = &outline->num_hsegments; major_dir = AH_DIR_RIGHT; /* This value must be positive! */ segment_dir = major_dir; /* set up (u,v) in each point */ ah_setup_uv( outline, AH_UV_FYX ); for ( dimension = 1; dimension >= 0; dimension-- ) { AH_Point* contour = outline->contours; AH_Point* contour_limit = contour + outline->num_contours; AH_Segment segment = segments; FT_Int num_segments = 0; #ifdef AH_HINT_METRICS AH_Point min_point = 0; AH_Point max_point = 0; FT_Pos min_coord = 32000; FT_Pos max_coord = -32000; #endif /* do each contour separately */ for ( ; contour < contour_limit; contour++ ) { AH_Point point = contour[0]; AH_Point last = point->prev; int on_edge = 0; FT_Pos min_pos = +32000; /* minimum segment pos != min_coord */ FT_Pos max_pos = -32000; /* maximum segment pos != max_coord */ FT_Bool passed; #ifdef AH_HINT_METRICS if ( point->u < min_coord ) { min_coord = point->u; min_point = point; } if ( point->u > max_coord ) { max_coord = point->u; max_point = point; } #endif if ( point == last ) /* skip singletons -- just in case? */ continue; if ( ABS( last->out_dir ) == major_dir && ABS( point->out_dir ) == major_dir ) { /* we are already on an edge, try to locate its start */ last = point; for (;;) { point = point->prev; if ( ABS( point->out_dir ) != major_dir ) { point = point->next; break; } if ( point == last ) break; } } last = point; passed = 0; for (;;) { FT_Pos u, v; if ( on_edge ) { u = point->u; if ( u < min_pos ) min_pos = u; if ( u > max_pos ) max_pos = u; if ( point->out_dir != segment_dir || point == last ) { /* we are just leaving an edge; record a new segment! */ segment->last = point; segment->pos = ( min_pos + max_pos ) >> 1; /* a segment is round if either its first or last point */ /* is a control point */ if ( ( segment->first->flags | point->flags ) & AH_FLAG_CONTROL ) segment->flags |= AH_EDGE_ROUND; /* compute segment size */ min_pos = max_pos = point->v; v = segment->first->v; if ( v < min_pos ) min_pos = v; if ( v > max_pos ) max_pos = v; segment->min_coord = min_pos; segment->max_coord = max_pos; on_edge = 0; num_segments++; segment++; /* fallthrough */ } } /* now exit if we are at the start/end point */ if ( point == last ) { if ( passed ) break; passed = 1; } if ( !on_edge && ABS( point->out_dir ) == major_dir ) { /* this is the start of a new segment! */ segment_dir = point->out_dir; /* clear all segment fields */ FT_ZERO( segment ); segment->dir = segment_dir; segment->flags = AH_EDGE_NORMAL; min_pos = max_pos = point->u; segment->first = point; segment->last = point; segment->contour = contour; on_edge = 1; #ifdef AH_HINT_METRICS if ( point == max_point ) max_point = 0; if ( point == min_point ) min_point = 0; #endif } point = point->next; } } /* contours */ #ifdef AH_HINT_METRICS /* we need to ensure that there are edges on the left-most and */ /* right-most points of the glyph in order to hint the metrics; */ /* we do this by inserting fake segments when needed */ if ( dimension == 0 ) { AH_Point point = outline->points; AH_Point point_limit = point + outline->num_points; FT_Pos min_pos = 32000; FT_Pos max_pos = -32000; min_point = 0; max_point = 0; /* compute minimum and maximum points */ for ( ; point < point_limit; point++ ) { FT_Pos x = point->fx; if ( x < min_pos ) { min_pos = x; min_point = point; } if ( x > max_pos ) { max_pos = x; max_point = point; } } /* insert minimum segment */ if ( min_point ) { /* clear all segment fields */ FT_ZERO( segment ); segment->dir = segment_dir; segment->flags = AH_EDGE_NORMAL; segment->first = min_point; segment->last = min_point; segment->pos = min_pos; num_segments++; segment++; } /* insert maximum segment */ if ( max_point ) { /* clear all segment fields */ FT_ZERO( segment ); segment->dir = segment_dir; segment->flags = AH_EDGE_NORMAL; segment->first = max_point; segment->last = max_point; segment->pos = max_pos; num_segments++; segment++; } } #endif /* AH_HINT_METRICS */ *p_num_segments = num_segments; segments = outline->vert_segments; major_dir = AH_DIR_UP; p_num_segments = &outline->num_vsegments; ah_setup_uv( outline, AH_UV_FXY ); }
af_loader_load_glyph( AF_Loader loader, AF_Module module, FT_Face face, FT_UInt gindex, FT_Int32 load_flags ) { FT_Error error; FT_Size size = face->size; AF_ScalerRec scaler; if ( !size ) return FT_THROW( Invalid_Size_Handle ); FT_ZERO( &scaler ); scaler.face = face; scaler.x_scale = size->metrics.x_scale; scaler.x_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */ scaler.y_scale = size->metrics.y_scale; scaler.y_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */ scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags ); scaler.flags = 0; /* XXX: fix this */ error = af_loader_reset( loader, module, face ); if ( !error ) { AF_StyleMetrics metrics; FT_UInt options = AF_STYLE_NONE_DFLT; #ifdef FT_OPTION_AUTOFIT2 /* XXX: undocumented hook to activate the latin2 writing system */ if ( load_flags & ( 1UL << 20 ) ) options = AF_STYLE_LTN2_DFLT; #endif error = af_face_globals_get_metrics( loader->globals, gindex, options, &metrics ); if ( !error ) { #ifdef FT_CONFIG_OPTION_PIC AF_FaceGlobals globals = loader->globals; #endif AF_StyleClass style_class = metrics->style_class; AF_WritingSystemClass writing_system_class = AF_WRITING_SYSTEM_CLASSES_GET[style_class->writing_system]; loader->metrics = metrics; if ( writing_system_class->style_metrics_scale ) writing_system_class->style_metrics_scale( metrics, &scaler ); else metrics->scaler = scaler; load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM; load_flags &= ~FT_LOAD_RENDER; if ( writing_system_class->style_hints_init ) { error = writing_system_class->style_hints_init( loader->hints, metrics ); if ( error ) goto Exit; } error = af_loader_load_g( loader, &scaler, gindex, load_flags ); } } Exit: return error; }
cf2_decoder_parse_charstrings( CFF_Decoder* decoder, FT_Byte* charstring_base, FT_ULong charstring_len ) { FT_Memory memory; FT_Error error = FT_Err_Ok; CF2_Font font; FT_ASSERT( decoder && decoder->cff ); memory = decoder->builder.memory; /* CF2 data is saved here across glyphs */ font = (CF2_Font)decoder->cff->cf2_instance.data; /* on first glyph, allocate instance structure */ if ( decoder->cff->cf2_instance.data == NULL ) { decoder->cff->cf2_instance.finalizer = (FT_Generic_Finalizer)cf2_free_instance; if ( FT_ALLOC( decoder->cff->cf2_instance.data, sizeof ( CF2_FontRec ) ) ) return FT_THROW( Out_Of_Memory ); font = (CF2_Font)decoder->cff->cf2_instance.data; font->memory = memory; /* initialize a client outline, to be shared by each glyph rendered */ cf2_outline_init( &font->outline, font->memory, &font->error ); } /* save decoder; it is a stack variable and will be different on each */ /* call */ font->decoder = decoder; font->outline.decoder = decoder; { /* build parameters for Adobe engine */ CFF_Builder* builder = &decoder->builder; CFF_Driver driver = (CFF_Driver)FT_FACE_DRIVER( builder->face ); /* local error */ FT_Error error2 = FT_Err_Ok; CF2_BufferRec buf; CF2_Matrix transform; CF2_F16Dot16 glyphWidth; FT_Bool hinted; FT_Bool scaled; /* FreeType has already looked up the GID; convert to */ /* `RegionBuffer', assuming that the input has been validated */ FT_ASSERT( charstring_base + charstring_len >= charstring_base ); FT_ZERO( &buf ); buf.start = buf.ptr = charstring_base; buf.end = charstring_base + charstring_len; FT_ZERO( &transform ); cf2_getScaleAndHintFlag( decoder, &transform.a, &transform.d, &hinted, &scaled ); font->renderingFlags = 0; if ( hinted ) font->renderingFlags |= CF2_FlagsHinted; if ( scaled && !driver->no_stem_darkening ) font->renderingFlags |= CF2_FlagsDarkened; font->darkenParams[0] = driver->darken_params[0]; font->darkenParams[1] = driver->darken_params[1]; font->darkenParams[2] = driver->darken_params[2]; font->darkenParams[3] = driver->darken_params[3]; font->darkenParams[4] = driver->darken_params[4]; font->darkenParams[5] = driver->darken_params[5]; font->darkenParams[6] = driver->darken_params[6]; font->darkenParams[7] = driver->darken_params[7]; /* now get an outline for this glyph; */ /* also get units per em to validate scale */ font->unitsPerEm = (CF2_Int)cf2_getUnitsPerEm( decoder ); if ( scaled ) { error2 = cf2_checkTransform( &transform, font->unitsPerEm ); if ( error2 ) return error2; } error2 = cf2_getGlyphOutline( font, &buf, &transform, &glyphWidth ); if ( error2 ) return FT_ERR( Invalid_File_Format ); cf2_setGlyphWidth( &font->outline, glyphWidth ); return FT_Err_Ok; } }
af_latin_metrics_init_widths( AF_LatinMetrics metrics, FT_Face face, FT_ULong charcode ) { /* scan the array of segments in each direction */ AF_GlyphHintsRec hints[1]; af_glyph_hints_init( hints, face->memory ); metrics->axis[AF_DIMENSION_HORZ].width_count = 0; metrics->axis[AF_DIMENSION_VERT].width_count = 0; { FT_Error error; FT_UInt glyph_index; int dim; AF_LatinMetricsRec dummy[1]; AF_Scaler scaler = &dummy->root.scaler; glyph_index = FT_Get_Char_Index( face, charcode ); if ( glyph_index == 0 ) goto Exit; error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE ); if ( error || face->glyph->outline.n_points <= 0 ) goto Exit; FT_ZERO( dummy ); dummy->units_per_em = metrics->units_per_em; scaler->x_scale = scaler->y_scale = 0x10000L; scaler->x_delta = scaler->y_delta = 0; scaler->face = face; scaler->render_mode = FT_RENDER_MODE_NORMAL; scaler->flags = 0; af_glyph_hints_rescale( hints, (AF_ScriptMetrics)dummy ); error = af_glyph_hints_reload( hints, &face->glyph->outline, 0 ); if ( error ) goto Exit; for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) { AF_LatinAxis axis = &metrics->axis[dim]; AF_AxisHints axhints = &hints->axis[dim]; AF_Segment seg, limit, link; FT_UInt num_widths = 0; error = af_latin_hints_compute_segments( hints, (AF_Dimension)dim ); if ( error ) goto Exit; af_latin_hints_link_segments( hints, (AF_Dimension)dim ); seg = axhints->segments; limit = seg + axhints->num_segments; for ( ; seg < limit; seg++ ) { link = seg->link; /* we only consider stem segments there! */ if ( link && link->link == seg && link > seg ) { FT_Pos dist; dist = seg->pos - link->pos; if ( dist < 0 ) dist = -dist; if ( num_widths < AF_LATIN_MAX_WIDTHS ) axis->widths[ num_widths++ ].org = dist; } } af_sort_widths( num_widths, axis->widths ); axis->width_count = num_widths; } Exit: for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ ) { AF_LatinAxis axis = &metrics->axis[dim]; FT_Pos stdw; stdw = ( axis->width_count > 0 ) ? axis->widths[0].org : AF_LATIN_CONSTANT( metrics, 50 ); /* let's try 20% of the smallest width */ axis->edge_distance_threshold = stdw / 5; axis->standard_width = stdw; axis->extra_light = 0; } } af_glyph_hints_done( hints ); }
static FT_Error af_cjk_hints_compute_edges( AF_GlyphHints hints, AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; FT_Error error = AF_Err_Ok; FT_Memory memory = hints->memory; AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim]; AF_Segment segments = axis->segments; AF_Segment segment_limit = segments + axis->num_segments; AF_Segment seg; FT_Fixed scale; FT_Pos edge_distance_threshold; axis->num_edges = 0; scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale : hints->y_scale; /*********************************************************************/ /* */ /* We begin by generating a sorted table of edges for the current */ /* direction. To do so, we simply scan each segment and try to find */ /* an edge in our table that corresponds to its position. */ /* */ /* If no edge is found, we create and insert a new edge in the */ /* sorted table. Otherwise, we simply add the segment to the edge's */ /* list which is then processed in the second step to compute the */ /* edge's properties. */ /* */ /* Note that the edges table is sorted along the segment/edge */ /* position. */ /* */ /*********************************************************************/ edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold, scale ); if ( edge_distance_threshold > 64 / 4 ) edge_distance_threshold = FT_DivFix( 64 / 4, scale ); else edge_distance_threshold = laxis->edge_distance_threshold; for ( seg = segments; seg < segment_limit; seg++ ) { AF_Edge found = 0; FT_Pos best = 0xFFFFU; FT_Int ee; /* look for an edge corresponding to the segment */ for ( ee = 0; ee < axis->num_edges; ee++ ) { AF_Edge edge = axis->edges + ee; FT_Pos dist; if ( edge->dir != seg->dir ) continue; dist = seg->pos - edge->fpos; if ( dist < 0 ) dist = -dist; if ( dist < edge_distance_threshold && dist < best ) { AF_Segment link = seg->link; /* check whether all linked segments of the candidate edge */ /* can make a single edge. */ if ( link ) { AF_Segment seg1 = edge->first; AF_Segment link1; FT_Pos dist2 = 0; do { link1 = seg1->link; if ( link1 ) { dist2 = AF_SEGMENT_DIST( link, link1 ); if ( dist2 >= edge_distance_threshold ) break; } } while ( ( seg1 = seg1->edge_next ) != edge->first ); if ( dist2 >= edge_distance_threshold ) continue; } best = dist; found = edge; } } if ( !found ) { AF_Edge edge; /* insert a new edge in the list and */ /* sort according to the position */ error = af_axis_hints_new_edge( axis, seg->pos, (AF_Direction)seg->dir, memory, &edge ); if ( error ) goto Exit; /* add the segment to the new edge's list */ FT_ZERO( edge ); edge->first = seg; edge->last = seg; edge->fpos = seg->pos; edge->opos = edge->pos = FT_MulFix( seg->pos, scale ); seg->edge_next = seg; edge->dir = seg->dir; } else { /* if an edge was found, simply add the segment to the edge's */ /* list */ seg->edge_next = found->first; found->last->edge_next = seg; found->last = seg; } } /*********************************************************************/ /* */ /* Good, we now compute each edge's properties according to segments */ /* found on its position. Basically, these are as follows. */ /* */ /* - edge's main direction */ /* - stem edge, serif edge or both (which defaults to stem then) */ /* - rounded edge, straight or both (which defaults to straight) */ /* - link for edge */ /* */ /*********************************************************************/ /* first of all, set the `edge' field in each segment -- this is */ /* required in order to compute edge links */ /* */ /* Note that removing this loop and setting the `edge' field of each */ /* segment directly in the code above slows down execution speed for */ /* some reasons on platforms like the Sun. */ { AF_Edge edges = axis->edges; AF_Edge edge_limit = edges + axis->num_edges; AF_Edge edge; for ( edge = edges; edge < edge_limit; edge++ ) { seg = edge->first; if ( seg ) do { seg->edge = edge; seg = seg->edge_next; } while ( seg != edge->first ); } /* now compute each edge properties */ for ( edge = edges; edge < edge_limit; edge++ ) { FT_Int is_round = 0; /* does it contain round segments? */ FT_Int is_straight = 0; /* does it contain straight segments? */ seg = edge->first; do { FT_Bool is_serif; /* check for roundness of segment */ if ( seg->flags & AF_EDGE_ROUND ) is_round++; else is_straight++; /* check for links -- if seg->serif is set, then seg->link must */ /* be ignored */ is_serif = (FT_Bool)( seg->serif && seg->serif->edge != edge ); if ( seg->link || is_serif ) { AF_Edge edge2; AF_Segment seg2; edge2 = edge->link; seg2 = seg->link; if ( is_serif ) { seg2 = seg->serif; edge2 = edge->serif; } if ( edge2 ) { FT_Pos edge_delta; FT_Pos seg_delta; edge_delta = edge->fpos - edge2->fpos; if ( edge_delta < 0 ) edge_delta = -edge_delta; seg_delta = AF_SEGMENT_DIST( seg, seg2 ); if ( seg_delta < edge_delta ) edge2 = seg2->edge; } else edge2 = seg2->edge; if ( is_serif ) { edge->serif = edge2; edge2->flags |= AF_EDGE_SERIF; } else edge->link = edge2; } seg = seg->edge_next; } while ( seg != edge->first ); /* set the round/straight flags */ edge->flags = AF_EDGE_NORMAL; if ( is_round > 0 && is_round >= is_straight ) edge->flags |= AF_EDGE_ROUND; /* get rid of serifs if link is set */ /* XXX: This gets rid of many unpleasant artefacts! */ /* Example: the `c' in cour.pfa at size 13 */ if ( edge->serif && edge->link ) edge->serif = 0; } } Exit: return error; }
af_latin_hints_compute_segments( AF_GlyphHints hints, AF_Dimension dim ) { AF_AxisHints axis = &hints->axis[dim]; FT_Memory memory = hints->memory; FT_Error error = AF_Err_Ok; AF_Segment segment = NULL; AF_SegmentRec seg0; AF_Point* contour = hints->contours; AF_Point* contour_limit = contour + hints->num_contours; AF_Direction major_dir, segment_dir; FT_ZERO( &seg0 ); seg0.score = 32000; seg0.flags = AF_EDGE_NORMAL; major_dir = (AF_Direction)FT_ABS( axis->major_dir ); segment_dir = major_dir; axis->num_segments = 0; /* set up (u,v) in each point */ if ( dim == AF_DIMENSION_HORZ ) { AF_Point point = hints->points; AF_Point limit = point + hints->num_points; for ( ; point < limit; point++ ) { point->u = point->fx; point->v = point->fy; } } else { AF_Point point = hints->points; AF_Point limit = point + hints->num_points; for ( ; point < limit; point++ ) { point->u = point->fy; point->v = point->fx; } } /* do each contour separately */ for ( ; contour < contour_limit; contour++ ) { AF_Point point = contour[0]; AF_Point last = point->prev; int on_edge = 0; FT_Pos min_pos = 32000; /* minimum segment pos != min_coord */ FT_Pos max_pos = -32000; /* maximum segment pos != max_coord */ FT_Bool passed; if ( point == last ) /* skip singletons -- just in case */ continue; if ( FT_ABS( last->out_dir ) == major_dir && FT_ABS( point->out_dir ) == major_dir ) { /* we are already on an edge, try to locate its start */ last = point; for (;;) { point = point->prev; if ( FT_ABS( point->out_dir ) != major_dir ) { point = point->next; break; } if ( point == last ) break; } } last = point; passed = 0; for (;;) { FT_Pos u, v; if ( on_edge ) { u = point->u; if ( u < min_pos ) min_pos = u; if ( u > max_pos ) max_pos = u; if ( point->out_dir != segment_dir || point == last ) { /* we are just leaving an edge; record a new segment! */ segment->last = point; segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 ); /* a segment is round
af_loader_load_glyph( AF_Loader loader, AF_Module module, FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags ) { FT_Error error; FT_Size size = face->size; FT_Size_Internal size_internal = size->internal; FT_GlyphSlot slot = face->glyph; FT_Slot_Internal slot_internal = slot->internal; FT_GlyphLoader gloader = slot_internal->loader; AF_GlyphHints hints = loader->hints; AF_ScalerRec scaler; AF_StyleMetrics style_metrics; FT_UInt style_options = AF_STYLE_NONE_DFLT; AF_StyleClass style_class; AF_WritingSystemClass writing_system_class; if ( !size ) return FT_THROW( Invalid_Size_Handle ); FT_ZERO( &scaler ); if ( !size_internal->autohint_metrics.x_scale || size_internal->autohint_mode != FT_LOAD_TARGET_MODE( load_flags ) ) { /* switching between hinting modes usually means different scaling */ /* values; this later on enforces recomputation of everything */ /* related to the current size */ size_internal->autohint_mode = FT_LOAD_TARGET_MODE( load_flags ); size_internal->autohint_metrics = size->metrics; #ifdef AF_CONFIG_OPTION_TT_SIZE_METRICS { FT_Size_Metrics* size_metrics = &size_internal->autohint_metrics; /* set metrics to integer values and adjust scaling accordingly; */ /* this is the same setup as with TrueType fonts, cf. function */ /* `tt_size_reset' in file `ttobjs.c' */ size_metrics->ascender = FT_PIX_ROUND( FT_MulFix( face->ascender, size_metrics->y_scale ) ); size_metrics->descender = FT_PIX_ROUND( FT_MulFix( face->descender, size_metrics->y_scale ) ); size_metrics->height = FT_PIX_ROUND( FT_MulFix( face->height, size_metrics->y_scale ) ); size_metrics->x_scale = FT_DivFix( size_metrics->x_ppem << 6, face->units_per_EM ); size_metrics->y_scale = FT_DivFix( size_metrics->y_ppem << 6, face->units_per_EM ); size_metrics->max_advance = FT_PIX_ROUND( FT_MulFix( face->max_advance_width, size_metrics->x_scale ) ); } #endif /* AF_CONFIG_OPTION_TT_SIZE_METRICS */ } /* * TODO: This code currently doesn't support fractional advance widths, * i.e., placing hinted glyphs at anything other than integer * x-positions. This is only relevant for the warper code, which * scales and shifts glyphs to optimize blackness of stems (hinting on * the x-axis by nature places things on pixel integers, hinting on the * y-axis only, i.e., LIGHT mode, doesn't touch the x-axis). The delta * values of the scaler would need to be adjusted. */ scaler.face = face; scaler.x_scale = size_internal->autohint_metrics.x_scale; scaler.x_delta = 0; scaler.y_scale = size_internal->autohint_metrics.y_scale; scaler.y_delta = 0; scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags ); scaler.flags = 0; /* note that the fallback style can't be changed anymore */ /* after the first call of `af_loader_load_glyph' */ error = af_loader_reset( loader, module, face ); if ( error ) goto Exit; #ifdef FT_OPTION_AUTOFIT2 /* XXX: undocumented hook to activate the latin2 writing system. */ if ( load_flags & ( 1UL << 20 ) ) style_options = AF_STYLE_LTN2_DFLT; #endif /* * Glyphs (really code points) are assigned to scripts. Script * analysis is done lazily: For each glyph that passes through here, * the corresponding script analyzer is called, but returns immediately * if it has been run already. */ error = af_face_globals_get_metrics( loader->globals, glyph_index, style_options, &style_metrics ); if ( error ) goto Exit; style_class = style_metrics->style_class; writing_system_class = af_writing_system_classes[style_class->writing_system]; loader->metrics = style_metrics; if ( writing_system_class->style_metrics_scale ) writing_system_class->style_metrics_scale( style_metrics, &scaler ); else style_metrics->scaler = scaler; if ( writing_system_class->style_hints_init ) { error = writing_system_class->style_hints_init( hints, style_metrics ); if ( error ) goto Exit; } /* * Do the main work of `af_loader_load_glyph'. Note that we never have * to deal with composite glyphs as those get loaded into * FT_GLYPH_FORMAT_OUTLINE by the recursed `FT_Load_Glyph' function. * In the rare cases where FT_LOAD_NO_RECURSE is set, it implies * FT_LOAD_NO_SCALE and as such the auto-hinter is never called. */ load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM | FT_LOAD_LINEAR_DESIGN; load_flags &= ~FT_LOAD_RENDER; error = FT_Load_Glyph( face, glyph_index, load_flags ); if ( error ) goto Exit; /* * Apply stem darkening (emboldening) here before hints are applied to * the outline. Glyphs are scaled down proportionally to the * emboldening so that curve points don't fall outside their * precomputed blue zones. * * Any emboldening done by the font driver (e.g., the CFF driver) * doesn't reach here because the autohinter loads the unprocessed * glyphs in font units for analysis (functions `af_*_metrics_init_*') * and then above to prepare it for the rasterizers by itself, * independently of the font driver. So emboldening must be done here, * within the autohinter. * * All glyphs to be autohinted pass through here one by one. The * standard widths can therefore change from one glyph to the next, * depending on what script a glyph is assigned to (each script has its * own set of standard widths and other metrics). The darkening amount * must therefore be recomputed for each size and * `standard_{vertical,horizontal}_width' change. * * Ignore errors and carry on without emboldening. * */ /* stem darkening only works well in `light' mode */ if ( scaler.render_mode == FT_RENDER_MODE_LIGHT && ( !face->internal->no_stem_darkening || ( face->internal->no_stem_darkening < 0 && !module->no_stem_darkening ) ) ) af_loader_embolden_glyph_in_slot( loader, face, style_metrics ); loader->transformed = slot_internal->glyph_transformed; if ( loader->transformed ) { FT_Matrix inverse; loader->trans_matrix = slot_internal->glyph_matrix; loader->trans_delta = slot_internal->glyph_delta; inverse = loader->trans_matrix; if ( !FT_Matrix_Invert( &inverse ) ) FT_Vector_Transform( &loader->trans_delta, &inverse ); } switch ( slot->format ) { case FT_GLYPH_FORMAT_OUTLINE: /* translate the loaded glyph when an internal transform is needed */ if ( loader->transformed ) FT_Outline_Translate( &slot->outline, loader->trans_delta.x, loader->trans_delta.y ); /* compute original horizontal phantom points */ /* (and ignore vertical ones) */ loader->pp1.x = hints->x_delta; loader->pp1.y = hints->y_delta; loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance, hints->x_scale ) + hints->x_delta; loader->pp2.y = hints->y_delta; /* be sure to check for spacing glyphs */ if ( slot->outline.n_points == 0 ) goto Hint_Metrics; /* now load the slot image into the auto-outline */ /* and run the automatic hinting process */ if ( writing_system_class->style_hints_apply ) { error = writing_system_class->style_hints_apply( glyph_index, hints, &gloader->base.outline, style_metrics ); if ( error ) goto Exit; } /* we now need to adjust the metrics according to the change in */ /* width/positioning that occurred during the hinting process */ if ( scaler.render_mode != FT_RENDER_MODE_LIGHT ) { AF_AxisHints axis = &hints->axis[AF_DIMENSION_HORZ]; if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) ) { AF_Edge edge1 = axis->edges; /* leftmost edge */ AF_Edge edge2 = edge1 + axis->num_edges - 1; /* rightmost edge */ FT_Pos old_rsb = loader->pp2.x - edge2->opos; /* loader->pp1.x is always zero at this point of time */ FT_Pos old_lsb = edge1->opos; /* - loader->pp1.x */ FT_Pos new_lsb = edge1->pos; /* remember unhinted values to later account */ /* for rounding errors */ FT_Pos pp1x_uh = new_lsb - old_lsb; FT_Pos pp2x_uh = edge2->pos + old_rsb; /* prefer too much space over too little space */ /* for very small sizes */ if ( old_lsb < 24 ) pp1x_uh -= 8; if ( old_rsb < 24 ) pp2x_uh += 8; loader->pp1.x = FT_PIX_ROUND( pp1x_uh ); loader->pp2.x = FT_PIX_ROUND( pp2x_uh ); if ( loader->pp1.x >= new_lsb && old_lsb > 0 ) loader->pp1.x -= 64; if ( loader->pp2.x <= edge2->pos && old_rsb > 0 ) loader->pp2.x += 64; slot->lsb_delta = loader->pp1.x - pp1x_uh; slot->rsb_delta = loader->pp2.x - pp2x_uh; } else { FT_Pos pp1x = loader->pp1.x; FT_Pos pp2x = loader->pp2.x; loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta ); loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta ); slot->lsb_delta = loader->pp1.x - pp1x; slot->rsb_delta = loader->pp2.x - pp2x; } } /* `light' mode uses integer advance widths */ /* but sets `lsb_delta' and `rsb_delta' */ else { FT_Pos pp1x = loader->pp1.x; FT_Pos pp2x = loader->pp2.x; loader->pp1.x = FT_PIX_ROUND( pp1x ); loader->pp2.x = FT_PIX_ROUND( pp2x ); slot->lsb_delta = loader->pp1.x - pp1x; slot->rsb_delta = loader->pp2.x - pp2x; } break; default: /* we don't support other formats (yet?) */ error = FT_THROW( Unimplemented_Feature ); } Hint_Metrics: { FT_BBox bbox; FT_Vector vvector; vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX; vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY; vvector.x = FT_MulFix( vvector.x, style_metrics->scaler.x_scale ); vvector.y = FT_MulFix( vvector.y, style_metrics->scaler.y_scale ); /* transform the hinted outline if needed */ if ( loader->transformed ) { FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix ); FT_Vector_Transform( &vvector, &loader->trans_matrix ); } /* we must translate our final outline by -pp1.x and compute */ /* the new metrics */ if ( loader->pp1.x ) FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 ); FT_Outline_Get_CBox( &gloader->base.outline, &bbox ); bbox.xMin = FT_PIX_FLOOR( bbox.xMin ); bbox.yMin = FT_PIX_FLOOR( bbox.yMin ); bbox.xMax = FT_PIX_CEIL( bbox.xMax ); bbox.yMax = FT_PIX_CEIL( bbox.yMax ); slot->metrics.width = bbox.xMax - bbox.xMin; slot->metrics.height = bbox.yMax - bbox.yMin; slot->metrics.horiBearingX = bbox.xMin; slot->metrics.horiBearingY = bbox.yMax; slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x ); slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y ); /* for mono-width fonts (like Andale, Courier, etc.) we need */ /* to keep the original rounded advance width; ditto for */ /* digits if all have the same advance width */ if ( scaler.render_mode != FT_RENDER_MODE_LIGHT && ( FT_IS_FIXED_WIDTH( slot->face ) || ( af_face_globals_is_digit( loader->globals, glyph_index ) && style_metrics->digits_have_same_width ) ) ) { slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance, style_metrics->scaler.x_scale ); /* Set delta values to 0. Otherwise code that uses them is */ /* going to ruin the fixed advance width. */ slot->lsb_delta = 0; slot->rsb_delta = 0; } else { /* non-spacing glyphs must stay as-is */ if ( slot->metrics.horiAdvance ) slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; } slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance, style_metrics->scaler.y_scale ); slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance ); slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance ); slot->format = FT_GLYPH_FORMAT_OUTLINE; } Exit: return error; }
af_loader_load_glyph( AF_Module module, FT_Face face, FT_UInt gindex, FT_Int32 load_flags ) { FT_Error error; FT_Size size = face->size; AF_Loader loader = module->loader; AF_ScalerRec scaler; if ( !size ) return AF_Err_Invalid_Argument; FT_ZERO( &scaler ); scaler.face = face; scaler.x_scale = size->metrics.x_scale; scaler.x_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */ scaler.y_scale = size->metrics.y_scale; scaler.y_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */ scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags ); scaler.flags = 0; /* XXX: fix this */ error = af_loader_reset( module, face ); if ( !error ) { AF_ScriptMetrics metrics; FT_UInt options = 0; #ifdef FT_OPTION_AUTOFIT2 /* XXX: undocumented hook to activate the latin2 hinter */ if ( load_flags & ( 1UL << 20 ) ) options = 2; #endif error = af_face_globals_get_metrics( loader->globals, gindex, options, &metrics ); if ( !error ) { loader->metrics = metrics; if ( metrics->clazz->script_metrics_scale ) metrics->clazz->script_metrics_scale( metrics, &scaler ); else metrics->scaler = scaler; load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM; load_flags &= ~FT_LOAD_RENDER; if ( metrics->clazz->script_hints_init ) { error = metrics->clazz->script_hints_init( &loader->hints, metrics ); if ( error ) goto Exit; } error = af_loader_load_g( loader, &scaler, gindex, load_flags, 0 ); } } Exit: return error; }
cf2_blues_init( CF2_Blues blues, CF2_Font font ) { /* pointer to parsed font object */ CFF_Decoder* decoder = font->decoder; CF2_Fixed zoneHeight; CF2_Fixed maxZoneHeight = 0; CF2_Fixed csUnitsPerPixel; size_t numBlueValues; size_t numOtherBlues; size_t numFamilyBlues; size_t numFamilyOtherBlues; FT_Pos* blueValues; FT_Pos* otherBlues; FT_Pos* familyBlues; FT_Pos* familyOtherBlues; size_t i; CF2_Fixed emBoxBottom, emBoxTop; CF2_Int unitsPerEm = font->unitsPerEm; if ( unitsPerEm == 0 ) unitsPerEm = 1000; FT_ZERO( blues ); blues->scale = font->innerTransform.d; cf2_getBlueMetrics( decoder, &blues->blueScale, &blues->blueShift, &blues->blueFuzz ); cf2_getBlueValues( decoder, &numBlueValues, &blueValues ); cf2_getOtherBlues( decoder, &numOtherBlues, &otherBlues ); cf2_getFamilyBlues( decoder, &numFamilyBlues, &familyBlues ); cf2_getFamilyOtherBlues( decoder, &numFamilyOtherBlues, &familyOtherBlues ); /* * synthetic em box hint heuristic * * Apply this when ideographic dictionary (LanguageGroup 1) has no * real alignment zones. Adobe tools generate dummy zones at -250 and * 1100 for a 1000 unit em. Fonts with ICF-based alignment zones * should not enable the heuristic. When the heuristic is enabled, * the font's blue zones are ignored. * */ /* get em box from OS/2 typoAscender/Descender */ /* TODO: FreeType does not parse these metrics. Skip them for now. */ #if 0 FCM_getHorizontalLineMetrics( &e, font->font, &ascender, &descender, &linegap ); if ( ascender - descender == unitsPerEm ) { emBoxBottom = cf2_intToFixed( descender ); emBoxTop = cf2_intToFixed( ascender ); } else #endif { emBoxBottom = CF2_ICF_Bottom; emBoxTop = CF2_ICF_Top; } if ( cf2_getLanguageGroup( decoder ) == 1 && ( numBlueValues == 0 || ( numBlueValues == 4 && cf2_blueToFixed( blueValues[0] ) < emBoxBottom && cf2_blueToFixed( blueValues[1] ) < emBoxBottom && cf2_blueToFixed( blueValues[2] ) > emBoxTop && cf2_blueToFixed( blueValues[3] ) > emBoxTop ) ) ) { /* * Construct hint edges suitable for synthetic ghost hints at top * and bottom of em box. +-CF2_MIN_COUNTER allows for unhinted * features above or below the last hinted edge. This also gives a * net 1 pixel boost to the height of ideographic glyphs. * * Note: Adjust synthetic hints outward by epsilon (0x.0001) to * avoid interference. E.g., some fonts have real hints at * 880 and -120. */ blues->emBoxBottomEdge.csCoord = emBoxBottom - CF2_FIXED_EPSILON; blues->emBoxBottomEdge.dsCoord = cf2_fixedRound( FT_MulFix( blues->emBoxBottomEdge.csCoord, blues->scale ) ) - CF2_MIN_COUNTER; blues->emBoxBottomEdge.scale = blues->scale; blues->emBoxBottomEdge.flags = CF2_GhostBottom | CF2_Locked | CF2_Synthetic; blues->emBoxTopEdge.csCoord = emBoxTop + CF2_FIXED_EPSILON + 2 * font->darkenY; blues->emBoxTopEdge.dsCoord = cf2_fixedRound( FT_MulFix( blues->emBoxTopEdge.csCoord, blues->scale ) ) + CF2_MIN_COUNTER; blues->emBoxTopEdge.scale = blues->scale; blues->emBoxTopEdge.flags = CF2_GhostTop | CF2_Locked | CF2_Synthetic; blues->doEmBoxHints = TRUE; /* enable the heuristic */ return; } /* copy `BlueValues' and `OtherBlues' to a combined array of top and */ /* bottom zones */ for ( i = 0; i < numBlueValues; i += 2 ) { blues->zone[blues->count].csBottomEdge = cf2_blueToFixed( blueValues[i] ); blues->zone[blues->count].csTopEdge = cf2_blueToFixed( blueValues[i + 1] ); zoneHeight = blues->zone[blues->count].csTopEdge - blues->zone[blues->count].csBottomEdge; if ( zoneHeight < 0 ) { FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" )); continue; /* reject this zone */ } if ( zoneHeight > maxZoneHeight ) { /* take maximum before darkening adjustment */ /* so overshoot suppression point doesn't change */ maxZoneHeight = zoneHeight; } /* adjust both edges of top zone upward by twice darkening amount */ if ( i != 0 ) { blues->zone[blues->count].csTopEdge += 2 * font->darkenY; blues->zone[blues->count].csBottomEdge += 2 * font->darkenY; } /* first `BlueValue' is bottom zone; others are top */ if ( i == 0 ) { blues->zone[blues->count].bottomZone = TRUE; blues->zone[blues->count].csFlatEdge = blues->zone[blues->count].csTopEdge; } else { blues->zone[blues->count].bottomZone = FALSE; blues->zone[blues->count].csFlatEdge = blues->zone[blues->count].csBottomEdge; } blues->count += 1; } for ( i = 0; i < numOtherBlues; i += 2 ) { blues->zone[blues->count].csBottomEdge = cf2_blueToFixed( otherBlues[i] ); blues->zone[blues->count].csTopEdge = cf2_blueToFixed( otherBlues[i + 1] ); zoneHeight = blues->zone[blues->count].csTopEdge - blues->zone[blues->count].csBottomEdge; if ( zoneHeight < 0 ) { FT_TRACE4(( "cf2_blues_init: ignoring negative zone height\n" )); continue; /* reject this zone */ } if ( zoneHeight > maxZoneHeight ) { /* take maximum before darkening adjustment */ /* so overshoot suppression point doesn't change */ maxZoneHeight = zoneHeight; } /* Note: bottom zones are not adjusted for darkening amount */ /* all OtherBlues are bottom zone */ blues->zone[blues->count].bottomZone = TRUE; blues->zone[blues->count].csFlatEdge = blues->zone[blues->count].csTopEdge; blues->count += 1; } /* Adjust for FamilyBlues */ /* Search for the nearest flat edge in `FamilyBlues' or */ /* `FamilyOtherBlues'. According to the Black Book, any matching edge */ /* must be within one device pixel */ csUnitsPerPixel = FT_DivFix( cf2_intToFixed( 1 ), blues->scale ); /* loop on all zones in this font */ for ( i = 0; i < blues->count; i++ ) { size_t j; CF2_Fixed minDiff; CF2_Fixed flatFamilyEdge, diff; /* value for this font */ CF2_Fixed flatEdge = blues->zone[i].csFlatEdge; if ( blues->zone[i].bottomZone ) { /* In a bottom zone, the top edge is the flat edge. */ /* Search `FamilyOtherBlues' for bottom zones; look for closest */ /* Family edge that is within the one pixel threshold. */ minDiff = CF2_FIXED_MAX; for ( j = 0; j < numFamilyOtherBlues; j += 2 ) { /* top edge */ flatFamilyEdge = cf2_blueToFixed( familyOtherBlues[j + 1] ); diff = cf2_fixedAbs( flatEdge - flatFamilyEdge ); if ( diff < minDiff && diff < csUnitsPerPixel ) { blues->zone[i].csFlatEdge = flatFamilyEdge; minDiff = diff; if ( diff == 0 ) break; } } /* check the first member of FamilyBlues, which is a bottom zone */ if ( numFamilyBlues >= 2 ) { /* top edge */ flatFamilyEdge = cf2_blueToFixed( familyBlues[1] ); diff = cf2_fixedAbs( flatEdge - flatFamilyEdge ); if ( diff < minDiff && diff < csUnitsPerPixel ) blues->zone[i].csFlatEdge = flatFamilyEdge; } } else { /* In a top zone, the bottom edge is the flat edge. */ /* Search `FamilyBlues' for top zones; skip first zone, which is a */ /* bottom zone; look for closest Family edge that is within the */ /* one pixel threshold */ minDiff = CF2_FIXED_MAX; for ( j = 2; j < numFamilyBlues; j += 2 ) { /* bottom edge */ flatFamilyEdge = cf2_blueToFixed( familyBlues[j] ); /* adjust edges of top zone upward by twice darkening amount */ flatFamilyEdge += 2 * font->darkenY; /* bottom edge */ diff = cf2_fixedAbs( flatEdge - flatFamilyEdge ); if ( diff < minDiff && diff < csUnitsPerPixel ) { blues->zone[i].csFlatEdge = flatFamilyEdge; minDiff = diff; if ( diff == 0 ) break; } } } } /* TODO: enforce separation of zones, including BlueFuzz */ /* Adjust BlueScale; similar to AdjustBlueScale() in coretype */ /* `bcsetup.c'. */ if ( maxZoneHeight > 0 ) { if ( blues->blueScale > FT_DivFix( cf2_intToFixed( 1 ), maxZoneHeight ) ) { /* clamp at maximum scale */ blues->blueScale = FT_DivFix( cf2_intToFixed( 1 ), maxZoneHeight ); } /* * TODO: Revisit the bug fix for 613448. The minimum scale * requirement catches a number of library fonts. For * example, with default BlueScale (.039625) and 0.4 minimum, * the test below catches any font with maxZoneHeight < 10.1. * There are library fonts ranging from 2 to 10 that get * caught, including e.g., Eurostile LT Std Medium with * maxZoneHeight of 6. * */ #if 0 if ( blueScale < .4 / maxZoneHeight ) { tetraphilia_assert( 0 ); /* clamp at minimum scale, per bug 0613448 fix */ blueScale = .4 / maxZoneHeight; } #endif } /* * Suppress overshoot and boost blue zones at small sizes. Boost * amount varies linearly from 0.5 pixel near 0 to 0 pixel at * blueScale cutoff. * Note: This boost amount is different from the coretype heuristic. * */ if ( blues->scale < blues->blueScale ) { blues->suppressOvershoot = TRUE; /* Change rounding threshold for `dsFlatEdge'. */ /* Note: constant changed from 0.5 to 0.6 to avoid a problem with */ /* 10ppem Arial */ blues->boost = FT_MulFix( cf2_floatToFixed( .6 ), ( cf2_intToFixed( 1 ) - FT_DivFix( blues->scale, blues->blueScale ) ) ); if ( blues->boost > 0x7FFF ) { /* boost must remain less than 0.5, or baseline could go negative */ blues->boost = 0x7FFF; } } /* boost and darkening have similar effects; don't do both */ if ( font->stemDarkened ) blues->boost = 0; /* set device space alignment for each zone; */ /* apply boost amount before rounding flat edge */ for ( i = 0; i < blues->count; i++ ) { if ( blues->zone[i].bottomZone ) blues->zone[i].dsFlatEdge = cf2_fixedRound( FT_MulFix( blues->zone[i].csFlatEdge, blues->scale ) - blues->boost ); else blues->zone[i].dsFlatEdge = cf2_fixedRound( FT_MulFix( blues->zone[i].csFlatEdge, blues->scale ) + blues->boost ); } }