541 lines
15 KiB
C
541 lines
15 KiB
C
/****************************************************************************/
|
|
/* */
|
|
/* The FreeType project -- a free and portable quality TrueType renderer. */
|
|
/* */
|
|
/* Copyright 1996-1999 by */
|
|
/* D. Turner, R.Wilhelm, and W. Lemberg */
|
|
/* */
|
|
/* ftview: A simple font viewer. Now supports hinting and grayscaling */
|
|
/* with the '-g' option. */
|
|
/* */
|
|
/* */
|
|
/* Keys: */
|
|
/* */
|
|
/* x : fine counter-clockwise rotation */
|
|
/* c : fine clockwise rotation */
|
|
/* */
|
|
/* v : fast counter-clockwise rotation */
|
|
/* b : fast clockwise rotation */
|
|
/* */
|
|
/* + : fast scale up */
|
|
/* - : fast scale down */
|
|
/* u : fine scale down */
|
|
/* j : fine scale up */
|
|
/* */
|
|
/* l : go to next glyph */
|
|
/* k : go to previous glyph */
|
|
/* */
|
|
/* o : go to tenth next glyph */
|
|
/* i : go to tenth previous glyph */
|
|
/* */
|
|
/* 0 : go to hundredth next glyph */
|
|
/* 9 : go to hundredth previous glyph */
|
|
/* */
|
|
/* ) : go to 1000th next glyph */
|
|
/* ( : go to 1000th previous glyph */
|
|
/* */
|
|
/* } : go to 10000th next glyph */
|
|
/* { : go to 10000th previous glyph */
|
|
/* */
|
|
/* n : go to next (or last) .ttf file */
|
|
/* p : go to previous (or first) .ttf file */
|
|
/* */
|
|
/* h : toggle hinting */
|
|
/* */
|
|
/* B : toggle sbit */
|
|
/* */
|
|
/* ESC : exit */
|
|
/* */
|
|
/* */
|
|
/* NOTE: This is just a test program that is used to show off and */
|
|
/* debug the current engine. */
|
|
/* */
|
|
/****************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "blitter.h"
|
|
#include "common.h" /* for Panic() only */
|
|
#include "display.h"
|
|
#include "freetype.h"
|
|
#include "ftxsbit.h"
|
|
|
|
#include "gdriver.h"
|
|
#include "gevents.h"
|
|
#include "gmain.h"
|
|
|
|
#define Pi 3.1415926535
|
|
|
|
#define MAXPTSIZE 500 /* dtp */
|
|
#define Center_X ( Bit.width / 2 ) /* dtp */
|
|
#define Center_Y ( Bit.rows / 2 ) /* dtp */
|
|
|
|
/*
|
|
* If Ignore_Err_Not_SBit is not defined,
|
|
* "Fail" increase when the glyph does not have sbit and
|
|
* sbit_flag is 1.
|
|
*/
|
|
#define Ignore_Err_Not_SBit 1
|
|
|
|
char Header[128];
|
|
|
|
TT_Engine engine;
|
|
|
|
TT_Face face;
|
|
TT_Instance instance;
|
|
TT_Glyph glyph;
|
|
TT_CharMap char_map;
|
|
|
|
TT_Big_Glyph_Metrics metrics;
|
|
TT_Outline outline;
|
|
TT_Face_Properties properties;
|
|
TT_Instance_Metrics imetrics;
|
|
|
|
TT_SBit_Image* sbit;
|
|
|
|
int num_glyphs;
|
|
|
|
int ptsize;
|
|
int hinted;
|
|
|
|
int Rotation;
|
|
int Fail;
|
|
int Num;
|
|
unsigned char autorun;
|
|
|
|
int gray_render;
|
|
unsigned int sbit_flag; /* 0 if to display outlines
|
|
* 1 if to use embedded bitmaps
|
|
* 2 if to show sbit and outline glyphs
|
|
*/
|
|
|
|
int glyph_has_sbit;
|
|
|
|
|
|
|
|
static TT_Error Reset_Scale( int pointSize )
|
|
{
|
|
TT_Error error;
|
|
TT_SBit_Strike strike;
|
|
|
|
if ( (error = TT_Set_Instance_PointSize( instance, pointSize )) )
|
|
{
|
|
RestoreScreen();
|
|
fprintf( stderr, "Error = 0x%x.\n", (int)error );
|
|
Panic( "Could not reset instance.\n" );
|
|
}
|
|
TT_Get_Instance_Metrics( instance, &imetrics );
|
|
|
|
/* now re-allocates the small bitmap */
|
|
if ( gray_render )
|
|
{
|
|
Init_Small( imetrics.x_ppem, imetrics.y_ppem );
|
|
Clear_Small();
|
|
}
|
|
|
|
if ( TT_Get_SBit_Strike( face, instance, &strike ) )
|
|
glyph_has_sbit = 0;
|
|
else
|
|
glyph_has_sbit = 1;
|
|
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
|
|
static TT_Error LoadTrueTypeChar( int idx,
|
|
int hint )
|
|
{
|
|
int flags;
|
|
|
|
|
|
flags = TTLOAD_SCALE_GLYPH;
|
|
if ( hint )
|
|
flags |= TTLOAD_HINT_GLYPH;
|
|
|
|
return TT_Load_Glyph( instance, glyph, idx, flags );
|
|
}
|
|
|
|
|
|
static TT_Error Render_All( int first_glyph,
|
|
int ptsize )
|
|
{
|
|
TT_F26Dot6 start_x, start_y, step_x, step_y, x, y;
|
|
int i;
|
|
|
|
TT_Error error = 0;
|
|
|
|
|
|
start_x = 4;
|
|
start_y = vio_Height - ( ( ptsize * 96 + 36 ) / 72 + 10 );
|
|
|
|
step_x = imetrics.x_ppem + 4;
|
|
step_y = imetrics.y_ppem + 10;
|
|
|
|
x = start_x;
|
|
y = start_y;
|
|
|
|
i = first_glyph;
|
|
|
|
while ( i < num_glyphs )
|
|
{
|
|
if ( ( glyph_has_sbit ) &&
|
|
( ( sbit_flag + 1 ) & 2 ) &&
|
|
!(error = TT_Load_Glyph_Bitmap( face, instance, i, sbit )) )
|
|
{
|
|
Blit_Bitmap( &Bit,
|
|
&sbit->map,
|
|
gray_render ? 8 : 1,
|
|
x + (sbit->metrics.horiBearingX/64),
|
|
Bit.rows - y - (sbit->metrics.horiBearingY/64),
|
|
gray_palette[4] );
|
|
metrics = sbit->metrics;
|
|
goto Step;
|
|
}
|
|
|
|
if ( ( ( !glyph_has_sbit ) ||
|
|
( ( sbit_flag + 1 ) & 1 ) ) &&
|
|
!(error = LoadTrueTypeChar( i, hinted )) )
|
|
{
|
|
TT_Get_Glyph_Outline( glyph, &outline );
|
|
TT_Get_Glyph_Big_Metrics( glyph, &metrics );
|
|
|
|
Render_Single_Glyph( gray_render, glyph, x, y );
|
|
}
|
|
else
|
|
{
|
|
#ifdef Ignore_Err_Not_SBit
|
|
if (!(( glyph_has_sbit ) &&
|
|
( sbit_flag == 1 ) &&
|
|
( error == TT_Err_Invalid_Glyph_Index )))
|
|
#endif
|
|
Fail++;
|
|
}
|
|
Step:
|
|
x += ( metrics.horiAdvance / 64 ) + 1;
|
|
|
|
if ( x + imetrics.x_ppem > vio_Width )
|
|
{
|
|
x = start_x;
|
|
y -= step_y;
|
|
|
|
if ( y < 10 )
|
|
return TT_Err_Ok;
|
|
}
|
|
i++;
|
|
}
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
|
|
static int Process_Event( TEvent* event )
|
|
{
|
|
switch ( event->what )
|
|
{
|
|
case event_Quit: /* ESC or q */
|
|
return 0;
|
|
|
|
case event_Keyboard:
|
|
if ( event->info == 'n' ) /* Next file */
|
|
return 'n';
|
|
if ( event->info == 'p' ) /* Previous file */
|
|
return 'p';
|
|
if ( event->info == 'h' ) /* Toggle hinting */
|
|
hinted = !hinted;
|
|
if ( ( event->info == 'B' ) && ( glyph_has_sbit ) ) /* Toggle sbit */
|
|
sbit_flag = ( sbit_flag + 1 ) % 3;
|
|
break;
|
|
|
|
case event_Rotate_Glyph:
|
|
Rotation = ( Rotation + event->info ) & 1023;
|
|
break;
|
|
|
|
case event_Scale_Glyph:
|
|
ptsize += event->info;
|
|
if ( ptsize < 1 ) ptsize = 1;
|
|
if ( ptsize > MAXPTSIZE ) ptsize = MAXPTSIZE;
|
|
break;
|
|
|
|
case event_Change_Glyph:
|
|
Num += event->info;
|
|
if ( Num < 0 ) Num = 0;
|
|
if ( Num >= num_glyphs ) Num = num_glyphs - 1;
|
|
break;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static void usage( char* execname )
|
|
{
|
|
fprintf( stderr, "\n" );
|
|
fprintf( stderr, "ftview: simple TrueType interpreter tester -- part of the FreeType project\n" );
|
|
fprintf( stderr, "--------------------------------------------------------------------------\n" );
|
|
fprintf( stderr, "\n" );
|
|
fprintf( stderr, "Usage: %s [options below] ppem fontname[.ttf|.ttc] ...\n",
|
|
execname );
|
|
fprintf( stderr, "\n" );
|
|
fprintf( stderr, " -g gray-level rendering (default: none)\n" );
|
|
fprintf( stderr, " -r R use resolution R dpi (default: 96)\n" );
|
|
fprintf( stderr, " -B use embedded bitmaps (default: none)\n" );
|
|
fprintf( stderr, "\n" );
|
|
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
|
|
|
|
int main( int argc,
|
|
char** argv )
|
|
{
|
|
int i, old_ptsize, orig_ptsize, file;
|
|
int XisSetup = 0;
|
|
char filename[128 + 4];
|
|
char alt_filename[128 + 4];
|
|
char* execname;
|
|
int option;
|
|
int res = 96;
|
|
|
|
TT_Error error;
|
|
TEvent event;
|
|
|
|
TT_EBLC eblc_table;
|
|
|
|
|
|
execname = ft_basename( argv[0] );
|
|
|
|
while ( 1 )
|
|
{
|
|
option = ft_getopt( argc, argv, "gr:B" );
|
|
|
|
if ( option == -1 )
|
|
break;
|
|
|
|
switch ( option )
|
|
{
|
|
case 'g':
|
|
gray_render = 1;
|
|
sbit_flag = 0;
|
|
break;
|
|
|
|
case 'r':
|
|
res = atoi( ft_optarg );
|
|
if ( res < 1 )
|
|
usage( execname );
|
|
break;
|
|
|
|
case 'B':
|
|
if (!gray_render)
|
|
#if 0
|
|
sbit_flag = 1;
|
|
#else
|
|
sbit_flag = 2;
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
usage( execname );
|
|
break;
|
|
}
|
|
}
|
|
|
|
argc -= ft_optind;
|
|
argv += ft_optind;
|
|
|
|
if ( argc <= 1 )
|
|
usage( execname );
|
|
|
|
if ( sscanf( argv[0], "%d", &orig_ptsize ) != 1 )
|
|
orig_ptsize = 64;
|
|
|
|
file = 1;
|
|
|
|
/* Initialize engine */
|
|
|
|
if ( (error = TT_Init_FreeType( &engine )) )
|
|
Panic( "Error while initializing engine, code = 0x%x.\n", error );
|
|
|
|
if ( (error = TT_Init_SBit_Extension( engine )) )
|
|
Panic( "Error while initializing sbit extention, code = 0x%x.\n", error );
|
|
|
|
NewFile:
|
|
ptsize = orig_ptsize;
|
|
hinted = 1;
|
|
|
|
i = strlen( argv[file] );
|
|
while ( i > 0 && argv[file][i] != '\\' && argv[file][i] != '/' )
|
|
{
|
|
if ( argv[file][i] == '.' )
|
|
i = 0;
|
|
i--;
|
|
}
|
|
|
|
filename[128] = '\0';
|
|
alt_filename[128] = '\0';
|
|
|
|
strncpy( filename, argv[file], 128 );
|
|
strncpy( alt_filename, argv[file], 128 );
|
|
|
|
if ( i >= 0 )
|
|
{
|
|
strncpy( filename + strlen( filename ), ".ttf", 4 );
|
|
strncpy( alt_filename + strlen( alt_filename ), ".ttc", 4 );
|
|
}
|
|
|
|
/* Load face */
|
|
|
|
error = TT_Open_Face( engine, filename, &face );
|
|
|
|
if ( error == TT_Err_Could_Not_Open_File )
|
|
{
|
|
strcpy( filename, alt_filename );
|
|
error = TT_Open_Face( engine, alt_filename, &face );
|
|
}
|
|
|
|
if ( error == TT_Err_Could_Not_Open_File )
|
|
Panic( "Could not find/open %s.\n", filename );
|
|
else if ( error )
|
|
Panic( "Error while opening %s, code = 0x%x.\n", filename, error );
|
|
|
|
/* get face properties and allocate preload arrays */
|
|
|
|
TT_Get_Face_Properties( face, &properties );
|
|
|
|
num_glyphs = properties.num_Glyphs;
|
|
|
|
glyph_has_sbit = 0;
|
|
|
|
error = TT_Get_Face_Bitmaps( face, &eblc_table );
|
|
if ( error == TT_Err_Ok )
|
|
glyph_has_sbit = 1;
|
|
if ( sbit_flag && !glyph_has_sbit )
|
|
Panic( "%s does not have embedded bitmap glyphs.\n", filename );
|
|
|
|
/* create glyph */
|
|
|
|
error = TT_New_Glyph( face, &glyph );
|
|
if ( error )
|
|
Panic( "Could not create glyph container.\n" );
|
|
|
|
error = TT_New_SBit_Image( &sbit );
|
|
if ( error )
|
|
Panic( "Could not create sbit slot.\n" );
|
|
|
|
/* create instance */
|
|
|
|
error = TT_New_Instance( face, &instance );
|
|
if ( error )
|
|
Panic( "Could not create instance for %s.\n", filename );
|
|
|
|
error = TT_Set_Instance_Resolutions( instance, res, res );
|
|
if ( error )
|
|
Panic( "Could not set device resolutions." );
|
|
|
|
if ( !XisSetup )
|
|
{
|
|
XisSetup = 1;
|
|
|
|
if ( gray_render )
|
|
{
|
|
if ( !SetGraphScreen( Graphics_Mode_Gray ) )
|
|
Panic( "Could not set up grayscale graphics mode.\n" );
|
|
|
|
TT_Set_Raster_Gray_Palette( engine, virtual_palette );
|
|
}
|
|
else
|
|
{
|
|
if ( !SetGraphScreen( Graphics_Mode_Mono ) )
|
|
Panic( "Could not set up mono graphics mode.\n" );
|
|
}
|
|
}
|
|
|
|
Init_Display( gray_render );
|
|
|
|
Reset_Scale( ptsize );
|
|
|
|
old_ptsize = ptsize;
|
|
|
|
Fail = 0;
|
|
Num = 0;
|
|
|
|
for ( ;; )
|
|
{
|
|
int key;
|
|
char* sbit_string;
|
|
static char* sbit_messages[4] =
|
|
{ "off", "on", " if available", "NONE" };
|
|
|
|
sbit_string = sbit_messages[3];
|
|
if ( glyph_has_sbit )
|
|
{
|
|
if (sbit_flag >= 0 && sbit_flag < 3)
|
|
sbit_string = sbit_messages[sbit_flag];
|
|
}
|
|
|
|
Clear_Display();
|
|
Render_All( Num, ptsize );
|
|
if ( gray_render )
|
|
Convert_To_Display_Palette();
|
|
|
|
sprintf( Header, "%s: Glyph: %4d ptsize: %4d hinting: %s sbit: %s",
|
|
ft_basename( filename ), Num, ptsize,
|
|
hinted ? "on" : "off",
|
|
sbit_string );
|
|
Display_Bitmap_On_Screen( Bit.bitmap, Bit.rows, Bit.cols );
|
|
|
|
#ifndef X11
|
|
#ifndef OS2
|
|
Print_XY( 0, 0, Header );
|
|
#endif
|
|
#endif
|
|
|
|
Get_Event( &event );
|
|
if ( !( key = Process_Event( &event ) ) )
|
|
goto End;
|
|
|
|
if ( key == 'n' )
|
|
{
|
|
TT_Close_Face( face );
|
|
|
|
if ( file < argc - 1 )
|
|
file++;
|
|
|
|
goto NewFile;
|
|
}
|
|
|
|
if ( key == 'p' )
|
|
{
|
|
TT_Close_Face( face );
|
|
|
|
if ( file > 1 )
|
|
file--;
|
|
|
|
goto NewFile;
|
|
}
|
|
|
|
if ( ptsize != old_ptsize )
|
|
{
|
|
if ( Reset_Scale( ptsize ) )
|
|
Panic( "Could not resize font.\n" );
|
|
|
|
old_ptsize = ptsize;
|
|
}
|
|
}
|
|
|
|
End:
|
|
RestoreScreen();
|
|
|
|
TT_Done_FreeType( engine );
|
|
|
|
printf( "Execution completed successfully.\n" );
|
|
printf( "Fails = %d\n", Fail );
|
|
|
|
exit( EXIT_SUCCESS ); /* for safety reasons */
|
|
|
|
return 0; /* never reached */
|
|
}
|
|
|
|
|
|
/* End */
|