2000-05-28 19:15:37 +02:00
|
|
|
/****************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* The FreeType project -- a free and portable quality TrueType renderer. */
|
|
|
|
/* */
|
2000-05-30 07:13:30 +02:00
|
|
|
/* Copyright 1996-2000 by */
|
2000-05-28 19:15:37 +02:00
|
|
|
/* D. Turner, R.Wilhelm, and W. Lemberg */
|
|
|
|
/* */
|
|
|
|
/* */
|
|
|
|
/* FTMulti- a simple multiple masters font viewer */
|
|
|
|
/* */
|
|
|
|
/* Press F1 when running this program to have a list of key-bindings */
|
|
|
|
/* */
|
|
|
|
/****************************************************************************/
|
|
|
|
|
|
|
|
#include <freetype/freetype.h>
|
|
|
|
#include <freetype/ftraster.h>
|
|
|
|
#include <freetype/ftgrays.h>
|
|
|
|
#include <freetype/ftmm.h>
|
|
|
|
|
|
|
|
#include "common.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
|
|
#include "graph.h"
|
|
|
|
#include "grfont.h"
|
|
|
|
|
|
|
|
#define DIM_X 500
|
|
|
|
#define DIM_Y 400
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
#define CENTER_X ( bit.width / 2 )
|
|
|
|
#define CENTER_Y ( bit.rows / 2 )
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
#define MAXPTSIZE 500 /* dtp */
|
|
|
|
|
|
|
|
char Header[128];
|
|
|
|
char* new_header = 0;
|
|
|
|
|
|
|
|
const unsigned char* Text = (unsigned char*)
|
2000-05-30 07:13:30 +02:00
|
|
|
"The quick brown fox jumped over the lazy dog 0123456789 "
|
|
|
|
"\342\352\356\373\364\344\353\357\366\374\377\340\371\351\350\347 "
|
|
|
|
"&#~\"\'(-`_^@)=+\260 ABCDEFGHIJKLMNOPQRSTUVWXYZ "
|
|
|
|
"$\243^\250*\265\371%!\247:/;.,?<>";
|
2000-05-28 19:15:37 +02:00
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
FT_Library library; /* the FreeType library */
|
|
|
|
FT_Face face; /* the font face */
|
|
|
|
FT_Size size; /* the font size */
|
|
|
|
FT_GlyphSlot glyph; /* the glyph slot */
|
2000-05-28 19:15:37 +02:00
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
FT_Error error; /* error returned by FreeType? */
|
|
|
|
|
|
|
|
grSurface* surface; /* current display surface */
|
|
|
|
grBitmap bit; /* current display bitmap */
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
int num_glyphs; /* number of glyphs */
|
|
|
|
int ptsize; /* current point size */
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
int hinted = 1; /* is glyph hinting active? */
|
|
|
|
int antialias = 1; /* is anti-aliasing active? */
|
|
|
|
int use_sbits = 1; /* do we use embedded bitmaps? */
|
|
|
|
int low_prec = 0; /* force low precision */
|
|
|
|
int Num; /* current first glyph index */
|
2000-05-28 19:15:37 +02:00
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
int res = 72;
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
static grColor fore_color = { 255 };
|
|
|
|
|
|
|
|
int Fail;
|
|
|
|
unsigned char autorun;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
int graph_init = 0;
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
int render_mode = 1;
|
|
|
|
int use_grays = 1;
|
|
|
|
|
|
|
|
/* the standard raster's interface */
|
|
|
|
FT_Raster_Funcs std_raster;
|
|
|
|
|
|
|
|
FT_Multi_Master multimaster;
|
2000-05-30 07:13:30 +02:00
|
|
|
FT_Long design_pos[T1_MAX_MM_AXIS];
|
2000-05-28 19:15:37 +02:00
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
#define RASTER_BUFF_SIZE 32768
|
|
|
|
char raster_buff[RASTER_BUFF_SIZE];
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
#define DEBUGxxx
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2000-05-30 07:13:30 +02:00
|
|
|
#define LOG( x ) LogMessage##x
|
2000-05-28 19:15:37 +02:00
|
|
|
#else
|
2000-05-30 07:13:30 +02:00
|
|
|
#define LOG( x ) /* empty */
|
2000-05-28 19:15:37 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2000-05-30 07:13:30 +02:00
|
|
|
static
|
|
|
|
void LogMessage( const char* fmt, ... )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
|
2000-05-28 19:15:37 +02:00
|
|
|
va_start( ap, fmt );
|
|
|
|
vfprintf( stderr, fmt, ap );
|
|
|
|
va_end( ap );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
|
2000-05-28 19:15:37 +02:00
|
|
|
/* PanicZ */
|
2000-05-30 07:13:30 +02:00
|
|
|
static
|
|
|
|
void PanicZ( const char* message )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
|
|
|
fprintf( stderr, "%s\n error = 0x%04x\n", message, error );
|
2000-05-30 07:13:30 +02:00
|
|
|
exit( 1 );
|
2000-05-28 19:15:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Clears the Bit bitmap/pixmap */
|
2000-05-30 07:13:30 +02:00
|
|
|
static
|
|
|
|
void Clear_Display( void )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
|
|
|
long size = (long)bit.pitch * bit.rows;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
|
|
|
|
if ( size < 0 )
|
|
|
|
size = -size;
|
2000-05-28 19:15:37 +02:00
|
|
|
memset( bit.buffer, 0, size );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
/* Initialize the display bitmap named `bit' */
|
|
|
|
static
|
|
|
|
void Init_Display( void )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
|
|
|
grInitDevices();
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
bit.mode = gr_pixel_mode_gray;
|
|
|
|
bit.width = DIM_X;
|
|
|
|
bit.rows = DIM_Y;
|
|
|
|
bit.grays = 256;
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
surface = grNewSurface( 0, &bit );
|
2000-05-30 07:13:30 +02:00
|
|
|
if ( !surface )
|
2000-05-28 19:15:37 +02:00
|
|
|
PanicZ( "could not allocate display surface\n" );
|
|
|
|
|
|
|
|
graph_init = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define MAX_BUFFER 300000
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
#define FLOOR( x ) ( (x) & -64 )
|
|
|
|
#define CEIL( x ) ( ( (x) + 63 ) & -64 )
|
|
|
|
#define TRUNC( x ) ( (x) >> 6 )
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
static
|
2000-05-30 07:13:30 +02:00
|
|
|
char bit_buffer[MAX_BUFFER];
|
|
|
|
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
/* Render a single glyph with the "grays" component */
|
2000-05-30 07:13:30 +02:00
|
|
|
static
|
|
|
|
FT_Error Render_Glyph( int x_offset,
|
|
|
|
int y_offset )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
|
|
|
FT_Bitmap bit2;
|
|
|
|
grBitmap bit3;
|
|
|
|
int width, height, pitch, size;
|
|
|
|
int left, right, top, bottom;
|
|
|
|
int x_top, y_top;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
/* first, render the glyph into an intermediate buffer */
|
|
|
|
|
2000-05-28 19:15:37 +02:00
|
|
|
left = FLOOR( glyph->metrics.horiBearingX );
|
|
|
|
right = CEIL( glyph->metrics.horiBearingX + glyph->metrics.width );
|
2000-05-30 07:13:30 +02:00
|
|
|
width = TRUNC( right - left );
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
top = CEIL( glyph->metrics.horiBearingY );
|
|
|
|
bottom = FLOOR( glyph->metrics.horiBearingY - glyph->metrics.height );
|
|
|
|
height = TRUNC( top - bottom );
|
|
|
|
|
|
|
|
if ( glyph->format == ft_glyph_format_outline )
|
|
|
|
{
|
2000-05-30 07:13:30 +02:00
|
|
|
pitch = antialias ? ( width + 3 ) & -4
|
|
|
|
: ( width + 7 ) >> 3;
|
|
|
|
size = pitch * height;
|
2000-05-28 19:15:37 +02:00
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
if ( size > MAX_BUFFER )
|
2000-05-28 19:15:37 +02:00
|
|
|
return FT_Err_Out_Of_Memory;
|
|
|
|
|
|
|
|
bit2.width = width;
|
|
|
|
bit2.rows = height;
|
|
|
|
bit2.pitch = pitch;
|
|
|
|
bit2.pixel_mode = antialias ? ft_pixel_mode_grays : ft_pixel_mode_mono;
|
|
|
|
bit2.buffer = bit_buffer;
|
|
|
|
|
|
|
|
bit3.rows = bit2.rows;
|
|
|
|
bit3.width = bit2.width;
|
|
|
|
bit3.pitch = bit2.pitch;
|
|
|
|
bit3.mode = antialias ? bit.mode : gr_pixel_mode_mono;
|
|
|
|
bit3.buffer = bit_buffer;
|
|
|
|
bit3.grays = 256;
|
|
|
|
|
|
|
|
FT_Outline_Translate( &glyph->outline, -left, -bottom );
|
|
|
|
memset( bit_buffer, 0, size );
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
if ( low_prec )
|
2000-05-28 19:15:37 +02:00
|
|
|
glyph->outline.flags &= ~ft_outline_high_precision;
|
|
|
|
|
|
|
|
error = FT_Outline_Get_Bitmap( library, &glyph->outline, &bit2 );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bit3.rows = glyph->bitmap.rows;
|
|
|
|
bit3.width = glyph->bitmap.width;
|
|
|
|
bit3.pitch = glyph->bitmap.pitch;
|
|
|
|
bit3.mode = gr_pixel_mode_mono;
|
|
|
|
bit3.buffer = glyph->bitmap.buffer;
|
|
|
|
bit3.grays = 0;
|
|
|
|
}
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
/* then, blit the image to the target surface */
|
|
|
|
|
|
|
|
x_top = x_offset + TRUNC( left );
|
|
|
|
y_top = y_offset - TRUNC( top );
|
2000-05-28 19:15:37 +02:00
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
#if 0
|
|
|
|
if ( bit.pitch < 0 )
|
2000-05-28 19:15:37 +02:00
|
|
|
y_top = bit.rows - y_top;
|
2000-05-30 07:13:30 +02:00
|
|
|
#endif
|
|
|
|
|
2000-05-28 19:15:37 +02:00
|
|
|
grBlitGlyphToBitmap( &bit, &bit3, x_top, y_top, fore_color );
|
2000-05-30 07:13:30 +02:00
|
|
|
|
|
|
|
return FT_Err_Ok;
|
2000-05-28 19:15:37 +02:00
|
|
|
}
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
|
|
|
|
static
|
|
|
|
FT_Error Reset_Scale( int pointSize )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
|
|
|
FT_Error error;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
|
2000-05-28 19:15:37 +02:00
|
|
|
error = FT_Set_Char_Size( face, pointSize << 6,
|
|
|
|
pointSize << 6,
|
|
|
|
res,
|
|
|
|
res );
|
|
|
|
if ( error )
|
|
|
|
{
|
2000-05-30 07:13:30 +02:00
|
|
|
/* to be written */
|
2000-05-28 19:15:37 +02:00
|
|
|
}
|
2000-05-30 07:13:30 +02:00
|
|
|
|
2000-05-28 19:15:37 +02:00
|
|
|
return FT_Err_Ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
static
|
|
|
|
FT_Error LoadChar( int idx,
|
|
|
|
int hint )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
|
|
|
int flags;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
|
2000-05-28 19:15:37 +02:00
|
|
|
flags = FT_LOAD_DEFAULT;
|
|
|
|
|
|
|
|
if ( !hint )
|
|
|
|
flags |= FT_LOAD_NO_HINTING;
|
|
|
|
|
|
|
|
if ( !use_sbits )
|
|
|
|
flags |= FT_LOAD_NO_BITMAP;
|
|
|
|
|
|
|
|
return FT_Load_Glyph( face, idx, flags );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
static
|
|
|
|
FT_Error Render_All( int first_glyph,
|
|
|
|
int ptsize )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
|
|
|
FT_F26Dot6 start_x, start_y, step_x, step_y, x, y;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
FT_Error error;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
|
2000-05-28 19:15:37 +02:00
|
|
|
start_x = 4;
|
2000-05-30 07:13:30 +02:00
|
|
|
start_y = 36 + ptsize;
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
step_x = size->metrics.x_ppem + 4;
|
|
|
|
step_y = size->metrics.y_ppem + 10;
|
|
|
|
|
|
|
|
x = start_x;
|
|
|
|
y = start_y;
|
|
|
|
|
|
|
|
i = first_glyph;
|
|
|
|
|
|
|
|
#if 0
|
2000-05-30 07:13:30 +02:00
|
|
|
while ( i < first_glyph + 1 )
|
2000-05-28 19:15:37 +02:00
|
|
|
#else
|
|
|
|
while ( i < num_glyphs )
|
|
|
|
#endif
|
|
|
|
{
|
2000-05-30 07:13:30 +02:00
|
|
|
if ( !( error = LoadChar( i, hinted ) ) )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
2000-05-30 07:13:30 +02:00
|
|
|
#ifdef DEBUG
|
|
|
|
if ( i <= first_glyph + 6 )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
|
|
|
LOG(( "metrics[%02d] = [%x %x]\n",
|
|
|
|
i,
|
|
|
|
glyph->metrics.horiBearingX,
|
|
|
|
glyph->metrics.horiAdvance ));
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
if ( i == first_glyph + 6 )
|
|
|
|
LOG(( "-------------------------\n" ));
|
2000-05-28 19:15:37 +02:00
|
|
|
}
|
2000-05-30 07:13:30 +02:00
|
|
|
#endif
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
Render_Glyph( x, y );
|
|
|
|
|
|
|
|
x += ( glyph->metrics.horiAdvance >> 6 ) + 1;
|
|
|
|
|
|
|
|
if ( x + size->metrics.x_ppem > bit.width )
|
|
|
|
{
|
|
|
|
x = start_x;
|
|
|
|
y += step_y;
|
|
|
|
|
|
|
|
if ( y >= bit.rows )
|
|
|
|
return FT_Err_Ok;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Fail++;
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FT_Err_Ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
static
|
|
|
|
FT_Error Render_Text( int first_glyph,
|
|
|
|
int ptsize )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
|
|
|
FT_F26Dot6 start_x, start_y, step_x, step_y, x, y;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
FT_Error error;
|
|
|
|
const unsigned char* p;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
|
2000-05-28 19:15:37 +02:00
|
|
|
start_x = 4;
|
|
|
|
start_y = 32 + size->metrics.y_ppem;
|
|
|
|
|
|
|
|
step_x = size->metrics.x_ppem + 4;
|
|
|
|
step_y = size->metrics.y_ppem + 10;
|
|
|
|
|
|
|
|
x = start_x;
|
|
|
|
y = start_y;
|
|
|
|
|
|
|
|
i = first_glyph;
|
|
|
|
p = Text;
|
2000-05-30 07:13:30 +02:00
|
|
|
while ( i > 0 && *p )
|
|
|
|
{
|
|
|
|
p++;
|
|
|
|
i--;
|
|
|
|
}
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
while ( *p )
|
|
|
|
{
|
2000-05-30 07:13:30 +02:00
|
|
|
if ( !( error = LoadChar( FT_Get_Char_Index( face,
|
|
|
|
(unsigned char)*p ),
|
|
|
|
hinted ) ) )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
2000-05-30 07:13:30 +02:00
|
|
|
#ifdef DEBUG
|
|
|
|
if ( i <= first_glyph + 6 )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
|
|
|
LOG(( "metrics[%02d] = [%x %x]\n",
|
|
|
|
i,
|
|
|
|
glyph->metrics.horiBearingX,
|
|
|
|
glyph->metrics.horiAdvance ));
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
if ( i == first_glyph + 6 )
|
|
|
|
LOG(( "-------------------------\n" ));
|
2000-05-28 19:15:37 +02:00
|
|
|
}
|
2000-05-30 07:13:30 +02:00
|
|
|
#endif
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
Render_Glyph( x, y );
|
|
|
|
|
|
|
|
x += ( glyph->metrics.horiAdvance >> 6 ) + 1;
|
|
|
|
|
|
|
|
if ( x + size->metrics.x_ppem > bit.width )
|
|
|
|
{
|
|
|
|
x = start_x;
|
|
|
|
y += step_y;
|
|
|
|
|
|
|
|
if ( y >= bit.rows )
|
|
|
|
return FT_Err_Ok;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Fail++;
|
|
|
|
|
|
|
|
i++;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FT_Err_Ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
static
|
|
|
|
void Help( void )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
|
|
|
grEvent dummy_event;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
|
2000-05-28 19:15:37 +02:00
|
|
|
Clear_Display();
|
2000-05-30 07:13:30 +02:00
|
|
|
|
2000-05-28 19:15:37 +02:00
|
|
|
grGotoxy( 0, 0 );
|
|
|
|
grSetMargin( 2, 1 );
|
|
|
|
grGotobitmap( &bit );
|
|
|
|
|
|
|
|
grWriteln("FreeType Glyph Viewer - part of the FreeType test suite" );
|
|
|
|
grLn();
|
|
|
|
grWriteln("This program is used to display all glyphs from one or" );
|
|
|
|
grWriteln("several font files, with the FreeType library.");
|
|
|
|
grLn();
|
2000-05-30 07:13:30 +02:00
|
|
|
grWriteln("Use the following keys:");
|
2000-05-28 19:15:37 +02:00
|
|
|
grLn();
|
|
|
|
grWriteln(" F1 or ? : display this help screen" );
|
|
|
|
grWriteln(" a : toggle anti-aliasing" );
|
|
|
|
grWriteln(" h : toggle outline hinting" );
|
|
|
|
grWriteln(" b : toggle embedded bitmaps" );
|
|
|
|
grWriteln(" l : toggle low precision rendering" );
|
2000-05-30 07:13:30 +02:00
|
|
|
grWriteln(" g : toggle between `smooth' and `standard' anti-aliaser" );
|
2000-05-28 19:15:37 +02:00
|
|
|
grWriteln(" space : toggle rendering mode" );
|
|
|
|
grLn();
|
|
|
|
grWriteln(" Up : increase pointsize by 1 unit" );
|
|
|
|
grWriteln(" Down : decrease pointsize by 1 unit" );
|
|
|
|
grWriteln(" Page Up : increase pointsize by 10 units" );
|
|
|
|
grWriteln(" Page Down : decrease pointsize by 10 units" );
|
|
|
|
grLn();
|
|
|
|
grWriteln(" Right : increment first glyph index" );
|
|
|
|
grWriteln(" Left : decrement first glyph index" );
|
|
|
|
grLn();
|
|
|
|
grWriteln(" F3 : decrement first axis position by 20" );
|
|
|
|
grWriteln(" F4 : increment first axis position by 20" );
|
2000-05-29 22:37:41 +02:00
|
|
|
grWriteln(" F5 : decrement second axis position by 20" );
|
|
|
|
grWriteln(" F6 : increment second axis position by 20" );
|
|
|
|
grWriteln(" F7 : decrement third axis position by 20" );
|
|
|
|
grWriteln(" F8 : increment third axis position by 20" );
|
2000-05-28 19:15:37 +02:00
|
|
|
grLn();
|
|
|
|
grWriteln("press any key to exit this help screen");
|
|
|
|
|
|
|
|
grRefreshSurface( surface );
|
|
|
|
grListenSurface( surface, gr_event_key, &dummy_event );
|
|
|
|
}
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
|
|
|
|
static
|
|
|
|
void reset_raster( void )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
|
|
|
if ( antialias && use_grays )
|
|
|
|
FT_Set_Raster( library, &ft_grays_raster );
|
|
|
|
else
|
|
|
|
FT_Set_Raster( library, &std_raster );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
static
|
|
|
|
int Process_Event( grEvent* event )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
|
|
|
int i, axis;
|
|
|
|
|
|
|
|
switch ( event->key )
|
|
|
|
{
|
|
|
|
case grKeyEsc: /* ESC or q */
|
2000-05-30 07:13:30 +02:00
|
|
|
case grKEY( 'q' ):
|
2000-05-28 19:15:37 +02:00
|
|
|
return 0;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
case grKeyF1:
|
|
|
|
case grKEY( '?' ):
|
|
|
|
Help();
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* mode keys */
|
|
|
|
|
|
|
|
case grKEY( 'a' ):
|
2000-05-28 19:15:37 +02:00
|
|
|
antialias = !antialias;
|
2000-05-30 07:13:30 +02:00
|
|
|
new_header = antialias ? "anti-aliasing is now on"
|
|
|
|
: "anti-aliasing is now off";
|
2000-05-28 19:15:37 +02:00
|
|
|
reset_raster();
|
|
|
|
return 1;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
case grKEY( 'b' ):
|
2000-05-28 19:15:37 +02:00
|
|
|
use_sbits = !use_sbits;
|
2000-05-30 07:13:30 +02:00
|
|
|
new_header = use_sbits ? "embedded bitmaps are now used if available"
|
|
|
|
: "embedded bitmaps are now ignored";
|
2000-05-28 19:15:37 +02:00
|
|
|
return 1;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
case grKEY( 'n' ):
|
|
|
|
case grKEY( 'p' ):
|
2000-05-28 19:15:37 +02:00
|
|
|
return (int)event->key;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
case grKEY( 'g' ):
|
2000-05-28 19:15:37 +02:00
|
|
|
use_grays = !use_grays;
|
2000-05-30 07:13:30 +02:00
|
|
|
new_header = use_grays ? "now using the smooth anti-aliaser"
|
|
|
|
: "now using the standard anti-aliaser";
|
2000-05-28 19:15:37 +02:00
|
|
|
reset_raster();
|
|
|
|
break;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
case grKEY( 'l' ):
|
2000-05-28 19:15:37 +02:00
|
|
|
low_prec = !low_prec;
|
2000-05-30 07:13:30 +02:00
|
|
|
new_header = low_prec ? "rendering precision is now forced to low"
|
|
|
|
: "rendering precision is now normal";
|
2000-05-28 19:15:37 +02:00
|
|
|
break;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
case grKEY( 'h' ):
|
2000-05-28 19:15:37 +02:00
|
|
|
hinted = !hinted;
|
2000-05-30 07:13:30 +02:00
|
|
|
new_header = hinted ? "glyph hinting is now active"
|
|
|
|
: "glyph hinting is now ignored";
|
2000-05-28 19:15:37 +02:00
|
|
|
break;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
case grKEY( ' ' ):
|
2000-05-28 19:15:37 +02:00
|
|
|
render_mode ^= 1;
|
2000-05-30 07:13:30 +02:00
|
|
|
new_header = render_mode ? "rendering all glyphs in font"
|
|
|
|
: "rendering test text string";
|
2000-05-28 19:15:37 +02:00
|
|
|
break;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
/* MM related keys */
|
|
|
|
|
|
|
|
case grKeyF3:
|
|
|
|
i = -20;
|
|
|
|
axis = 0;
|
|
|
|
goto Do_Axis;
|
|
|
|
|
|
|
|
case grKeyF4:
|
|
|
|
i = 20;
|
|
|
|
axis = 0;
|
|
|
|
goto Do_Axis;
|
|
|
|
|
|
|
|
case grKeyF5:
|
|
|
|
i = -20;
|
|
|
|
axis = 1;
|
|
|
|
goto Do_Axis;
|
|
|
|
|
|
|
|
case grKeyF6:
|
|
|
|
i = 20;
|
|
|
|
axis = 1;
|
|
|
|
goto Do_Axis;
|
|
|
|
|
|
|
|
case grKeyF7:
|
|
|
|
i = -20;
|
|
|
|
axis = 2;
|
|
|
|
goto Do_Axis;
|
|
|
|
|
|
|
|
case grKeyF8:
|
|
|
|
i = 20;
|
|
|
|
axis = 2;
|
|
|
|
goto Do_Axis;
|
|
|
|
|
|
|
|
/* scaling related keys */
|
|
|
|
|
|
|
|
case grKeyPageUp:
|
|
|
|
i = 10;
|
|
|
|
goto Do_Scale;
|
|
|
|
|
|
|
|
case grKeyPageDown:
|
|
|
|
i = -10;
|
|
|
|
goto Do_Scale;
|
|
|
|
|
|
|
|
case grKeyUp:
|
|
|
|
i = 1;
|
|
|
|
goto Do_Scale;
|
|
|
|
|
|
|
|
case grKeyDown:
|
|
|
|
i = -1;
|
|
|
|
goto Do_Scale;
|
|
|
|
|
|
|
|
/* glyph index related keys */
|
|
|
|
|
|
|
|
case grKeyLeft:
|
|
|
|
i = -1;
|
|
|
|
goto Do_Glyph;
|
|
|
|
|
|
|
|
case grKeyRight:
|
|
|
|
i = 1;
|
|
|
|
goto Do_Glyph;
|
|
|
|
|
|
|
|
case grKeyF9:
|
|
|
|
i = -100;
|
|
|
|
goto Do_Glyph;
|
|
|
|
|
|
|
|
case grKeyF10:
|
|
|
|
i = 100;
|
|
|
|
goto Do_Glyph;
|
|
|
|
|
|
|
|
case grKeyF11:
|
|
|
|
i = -1000;
|
|
|
|
goto Do_Glyph;
|
|
|
|
|
|
|
|
case grKeyF12:
|
|
|
|
i = 1000;
|
|
|
|
goto Do_Glyph;
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
default:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
Do_Axis:
|
2000-05-30 07:13:30 +02:00
|
|
|
if ( axis < multimaster.num_axis )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
2000-05-30 07:13:30 +02:00
|
|
|
FT_MM_Axis* a = multimaster.axis + axis;
|
2000-05-28 19:15:37 +02:00
|
|
|
FT_Long pos = design_pos[axis];
|
2000-05-30 07:13:30 +02:00
|
|
|
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
pos += i;
|
2000-05-30 07:13:30 +02:00
|
|
|
if ( pos < a->minimum ) pos = a->minimum;
|
|
|
|
if ( pos > a->maximum ) pos = a->maximum;
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
design_pos[axis] = pos;
|
|
|
|
|
|
|
|
FT_Set_MM_Design_Coordinates( face, multimaster.num_axis, design_pos );
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
Do_Scale:
|
|
|
|
ptsize += i;
|
2000-05-30 07:13:30 +02:00
|
|
|
if ( ptsize < 1 ) ptsize = 1;
|
|
|
|
if ( ptsize > MAXPTSIZE ) ptsize = MAXPTSIZE;
|
2000-05-28 19:15:37 +02:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
Do_Glyph:
|
|
|
|
Num += i;
|
2000-05-30 07:13:30 +02:00
|
|
|
if ( Num < 0 ) Num = 0;
|
|
|
|
if ( Num >= num_glyphs ) Num = num_glyphs - 1;
|
2000-05-28 19:15:37 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
static
|
|
|
|
void usage( char* execname )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
|
|
|
fprintf( stderr, "\n" );
|
|
|
|
fprintf( stderr, "ftmulti: multiple masters font viewer - part of FreeType\n" );
|
|
|
|
fprintf( stderr, "--------------------------------------------------------\n" );
|
|
|
|
fprintf( stderr, "\n" );
|
|
|
|
fprintf( stderr, "Usage: %s [options below] ppem fontname[.ttf|.ttc] ...\n",
|
|
|
|
execname );
|
|
|
|
fprintf( stderr, "\n" );
|
|
|
|
fprintf( stderr, " -r R use resolution R dpi (default: 72 dpi)\n" );
|
|
|
|
fprintf( stderr, " -f index specify first glyph index to display\n" );
|
|
|
|
fprintf( stderr, "\n" );
|
|
|
|
|
|
|
|
exit( 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
int
|
|
|
|
main( int argc,
|
|
|
|
char* argv[] )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
2000-05-30 07:13:30 +02:00
|
|
|
int old_ptsize, orig_ptsize, file;
|
2000-05-28 19:15:37 +02:00
|
|
|
int first_glyph = 0;
|
|
|
|
int XisSetup = 0;
|
|
|
|
char* execname;
|
|
|
|
int option;
|
|
|
|
int file_loaded;
|
|
|
|
|
|
|
|
FT_Error error;
|
|
|
|
grEvent event;
|
|
|
|
|
|
|
|
execname = ft_basename( argv[0] );
|
|
|
|
|
|
|
|
while ( 1 )
|
|
|
|
{
|
|
|
|
option = getopt( argc, argv, "f:r:" );
|
|
|
|
|
|
|
|
if ( option == -1 )
|
|
|
|
break;
|
|
|
|
|
|
|
|
switch ( option )
|
|
|
|
{
|
|
|
|
case 'f':
|
|
|
|
first_glyph = atoi( optarg );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'r':
|
|
|
|
res = atoi( optarg );
|
|
|
|
if ( res < 1 )
|
|
|
|
usage( execname );
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
usage( execname );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
argc -= optind;
|
|
|
|
argv += optind;
|
|
|
|
|
|
|
|
if ( argc <= 1 )
|
|
|
|
usage( execname );
|
|
|
|
|
|
|
|
if ( sscanf( argv[0], "%d", &orig_ptsize ) != 1 )
|
|
|
|
orig_ptsize = 64;
|
|
|
|
|
|
|
|
file = 1;
|
|
|
|
|
|
|
|
/* Initialize engine */
|
|
|
|
error = FT_Init_FreeType( &library );
|
2000-05-30 07:13:30 +02:00
|
|
|
if ( error )
|
|
|
|
PanicZ( "Could not initialize FreeType library" );
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
/* retrieve the standard raster's interface */
|
|
|
|
(void)FT_Get_Raster( library, ft_glyph_format_outline, &std_raster );
|
|
|
|
reset_raster();
|
|
|
|
|
|
|
|
NewFile:
|
|
|
|
ptsize = orig_ptsize;
|
|
|
|
hinted = 1;
|
|
|
|
file_loaded = 0;
|
|
|
|
|
|
|
|
/* Load face */
|
2000-05-30 07:13:30 +02:00
|
|
|
error = FT_New_Face( library, argv[file], 0, &face );
|
|
|
|
if ( error )
|
|
|
|
goto Display_Font;
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
/* retrieve multiple master information */
|
|
|
|
error = FT_Get_Multi_Master( face, &multimaster );
|
2000-05-30 07:13:30 +02:00
|
|
|
if ( error )
|
|
|
|
goto Display_Font;
|
2000-05-28 19:15:37 +02:00
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
/* set the current position to the median of each axis */
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
|
|
|
int n;
|
2000-05-30 07:13:30 +02:00
|
|
|
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
for ( n = 0; n < multimaster.num_axis; n++ )
|
|
|
|
design_pos[n] =
|
2000-05-30 07:13:30 +02:00
|
|
|
( multimaster.axis[n].minimum + multimaster.axis[n].maximum ) / 2;
|
2000-05-28 19:15:37 +02:00
|
|
|
}
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
error = FT_Set_MM_Design_Coordinates( face,
|
|
|
|
multimaster.num_axis,
|
|
|
|
design_pos );
|
|
|
|
if ( error )
|
|
|
|
goto Display_Font;
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
file_loaded++;
|
|
|
|
|
|
|
|
error = Reset_Scale( ptsize );
|
2000-05-30 07:13:30 +02:00
|
|
|
if ( error )
|
|
|
|
goto Display_Font;
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
num_glyphs = face->num_glyphs;
|
|
|
|
glyph = face->glyph;
|
|
|
|
size = face->size;
|
|
|
|
|
|
|
|
Display_Font:
|
2000-05-30 07:13:30 +02:00
|
|
|
/* initialize graphics if needed */
|
2000-05-28 19:15:37 +02:00
|
|
|
if ( !XisSetup )
|
|
|
|
{
|
|
|
|
XisSetup = 1;
|
|
|
|
Init_Display();
|
|
|
|
}
|
|
|
|
|
|
|
|
grSetTitle( surface, "FreeType Glyph Viewer - press F1 for help" );
|
|
|
|
old_ptsize = ptsize;
|
|
|
|
|
|
|
|
if ( file_loaded >= 1 )
|
|
|
|
{
|
|
|
|
Fail = 0;
|
|
|
|
Num = first_glyph;
|
|
|
|
|
|
|
|
if ( Num >= num_glyphs )
|
2000-05-30 07:13:30 +02:00
|
|
|
Num = num_glyphs - 1;
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
if ( Num < 0 )
|
|
|
|
Num = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( ;; )
|
|
|
|
{
|
|
|
|
int key;
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
|
2000-05-28 19:15:37 +02:00
|
|
|
Clear_Display();
|
|
|
|
|
|
|
|
if ( file_loaded >= 1 )
|
|
|
|
{
|
2000-05-30 07:13:30 +02:00
|
|
|
switch ( render_mode )
|
2000-05-28 19:15:37 +02:00
|
|
|
{
|
2000-05-30 07:13:30 +02:00
|
|
|
case 0:
|
|
|
|
Render_Text( Num, ptsize );
|
|
|
|
break;
|
2000-05-28 19:15:37 +02:00
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
default:
|
|
|
|
Render_All( Num, ptsize );
|
2000-05-28 19:15:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
sprintf( Header, "%s %s (file %s)",
|
|
|
|
face->family_name,
|
|
|
|
face->style_name,
|
2000-05-30 07:13:30 +02:00
|
|
|
ft_basename( argv[file] ) );
|
2000-05-28 19:15:37 +02:00
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
if ( !new_header )
|
2000-05-28 19:15:37 +02:00
|
|
|
new_header = Header;
|
|
|
|
|
|
|
|
grWriteCellString( &bit, 0, 0, new_header, fore_color );
|
|
|
|
new_header = 0;
|
|
|
|
|
|
|
|
sprintf( Header, "axis: " );
|
|
|
|
{
|
|
|
|
int n;
|
2000-05-30 07:13:30 +02:00
|
|
|
|
|
|
|
|
2000-05-28 19:15:37 +02:00
|
|
|
for ( n = 0; n < multimaster.num_axis; n++ )
|
|
|
|
{
|
2000-05-30 07:13:30 +02:00
|
|
|
char temp[32];
|
|
|
|
|
|
|
|
|
|
|
|
sprintf( temp, " %s:%ld",
|
|
|
|
multimaster.axis[n].name,
|
|
|
|
design_pos[n] );
|
2000-05-28 19:15:37 +02:00
|
|
|
strcat( Header, temp );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
grWriteCellString( &bit, 0, 16, Header, fore_color );
|
|
|
|
|
|
|
|
sprintf( Header, "at %d points, first glyph = %d",
|
|
|
|
ptsize,
|
|
|
|
Num );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-05-30 07:13:30 +02:00
|
|
|
sprintf( Header, "%s : not an MM font file, or could not be opened",
|
|
|
|
ft_basename( argv[file] ) );
|
2000-05-28 19:15:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
grWriteCellString( &bit, 0, 8, Header, fore_color );
|
|
|
|
grRefreshSurface( surface );
|
|
|
|
|
|
|
|
grListenSurface( surface, 0, &event );
|
|
|
|
if ( !( key = Process_Event( &event ) ) )
|
2000-05-30 07:13:30 +02:00
|
|
|
goto End;
|
2000-05-28 19:15:37 +02:00
|
|
|
|
|
|
|
if ( key == 'n' )
|
|
|
|
{
|
2000-05-30 07:13:30 +02:00
|
|
|
if ( file_loaded >= 1 )
|
2000-05-28 19:15:37 +02:00
|
|
|
FT_Done_Face( face );
|
|
|
|
|
|
|
|
if ( file < argc - 1 )
|
|
|
|
file++;
|
|
|
|
|
|
|
|
goto NewFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( key == 'p' )
|
|
|
|
{
|
2000-05-30 07:13:30 +02:00
|
|
|
if ( file_loaded >= 1 )
|
2000-05-28 19:15:37 +02:00
|
|
|
FT_Done_Face( face );
|
|
|
|
|
|
|
|
if ( file > 1 )
|
|
|
|
file--;
|
|
|
|
|
|
|
|
goto NewFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ptsize != old_ptsize )
|
|
|
|
{
|
|
|
|
if ( Reset_Scale( ptsize ) )
|
|
|
|
PanicZ( "Could not resize font." );
|
|
|
|
|
|
|
|
old_ptsize = ptsize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-05-30 07:13:30 +02:00
|
|
|
End:
|
2000-05-28 19:15:37 +02:00
|
|
|
#if 0
|
2000-05-30 07:13:30 +02:00
|
|
|
grDoneSurface( surface );
|
2000-05-28 19:15:37 +02:00
|
|
|
grDone();
|
|
|
|
#endif
|
2000-05-30 07:13:30 +02:00
|
|
|
|
2000-05-28 19:15:37 +02:00
|
|
|
printf( "Execution completed successfully.\n" );
|
|
|
|
printf( "Fails = %d\n", Fail );
|
|
|
|
|
|
|
|
exit( 0 ); /* for safety reasons */
|
|
|
|
return 0; /* never reached */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* End */
|