/****************************************************************************/ /* */ /* The FreeType project -- a free and portable quality font engine */ /* */ /* Copyright 1996-2011 by A. Leca, */ /* D. Turner, R. Wilhelm, and W. Lemberg */ /* */ /* ftchkadv: test FT_Get_Advance. This program compares the advances */ /* computed in various ways for all the glyphs of a given font. */ /* */ /* NOTE: This is just a test program that is used to debug the */ /* current engine. */ /* */ /****************************************************************************/ #include #include FT_FREETYPE_H #include FT_ADVANCES_H #include #include #include #include "common.h" #define gettext( x ) ( x ) FT_Error error; FT_Library library; FT_Face face; FT_Size size; FT_GlyphSlot slot; int check_advance_x = 0; unsigned int first_index = 0; FT_Int32 load_flags = FT_LOAD_DEFAULT; FT_Fixed* advances; unsigned int num_glyphs; int ptsize; int Fail; int Num; FT_Fixed NoRoundFix( FT_Fixed a ) { return a; } /* By default, do not round. */ /* FT_RoundFix, FT_CeilFix, or FT_FloorFix are valid alternates. */ FT_Fixed (*roundFix_func)( FT_Fixed ) = NoRoundFix; static void Usage( char* name ) { printf( "ftchkadv: FT_Get_Advance tester -- part of the FreeType project\n" ); printf( "---------------------------------------------------------------\n" ); printf( "\n" ); printf( "Usage: %s [options] ppem fontname[.ttf|.ttc] [fontname2..]\n", name ); fprintf( stderr, "options:\n"); fprintf( stderr, " -a : check advance.x instead of linearHoriAdvance\n" " -f HHHH : load flags (hexadecimal)\n" " -i NNN : first index to start with (default is 0)\n" " -r : rounds advances before comparison\n"); printf( "\n" ); exit( 1 ); } static void Panic( const char* message ) { fprintf( stderr, "%s\n error code = 0x%04x\n", message, error ); exit(1); } int main( int argc, char** argv ) { int i, file_index; unsigned int id; char filename[128 + 4]; char alt_filename[128 + 4]; char* execname; char* fname; FT_Fixed advance; execname = argv[0]; while ( 1 ) { int opt; opt = getopt( argc, argv, "af:i:r" ); if ( opt == -1 ) break; switch ( opt ) { case 'a': check_advance_x = 1; break; case 'f': load_flags = strtol( optarg, NULL, 16 ); break; case 'i': first_index = atoi( optarg ); break; case 'r': roundFix_func = FT_RoundFix; break; default: Usage( execname ); break; } } argc -= optind; argv += optind; if ( argc < 2 ) Usage( execname ); if ( sscanf( argv[0], "%d", &ptsize ) != 1 ) Usage( execname ); error = FT_Init_FreeType( &library ); if (error) Panic( "Could not create library object" ); /* Now check all files */ for ( file_index = 1; file_index < argc; file_index++ ) { fname = argv[file_index]; /* try to open the file with no extra extension first */ error = FT_New_Face( library, fname, 0, &face ); if (!error) { printf( "%s: ", fname ); goto Success; } if ( error == FT_Err_Unknown_File_Format ) { printf( "unknown format\n" ); continue; } /* ok, we could not load the file, try to add an extension to */ /* its name if possible.. */ i = strlen( fname ); while ( i > 0 && fname[i] != '\\' && fname[i] != '/' ) { if ( fname[i] == '.' ) i = 0; i--; } filename[128] = '\0'; alt_filename[128] = '\0'; strncpy( filename, fname, 128 ); strncpy( alt_filename, fname, 128 ); #ifndef macintosh if ( i >= 0 ) { strncpy( filename + strlen( filename ), ".ttf", 4 ); strncpy( alt_filename + strlen( alt_filename ), ".ttc", 4 ); } #endif i = strlen( filename ); fname = filename; while ( i >= 0 ) #ifndef macintosh if ( filename[i] == '/' || filename[i] == '\\' ) #else if ( filename[i] == ':' ) #endif { fname = filename + i + 1; i = -1; } else i--; printf( "%s: ", fname ); /* Load face */ error = FT_New_Face( library, filename, 0, &face ); if (error) { if (error == FT_Err_Unknown_File_Format) printf( "unknown format\n" ); else printf( "could not find/open file (error: %d)\n", error ); continue; } if (error) Panic( "Could not open file" ); Success: num_glyphs = face->num_glyphs; if ( !check_advance_x && load_flags & FT_LOAD_NO_SCALE && FT_IS_SCALABLE(face) && face->units_per_EM != ptsize ) { printf( "unscaled values, design EM=%d != %d!!! ", face->units_per_EM, ptsize ); } error = FT_Set_Char_Size( face, ptsize << 6, ptsize << 6, 72, 72 ); if (error) Panic( "Could not set character size" ); advances = (FT_Fixed *)calloc( sizeof ( FT_Fixed ), num_glyphs ); if (!advances) Panic( "Out of memory" ); error = FT_Get_Advances( face, first_index, num_glyphs - first_index, FT_ADVANCE_FLAG_FAST_ONLY|load_flags, advances ); if (error) { if ( error == FT_Err_Unimplemented_Feature ) { printf( "(no fast-computed advances) " ); error = FT_Get_Advances( face, first_index, num_glyphs - first_index, load_flags, advances ); } if ( error ) { printf( "FT_Get_Advances failed 0x%04x\n" , error ); goto Done; } } Fail = 0; for ( id = 0; id < num_glyphs - first_index; id++ ) { error = FT_Load_Glyph( face, id + first_index, load_flags ); if (error) { if ( Fail < 10 ) printf( "glyph %4u: fail to load 0x%04x\n" , id, error ); Fail++; } else { if ( check_advance_x ) { advance = ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) ? (FT_Fixed)face->glyph->advance.y : (FT_Fixed)face->glyph->advance.x; if ( load_flags & FT_LOAD_NO_SCALE ) { /* Glyph advance is in font units, advances also :-) */ } else { /* Glyph advance is in FUnit (26.6), advances are in 16.16 */ advance <<= (16 - 6); } } else { advance = ( load_flags & FT_LOAD_VERTICAL_LAYOUT ) ? (FT_Fixed)face->glyph->linearVertAdvance : (FT_Fixed)face->glyph->linearHoriAdvance; if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) { /* Glyph linear advance is in 16.16, advances also :-) */ } else { /* advances are unscaled in font units, while glyph linear */ /* advance is scaled in 16.16... The requested size better */ /* have to be the same as the design EM size! */ /* Should we round before loosing precision? */ advance = advance >> 16; } } /* Note that if hinted, glyph->advance is grid-fitted, so will */ /* not match the value returned by FT_Get_Advance unless rounded. */ if ( roundFix_func(advance) != roundFix_func(advances[id]) ) { if ( Fail < 10 ) printf( "glyph %4u: Load_Glyph->->%s: %x.%04x != Get_Advance: %x.%04x\n" , id + first_index, check_advance_x ? "advance" : "linearAdv", advance >> 16, (advance & 0xFFFF), advances[id] >> 16, (advances[id] & 0xFFFF) ); Fail++; } } } if ( Fail == 0 ) printf( "OK.\n" ); else if ( Fail == 1 ) printf( "1 fail.\n" ); else printf( "%d fails.\n", Fail ); Done: free( advances ); FT_Done_Face( face ); } FT_Done_FreeType(library); exit( 0 ); /* for safety reasons */ return 0; /* never reached */ } /* End */