|
|
#include <nirvana.h> |
|
|
#include NV_VIEWPORT_H |
|
|
#include <stdio.h> |
|
|
|
|
|
#include <ft2build.h> |
|
|
#include FT_FREETYPE_H |
|
|
|
|
|
/* include FreeType internals to debug hints */ |
|
|
#include <../src/pshinter/pshrec.h> |
|
|
#include <../src/pshinter/pshalgo.h> |
|
|
|
|
|
#include <../src/autohint/ahtypes.h> |
|
|
|
|
|
/************************************************************************/ |
|
|
/************************************************************************/ |
|
|
/***** *****/ |
|
|
/***** ROOT DEFINITIONS *****/ |
|
|
/***** *****/ |
|
|
/************************************************************************/ |
|
|
/************************************************************************/ |
|
|
|
|
|
|
|
|
#include <time.h> /* for clock() */ |
|
|
|
|
|
/* SunOS 4.1.* does not define CLOCKS_PER_SEC, so include <sys/param.h> */ |
|
|
/* to get the HZ macro which is the equivalent. */ |
|
|
#if defined( __sun__ ) && !defined( SVR4 ) && !defined( __SVR4 ) |
|
|
#include <sys/param.h> |
|
|
#define CLOCKS_PER_SEC HZ |
|
|
#endif |
|
|
|
|
|
static int first_glyph = 0; |
|
|
|
|
|
static NV_Renderer renderer; |
|
|
static NV_Painter painter; |
|
|
static NV_Pixmap target; |
|
|
static NV_Error error; |
|
|
static NV_Memory memory; |
|
|
static NVV_Display display; |
|
|
static NVV_Surface surface; |
|
|
|
|
|
static FT_Library freetype; |
|
|
static FT_Face face; |
|
|
|
|
|
|
|
|
static NV_Pos glyph_scale; |
|
|
static NV_Pos glyph_org_x; |
|
|
static NV_Pos glyph_org_y; |
|
|
static NV_Transform glyph_transform; /* font units -> device pixels */ |
|
|
static NV_Transform size_transform; /* subpixels -> device pixels */ |
|
|
|
|
|
static NV_Scale grid_scale = 1.0; |
|
|
|
|
|
static int glyph_index; |
|
|
static int pixel_size = 12; |
|
|
|
|
|
|
|
|
/************************************************************************/ |
|
|
/************************************************************************/ |
|
|
/***** *****/ |
|
|
/***** OPTIONS, COLORS and OTHERS *****/ |
|
|
/***** *****/ |
|
|
/************************************************************************/ |
|
|
/************************************************************************/ |
|
|
|
|
|
static int option_show_axis = 1; |
|
|
static int option_show_dots = 1; |
|
|
static int option_show_stroke = 0; |
|
|
static int option_show_glyph = 1; |
|
|
static int option_show_grid = 1; |
|
|
static int option_show_em = 0; |
|
|
static int option_show_smooth = 1; |
|
|
static int option_show_blues = 0; |
|
|
static int option_show_edges = 0; |
|
|
static int option_show_segments = 1; |
|
|
static int option_show_links = 1; |
|
|
static int option_show_indices = 0; |
|
|
|
|
|
static int option_show_ps_hints = 1; |
|
|
static int option_show_horz_hints = 1; |
|
|
static int option_show_vert_hints = 1; |
|
|
|
|
|
|
|
|
static int option_hinting = 1; |
|
|
|
|
|
static char temp_message[1024]; |
|
|
|
|
|
static NV_Path symbol_dot = NULL; |
|
|
static NV_Path symbol_circle = NULL; |
|
|
static NV_Path symbol_square = NULL; |
|
|
static NV_Path symbol_rect_h = NULL; |
|
|
static NV_Path symbol_rect_v = NULL; |
|
|
|
|
|
|
|
|
|
|
|
#define AXIS_COLOR 0xFFFF0000 |
|
|
#define GRID_COLOR 0xFFD0D0D0 |
|
|
#define ON_COLOR 0xFFFF2000 |
|
|
#define OFF_COLOR 0xFFFF0080 |
|
|
#define STRONG_COLOR 0xFF404040 |
|
|
#define INTERP_COLOR 0xFF206040 |
|
|
#define SMOOTH_COLOR 0xF000B040 |
|
|
#define BACKGROUND_COLOR 0xFFFFFFFF |
|
|
#define TEXT_COLOR 0xFF000000 |
|
|
#define EM_COLOR 0x80008000 |
|
|
#define BLUES_TOP_COLOR 0x4000008F |
|
|
#define BLUES_BOT_COLOR 0x40008F00 |
|
|
|
|
|
#define GHOST_HINT_COLOR 0xE00000FF |
|
|
#define STEM_HINT_COLOR 0xE02020FF |
|
|
#define STEM_JOIN_COLOR 0xE020FF20 |
|
|
|
|
|
#define EDGE_COLOR 0xF0704070 |
|
|
#define SEGMENT_COLOR 0xF0206040 |
|
|
#define LINK_COLOR 0xF0FFFF00 |
|
|
#define SERIF_LINK_COLOR 0xF0FF808F |
|
|
|
|
|
|
|
|
/* print message and abort program */ |
|
|
static void |
|
|
Panic( const char* message ) |
|
|
{ |
|
|
fprintf( stderr, "PANIC: %s\n", message ); |
|
|
exit(1); |
|
|
} |
|
|
|
|
|
|
|
|
static void |
|
|
init_symbols( void ) |
|
|
{ |
|
|
nv_path_new_rectangle( renderer, -1, -1, 3, 3, 0, 0, &symbol_square ); |
|
|
nv_path_new_rectangle( renderer, -1, -6, 2, 12, 0, 0, &symbol_rect_v ); |
|
|
nv_path_new_rectangle( renderer, -6, -1, 12, 2, 0, 0, &symbol_rect_h ); |
|
|
|
|
|
nv_path_new_circle( renderer, 0, 0, 3., &symbol_dot ); |
|
|
|
|
|
nv_path_stroke( symbol_dot, 0.6, |
|
|
nv_path_linecap_butt, |
|
|
nv_path_linejoin_miter, 1., |
|
|
&symbol_circle ); |
|
|
|
|
|
nv_path_destroy( symbol_dot ); |
|
|
|
|
|
nv_path_new_circle( renderer, 0, 0, 2., &symbol_dot ); |
|
|
} |
|
|
|
|
|
|
|
|
static void |
|
|
done_symbols( void ) |
|
|
{ |
|
|
nv_path_destroy( symbol_circle ); |
|
|
nv_path_destroy( symbol_dot ); |
|
|
nv_path_destroy( symbol_rect_v ); |
|
|
nv_path_destroy( symbol_rect_h ); |
|
|
nv_path_destroy( symbol_square ); |
|
|
} |
|
|
|
|
|
|
|
|
/************************************************************************/ |
|
|
/************************************************************************/ |
|
|
/***** *****/ |
|
|
/***** COMMON GRID DRAWING ROUTINES *****/ |
|
|
/***** *****/ |
|
|
/************************************************************************/ |
|
|
/************************************************************************/ |
|
|
|
|
|
static void |
|
|
reset_scale( NV_Scale scale ) |
|
|
{ |
|
|
/* compute font units -> grid pixels scale factor */ |
|
|
glyph_scale = target->width*0.75 / face->units_per_EM * scale; |
|
|
|
|
|
/* setup font units -> grid pixels transform */ |
|
|
nv_transform_set_scale( &glyph_transform, glyph_scale, -glyph_scale ); |
|
|
glyph_org_x = glyph_transform.delta.x = target->width*0.125; |
|
|
glyph_org_y = glyph_transform.delta.y = target->height*0.875; |
|
|
|
|
|
/* setup subpixels -> grid pixels transform */ |
|
|
nv_transform_set_scale( |
|
|
&size_transform, |
|
|
glyph_scale / nv_fromfixed( face->size->metrics.x_scale ), |
|
|
-glyph_scale / nv_fromfixed( face->size->metrics.y_scale ) ); |
|
|
|
|
|
size_transform.delta = glyph_transform.delta; |
|
|
} |
|
|
|
|
|
|
|
|
static void |
|
|
reset_size( int pixel_size, |
|
|
NV_Scale scale ) |
|
|
{ |
|
|
FT_Set_Pixel_Sizes( face, pixel_size, pixel_size ); |
|
|
reset_scale( scale ); |
|
|
} |
|
|
|
|
|
|
|
|
static void |
|
|
clear_background( void ) |
|
|
{ |
|
|
nv_pixmap_fill_rect( target, 0, 0, target->width, target->height, |
|
|
BACKGROUND_COLOR ); |
|
|
} |
|
|
|
|
|
|
|
|
static void |
|
|
draw_grid( void ) |
|
|
{ |
|
|
int x = (int)glyph_org_x; |
|
|
int y = (int)glyph_org_y; |
|
|
|
|
|
|
|
|
/* draw grid */ |
|
|
if ( option_show_grid ) |
|
|
{ |
|
|
NV_Scale min, max, x, step; |
|
|
|
|
|
|
|
|
/* draw vertical grid bars */ |
|
|
step = 64. * size_transform.matrix.xx; |
|
|
if ( step > 1. ) |
|
|
{ |
|
|
min = max = glyph_org_x; |
|
|
while ( min - step >= 0 ) min -= step; |
|
|
while ( max + step < target->width ) max += step; |
|
|
|
|
|
for ( x = min; x <= max; x += step ) |
|
|
nv_pixmap_fill_rect( target, (NV_Int)(x + .5), 0, |
|
|
1, target->height, GRID_COLOR ); |
|
|
} |
|
|
|
|
|
/* draw horizontal grid bars */ |
|
|
step = -64. * size_transform.matrix.yy; |
|
|
if ( step > 1. ) |
|
|
{ |
|
|
min = max = glyph_org_y; |
|
|
while ( min - step >= 0 ) min -= step; |
|
|
while ( max + step < target->height ) max += step; |
|
|
|
|
|
for ( x = min; x <= max; x += step ) |
|
|
nv_pixmap_fill_rect( target, 0, (NV_Int)(x + .5), |
|
|
target->width, 1, GRID_COLOR ); |
|
|
} |
|
|
} |
|
|
|
|
|
/* draw axis */ |
|
|
if ( option_show_axis ) |
|
|
{ |
|
|
nv_pixmap_fill_rect( target, x, 0, 1, target->height, AXIS_COLOR ); |
|
|
nv_pixmap_fill_rect( target, 0, y, target->width, 1, AXIS_COLOR ); |
|
|
} |
|
|
|
|
|
if ( option_show_em ) |
|
|
{ |
|
|
NV_Path path; |
|
|
NV_Path stroke; |
|
|
NV_UInt units = (NV_UInt)face->units_per_EM; |
|
|
|
|
|
|
|
|
nv_path_new_rectangle( renderer, 0, 0, units, units, 0, 0, &path ); |
|
|
nv_path_transform( path, &glyph_transform ); |
|
|
|
|
|
nv_path_stroke( path, 1.5, nv_path_linecap_butt, nv_path_linejoin_miter, |
|
|
4.0, &stroke ); |
|
|
|
|
|
nv_painter_set_color( painter, EM_COLOR, 256 ); |
|
|
nv_painter_fill_path( painter, NULL, 0, stroke ); |
|
|
|
|
|
nv_path_destroy( stroke ); |
|
|
nv_path_destroy( path ); |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/************************************************************************/ |
|
|
/************************************************************************/ |
|
|
/***** *****/ |
|
|
/***** POSTSCRIPT GLOBALS ROUTINES *****/ |
|
|
/***** *****/ |
|
|
/************************************************************************/ |
|
|
/************************************************************************/ |
|
|
|
|
|
#include <../src/pshinter/pshglob.h> |
|
|
|
|
|
static void |
|
|
draw_ps_blue_zones( void ) |
|
|
{ |
|
|
if ( option_show_blues && ps_debug_globals ) |
|
|
{ |
|
|
PSH_Blues blues = &ps_debug_globals->blues; |
|
|
PSH_Blue_Table table; |
|
|
NV_Vector v; |
|
|
FT_Int y1, y2; |
|
|
FT_UInt count; |
|
|
PSH_Blue_Zone zone; |
|
|
|
|
|
|
|
|
/* draw top zones */ |
|
|
table = &blues->normal_top; |
|
|
count = table->count; |
|
|
zone = table->zones; |
|
|
|
|
|
for ( ; count > 0; count--, zone++ ) |
|
|
{ |
|
|
v.x = 0; |
|
|
if ( !ps_debug_no_horz_hints ) |
|
|
{ |
|
|
v.y = zone->cur_ref + zone->cur_delta; |
|
|
nv_vector_transform( &v, &size_transform ); |
|
|
} |
|
|
else |
|
|
{ |
|
|
v.y = zone->org_ref + zone->org_delta; |
|
|
nv_vector_transform( &v, &glyph_transform ); |
|
|
} |
|
|
y1 = (int)(v.y + 0.5); |
|
|
|
|
|
v.x = 0; |
|
|
if ( !ps_debug_no_horz_hints ) |
|
|
{ |
|
|
v.y = zone->cur_ref; |
|
|
nv_vector_transform( &v, &size_transform ); |
|
|
} |
|
|
else |
|
|
{ |
|
|
v.y = zone->org_ref; |
|
|
nv_vector_transform( &v, &glyph_transform ); |
|
|
} |
|
|
y2 = (int)(v.y + 0.5); |
|
|
|
|
|
nv_pixmap_fill_rect( target, 0, y1, |
|
|
target->width, y2-y1+1, |
|
|
BLUES_TOP_COLOR ); |
|
|
|
|
|
#if 0 |
|
|
printf( "top [%.3f %.3f]\n", zone->cur_bottom/64.0, zone->cur_top/64.0 ); |
|
|
#endif |
|
|
} |
|
|
|
|
|
|
|
|
/* draw bottom zones */ |
|
|
table = &blues->normal_bottom; |
|
|
count = table->count; |
|
|
zone = table->zones; |
|
|
|
|
|
for ( ; count > 0; count--, zone++ ) |
|
|
{ |
|
|
v.x = 0; |
|
|
v.y = zone->cur_ref; |
|
|
nv_vector_transform( &v, &size_transform ); |
|
|
y1 = (int)(v.y + 0.5); |
|
|
|
|
|
v.x = 0; |
|
|
v.y = zone->cur_ref + zone->cur_delta; |
|
|
nv_vector_transform( &v, &size_transform ); |
|
|
y2 = (int)(v.y + 0.5); |
|
|
|
|
|
nv_pixmap_fill_rect( target, 0, y1, |
|
|
target->width, y2 - y1 + 1, |
|
|
BLUES_BOT_COLOR ); |
|
|
|
|
|
#if 0 |
|
|
printf( "bot [%.3f %.3f]\n", zone->cur_bottom/64.0, zone->cur_top/64.0 ); |
|
|
#endif |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/************************************************************************/ |
|
|
/************************************************************************/ |
|
|
/***** *****/ |
|
|
/***** POSTSCRIPT HINTER ALGORITHM ROUTINES *****/ |
|
|
/***** *****/ |
|
|
/************************************************************************/ |
|
|
/************************************************************************/ |
|
|
|
|
|
#include <../src/pshinter/pshalgo.h> |
|
|
|
|
|
static void |
|
|
draw_ps_hint( PSH_Hint hint, |
|
|
FT_Bool vertical ) |
|
|
{ |
|
|
int x1, x2; |
|
|
NV_Vector v; |
|
|
|
|
|
|
|
|
if ( pshint_vertical != vertical ) |
|
|
{ |
|
|
if ( vertical ) |
|
|
pshint_cpos = 40; |
|
|
else |
|
|
pshint_cpos = 10; |
|
|
|
|
|
pshint_vertical = vertical; |
|
|
} |
|
|
|
|
|
if ( !vertical ) |
|
|
{ |
|
|
if ( !option_show_vert_hints ) |
|
|
return; |
|
|
|
|
|
v.x = hint->cur_pos; |
|
|
v.y = 0; |
|
|
nv_vector_transform( &v, &size_transform ); |
|
|
x1 = (int)(v.x + 0.5); |
|
|
|
|
|
v.x = hint->cur_pos + hint->cur_len; |
|
|
v.y = 0; |
|
|
nv_vector_transform( &v, &size_transform ); |
|
|
x2 = (int)(v.x + 0.5); |
|
|
|
|
|
nv_pixmap_fill_rect( target, x1, 0, 1, target->height, |
|
|
psh_hint_is_ghost( hint ) |
|
|
? GHOST_HINT_COLOR : STEM_HINT_COLOR ); |
|
|
|
|
|
if ( psh_hint_is_ghost( hint ) ) |
|
|
{ |
|
|
x1 --; |
|
|
x2 = x1 + 2; |
|
|
} |
|
|
else |
|
|
nv_pixmap_fill_rect( target, x2, 0, 1, target->height, |
|
|
psh_hint_is_ghost( hint ) |
|
|
? GHOST_HINT_COLOR : STEM_HINT_COLOR ); |
|
|
|
|
|
nv_pixmap_fill_rect( target, x1, pshint_cpos, x2 + 1 - x1, 1, |
|
|
STEM_JOIN_COLOR ); |
|
|
} |
|
|
else |
|
|
{ |
|
|
if ( !option_show_horz_hints ) |
|
|
return; |
|
|
|
|
|
v.y = hint->cur_pos; |
|
|
v.x = 0; |
|
|
nv_vector_transform( &v, &size_transform ); |
|
|
x1 = (int)(v.y + 0.5); |
|
|
|
|
|
v.y = hint->cur_pos + hint->cur_len; |
|
|
v.x = 0; |
|
|
nv_vector_transform( &v, &size_transform ); |
|
|
x2 = (int)(v.y + 0.5); |
|
|
|
|
|
nv_pixmap_fill_rect( target, 0, x1, target->width, 1, |
|
|
psh_hint_is_ghost( hint ) |
|
|
? GHOST_HINT_COLOR : STEM_HINT_COLOR ); |
|
|
|
|
|
if ( psh_hint_is_ghost( hint ) ) |
|
|
{ |
|
|
x1 --; |
|
|
x2 = x1 + 2; |
|
|
} |
|
|
else |
|
|
nv_pixmap_fill_rect( target, 0, x2, target->width, 1, |
|
|
psh_hint_is_ghost(hint) |
|
|
? GHOST_HINT_COLOR : STEM_HINT_COLOR ); |
|
|
|
|
|
nv_pixmap_fill_rect( target, pshint_cpos, x2, 1, x1 + 1 - x2, |
|
|
STEM_JOIN_COLOR ); |
|
|
} |
|
|
|
|
|
#if 0 |
|
|
printf( "[%7.3f %7.3f] %c\n", hint->cur_pos/64.0, (hint->cur_pos+hint->cur_len)/64.0, vertical ? 'v' : 'h' ); |
|
|
#endif |
|
|
|
|
|
pshint_cpos += 10; |
|
|
} |
|
|
|
|
|
|
|
|
static void |
|
|
ps_draw_control_points( void ) |
|
|
{ |
|
|
if ( ps_debug_glyph ) |
|
|
{ |
|
|
PSH_Glyph glyph = ps_debug_glyph; |
|
|
PSH_Point point = glyph->points; |
|
|
FT_UInt count = glyph->num_points; |
|
|
NV_Transform transform, *trans = &transform; |
|
|
NV_Path vert_rect; |
|
|
NV_Path horz_rect; |
|
|
NV_Path dot, circle; |
|
|
|
|
|
|
|
|
for ( ; count > 0; count--, point++ ) |
|
|
{ |
|
|
NV_Vector vec; |
|
|
|
|
|
|
|
|
vec.x = point->cur_x; |
|
|
vec.y = point->cur_y; |
|
|
nv_vector_transform( &vec, &size_transform ); |
|
|
|
|
|
nv_transform_set_translate( trans, vec.x, vec.y ); |
|
|
|
|
|
if ( option_show_smooth && !psh_point_is_smooth(point) ) |
|
|
{ |
|
|
nv_painter_set_color( painter, SMOOTH_COLOR, 256 ); |
|
|
nv_painter_fill_path( painter, trans, 0, symbol_circle ); |
|
|
} |
|
|
|
|
|
if ( option_show_horz_hints ) |
|
|
{ |
|
|
if ( point->flags_y & PSH_POINT_STRONG ) |
|
|
{ |
|
|
nv_painter_set_color( painter, STRONG_COLOR, 256 ); |
|
|
nv_painter_fill_path( painter, trans, 0, symbol_rect_h ); |
|
|
} |
|
|
} |
|
|
|
|
|
if ( option_show_vert_hints ) |
|
|
{ |
|
|
if ( point->flags_x & PSH_POINT_STRONG ) |
|
|
{ |
|
|
nv_painter_set_color( painter, STRONG_COLOR, 256 ); |
|
|
nv_painter_fill_path( painter, trans, 0, symbol_rect_v ); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void |
|
|
ps_print_hints( void ) |
|
|
{ |
|
|
if ( ps_debug_hints ) |
|
|
{ |
|
|
FT_Int dimension; |
|
|
|
|
|
|
|
|
for ( dimension = 1; dimension >= 0; dimension-- ) |
|
|
{ |
|
|
PS_Dimension dim = &ps_debug_hints->dimension[ dimension ]; |
|
|
PS_Mask mask = dim->masks.masks; |
|
|
FT_UInt count = dim->masks.num_masks; |
|
|
|
|
|
|
|
|
printf( "%s hints -------------------------\n", |
|
|
dimension ? "vertical" : "horizontal" ); |
|
|
|
|
|
for ( ; count > 0; count--, mask++ ) |
|
|
{ |
|
|
FT_UInt index; |
|
|
|
|
|
|
|
|
printf( "mask -> %d\n", mask->end_point ); |
|
|
for ( index = 0; index < mask->num_bits; index++ ) |
|
|
{ |
|
|
if ( mask->bytes[ index >> 3 ] & (0x80 >> (index & 7)) ) |
|
|
{ |
|
|
PS_Hint hint = dim->hints.hints + index; |
|
|
|
|
|
|
|
|
printf( "%c [%3d %3d (%4d)]\n", dimension ? "v" : "h", |
|
|
hint->pos, hint->pos + hint->len, hint->len ); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/************************************************************************/ |
|
|
/************************************************************************/ |
|
|
/***** *****/ |
|
|
/***** AUTOHINTER DRAWING ROUTINES *****/ |
|
|
/***** *****/ |
|
|
/************************************************************************/ |
|
|
/************************************************************************/ |
|
|
|
|
|
static NV_Path |
|
|
ah_link_path( NV_Vector* p1, |
|
|
NV_Vector* p4, |
|
|
NV_Bool vertical ) |
|
|
{ |
|
|
NV_PathWriter writer; |
|
|
NV_Vector p2, p3; |
|
|
NV_Path path, stroke; |
|
|
|
|
|
|
|
|
if ( vertical ) |
|
|
{ |
|
|
p2.x = p4->x; |
|
|
p2.y = p1->y; |
|
|
|
|
|
p3.x = p1->x; |
|
|
p3.y = p4->y; |
|
|
} |
|
|
else |
|
|
{ |
|
|
p2.x = p1->x; |
|
|
p2.y = p4->y; |
|
|
|
|
|
p3.x = p4->x; |
|
|
p3.y = p1->y; |
|
|
} |
|
|
|
|
|
nv_path_writer_new( renderer, &writer ); |
|
|
nv_path_writer_moveto( writer, p1 ); |
|
|
nv_path_writer_cubicto( writer, &p2, &p3, p4 ); |
|
|
nv_path_writer_end( writer ); |
|
|
|
|
|
path = nv_path_writer_get_path( writer ); |
|
|
nv_path_writer_destroy( writer ); |
|
|
|
|
|
nv_path_stroke( path, 1., |
|
|
nv_path_linecap_butt, nv_path_linejoin_round, |
|
|
1., &stroke ); |
|
|
|
|
|
nv_path_destroy( path ); |
|
|
|
|
|
return stroke; |
|
|
} |
|
|
|
|
|
|
|
|
static void |
|
|
ah_draw_smooth_points( void ) |
|
|
{ |
|
|
if ( ah_debug_hinter && option_show_smooth ) |
|
|
{ |
|
|
AH_Outline glyph = ah_debug_hinter->glyph; |
|
|
FT_UInt count = glyph->num_points; |
|
|
AH_Point point = glyph->points; |
|
|
|
|
|
|
|
|
nv_painter_set_color( painter, SMOOTH_COLOR, 256 ); |
|
|
|
|
|
for ( ; count > 0; count--, point++ ) |
|
|
{ |
|
|
if ( !( point->flags & AH_FLAG_WEAK_INTERPOLATION ) ) |
|
|
{ |
|
|
NV_Transform transform, *trans = &transform; |
|
|
NV_Vector vec; |
|
|
|
|
|
|
|
|
vec.x = point->x - ah_debug_hinter->pp1.x; |
|
|
vec.y = point->y; |
|
|
nv_vector_transform( &vec, &size_transform ); |
|
|
|
|
|
nv_transform_set_translate( &transform, vec.x, vec.y ); |
|
|
nv_painter_fill_path( painter, trans, 0, symbol_circle ); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void |
|
|
ah_draw_edges( void ) |
|
|
{ |
|
|
if ( ah_debug_hinter ) |
|
|
{ |
|
|
AH_Outline glyph = ah_debug_hinter->glyph; |
|
|
FT_UInt count; |
|
|
AH_Edge edge; |
|
|
FT_Pos pp1 = ah_debug_hinter->pp1.x; |
|
|
|
|
|
|
|
|
nv_painter_set_color( painter, EDGE_COLOR, 256 ); |
|
|
|
|
|
if ( option_show_edges ) |
|
|
{ |
|
|
/* draw vertical edges */ |
|
|
if ( option_show_vert_hints ) |
|
|
{ |
|
|
count = glyph->num_vedges; |
|
|
edge = glyph->vert_edges; |
|
|
for ( ; count > 0; count--, edge++ ) |
|
|
{ |
|
|
NV_Vector vec; |
|
|
NV_Pos x; |
|
|
|
|
|
|
|
|
vec.x = edge->pos - pp1; |
|
|
vec.y = 0; |
|
|
|
|
|
nv_vector_transform( &vec, &size_transform ); |
|
|
x = (FT_Pos)( vec.x + 0.5 ); |
|
|
|
|
|
nv_pixmap_fill_rect( target, x, 0, 1, target->height, EDGE_COLOR ); |
|
|
} |
|
|
} |
|
|
|
|
|
/* draw horizontal edges */ |
|
|
if ( option_show_horz_hints ) |
|
|
{ |
|
|
count = glyph->num_hedges; |
|
|
edge = glyph->horz_edges; |
|
|
for ( ; count > 0; count--, edge++ ) |
|
|
{ |
|
|
NV_Vector vec; |
|
|
NV_Pos x; |
|
|
|
|
|
|
|
|
vec.x = 0; |
|
|
vec.y = edge->pos; |
|
|
|
|
|
nv_vector_transform( &vec, &size_transform ); |
|
|
x = (FT_Pos)( vec.y + 0.5 ); |
|
|
|
|
|
nv_pixmap_fill_rect( target, 0, x, target->width, 1, EDGE_COLOR ); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
if ( option_show_segments ) |
|
|
{ |
|
|
/* draw vertical segments */ |
|
|
if ( option_show_vert_hints ) |
|
|
{ |
|
|
AH_Segment seg = glyph->vert_segments; |
|
|
FT_UInt count = glyph->num_vsegments; |
|
|
|
|
|
|
|
|
for ( ; count > 0; count--, seg++ ) |
|
|
{ |
|
|
AH_PointRec *first, *last; |
|
|
NV_Vector v1, v2; |
|
|
NV_Pos y1, y2, x; |
|
|
|
|
|
|
|
|
first = seg->first; |
|
|
last = seg->last; |
|
|
|
|
|
v1.x = v2.x = first->x - pp1; |
|
|
|
|
|
if ( first->y <= last->y ) |
|
|
{ |
|
|
v1.y = first->y; |
|
|
v2.y = last->y; |
|
|
} |
|
|
else |
|
|
{ |
|
|
v1.y = last->y; |
|
|
v2.y = first->y; |
|
|
} |
|
|
|
|
|
nv_vector_transform( &v1, &size_transform ); |
|
|
nv_vector_transform( &v2, &size_transform ); |
|
|
|
|
|
y1 = (NV_Pos)( v1.y + 0.5 ); |
|
|
y2 = (NV_Pos)( v2.y + 0.5 ); |
|
|
x = (NV_Pos)( v1.x + 0.5 ); |
|
|
|
|
|
nv_pixmap_fill_rect( target, x - 1, y2, 3, |
|
|
FT_ABS( y1 - y2 ) + 1, SEGMENT_COLOR ); |
|
|
} |
|
|
} |
|
|
|
|
|
/* draw horizontal segments */ |
|
|
if ( option_show_horz_hints ) |
|
|
{ |
|
|
AH_Segment seg = glyph->horz_segments; |
|
|
FT_UInt count = glyph->num_hsegments; |
|
|
|
|
|
|
|
|
for ( ; count > 0; count--, seg++ ) |
|
|
{ |
|
|
AH_PointRec *first, *last; |
|
|
NV_Vector v1, v2; |
|
|
NV_Pos y1, y2, x; |
|
|
|
|
|
|
|
|
first = seg->first; |
|
|
last = seg->last; |
|
|
|
|
|
v1.y = v2.y = first->y; |
|
|
|
|
|
if ( first->x <= last->x ) |
|
|
{ |
|
|
v1.x = first->x - pp1; |
|
|
v2.x = last->x - pp1; |
|
|
} |
|
|
else |
|
|
{ |
|
|
v1.x = last->x - pp1; |
|
|
v2.x = first->x - pp1; |
|
|
} |
|
|
|
|
|
nv_vector_transform( &v1, &size_transform ); |
|
|
nv_vector_transform( &v2, &size_transform ); |
|
|
|
|
|
y1 = (NV_Pos)( v1.x + 0.5 ); |
|
|
y2 = (NV_Pos)( v2.x + 0.5 ); |
|
|
x = (NV_Pos)( v1.y + 0.5 ); |
|
|
|
|
|
nv_pixmap_fill_rect( target, y1, x - 1, |
|
|
FT_ABS( y1 - y2 ) + 1, 3, SEGMENT_COLOR ); |
|
|
} |
|
|
} |
|
|
|
|
|
if ( option_show_vert_hints && option_show_links ) |
|
|
{ |
|
|
AH_Segment seg = glyph->vert_segments; |
|
|
FT_UInt count = glyph->num_vsegments; |
|
|
|
|
|
|
|
|
for ( ; count > 0; count--, seg++ ) |
|
|
{ |
|
|
AH_Segment seg2 = NULL; |
|
|
NV_Path link; |
|
|
NV_Vector v1, v2; |
|
|
|
|
|
|
|
|
if ( seg->link ) |
|
|
{ |
|
|
if ( seg->link > seg ) |
|
|
seg2 = seg->link; |
|
|
} |
|
|
else if ( seg->serif ) |
|
|
seg2 = seg->serif; |
|
|
|
|
|
if ( seg2 ) |
|
|
{ |
|
|
v1.x = seg->first->x - pp1; |
|
|
v2.x = seg2->first->x - pp1; |
|
|
v1.y = ( seg->first->y + seg->last->y ) / 2; |
|
|
v2.y = ( seg2->first->y + seg2->last->y ) / 2; |
|
|
|
|
|
link = ah_link_path( &v1, &v2, 1 ); |
|
|
|
|
|
nv_painter_set_color( painter, |
|
|
seg->serif ? SERIF_LINK_COLOR : LINK_COLOR, |
|
|
256 ); |
|
|
nv_painter_fill_path( painter, &size_transform, 0, link ); |
|
|
|
|
|
nv_path_destroy( link ); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
if ( option_show_horz_hints && option_show_links ) |
|
|
{ |
|
|
AH_Segment seg = glyph->horz_segments; |
|
|
FT_UInt count = glyph->num_hsegments; |
|
|
|
|
|
|
|
|
for ( ; count > 0; count--, seg++ ) |
|
|
{ |
|
|
AH_Segment seg2 = NULL; |
|
|
NV_Path link; |
|
|
NV_Vector v1, v2; |
|
|
|
|
|
|
|
|
if ( seg->link ) |
|
|
{ |
|
|
if ( seg->link > seg ) |
|
|
seg2 = seg->link; |
|
|
} |
|
|
else if ( seg->serif ) |
|
|
seg2 = seg->serif; |
|
|
|
|
|
if ( seg2 ) |
|
|
{ |
|
|
v1.y = seg->first->y; |
|
|
v2.y = seg2->first->y; |
|
|
v1.x = ( seg->first->x + seg->last->x ) / 2 - pp1; |
|
|
v2.x = ( seg2->first->x + seg2->last->x ) / 2 - pp1; |
|
|
|
|
|
link = ah_link_path( &v1, &v2, 0 ); |
|
|
|
|
|
nv_painter_set_color( painter, |
|
|
seg->serif ? SERIF_LINK_COLOR : LINK_COLOR, |
|
|
256 ); |
|
|
nv_painter_fill_path( painter, &size_transform, 0, link ); |
|
|
|
|
|
nv_path_destroy( link ); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/************************************************************************/ |
|
|
/************************************************************************/ |
|
|
/***** *****/ |
|
|
/***** MAIN LOOP(S) *****/ |
|
|
/***** *****/ |
|
|
/************************************************************************/ |
|
|
/************************************************************************/ |
|
|
|
|
|
static void |
|
|
draw_glyph( int glyph_index ) |
|
|
{ |
|
|
NV_Path path; |
|
|
|
|
|
|
|
|
pshint_vertical = -1; |
|
|
|
|
|
ps_debug_hint_func = option_show_ps_hints ? draw_ps_hint : 0; |
|
|
|
|
|
ah_debug_hinter = NULL; |
|
|
|
|
|
error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_BITMAP ); |
|
|
if ( error ) |
|
|
Panic( "could not load glyph" ); |
|
|
|
|
|
if ( face->glyph->format != FT_GLYPH_FORMAT_OUTLINE ) |
|
|
Panic( "could not load glyph outline" ); |
|
|
|
|
|
error = nv_path_new_from_outline( renderer, |
|
|
(NV_Outline*)&face->glyph->outline, |
|
|
&size_transform, |
|
|
&path ); |
|
|
if ( error ) |
|
|
Panic( "could not create glyph path" ); |
|
|
|
|
|
/* trac<EFBFBD> du glyphe plein */ |
|
|
if ( option_show_glyph ) |
|
|
{ |
|
|
nv_painter_set_color( painter, 0xFF404080, 128 ); |
|
|
nv_painter_fill_path( painter, 0, 0, path ); |
|
|
} |
|
|
|
|
|
if ( option_show_stroke ) |
|
|
{ |
|
|
NV_Path stroke; |
|
|
|
|
|
|
|
|
error = nv_path_stroke( path, 0.6, |
|
|
nv_path_linecap_butt, |
|
|
nv_path_linejoin_miter, |
|
|
1.0, &stroke ); |
|
|
if ( error ) |
|
|
Panic( "could not stroke glyph path" ); |
|
|
|
|
|
nv_painter_set_color( painter, 0xFF000040, 256 ); |
|
|
nv_painter_fill_path( painter, 0, 0, stroke ); |
|
|
|
|
|
nv_path_destroy( stroke ); |
|
|
} |
|
|
|
|
|
/* trac<EFBFBD> des points de controle */ |
|
|
if ( option_show_dots ) |
|
|
{ |
|
|
NV_Path plot; |
|
|
NV_Outline out; |
|
|
NV_Scale r = 2; |
|
|
NV_Int n, first, last; |
|
|
|
|
|
|
|
|
nv_path_get_outline( path, NULL, memory, &out ); |
|
|
|
|
|
first = 0; |
|
|
for ( n = 0; n < out.n_contours; n++ ) |
|
|
{ |
|
|
int m; |
|
|
NV_Transform trans; |
|
|
NV_Color color; |
|
|
NV_SubVector* vec; |
|
|
|
|
|
|
|
|
last = out.contours[n]; |
|
|
|
|
|
for ( m = first; m <= last; m++ ) |
|
|
{ |
|
|
color = (out.tags[m] & FT_CURVE_TAG_ON) |
|
|
? ON_COLOR |
|
|
: OFF_COLOR; |
|
|
|
|
|
vec = out.points + m; |
|
|
|
|
|
nv_transform_set_translate( &trans, vec->x / 64.0, vec->y / 64.0 ); |
|
|
|
|
|
nv_painter_set_color( painter, color, 256 ); |
|
|
nv_painter_fill_path( painter, &trans, 0, symbol_dot ); |
|
|
|
|
|
if ( option_show_indices ) |
|
|
{ |
|
|
char temp[5]; |
|
|
|
|
|
|
|
|
sprintf( temp, "%d", m ); |
|
|
nv_pixmap_cell_text( target, vec->x / 64 + 4, vec->y / 64 - 4, |
|
|
temp, TEXT_COLOR ); |
|
|
} |
|
|
} |
|
|
|
|
|
first = last + 1; |
|
|
} |
|
|
} |
|
|
|
|
|
ah_draw_smooth_points(); |
|
|
ah_draw_edges(); |
|
|
|
|
|
nv_path_destroy( path ); |
|
|
|
|
|
/* autre infos */ |
|
|
{ |
|
|
char temp[1024]; |
|
|
char temp2[64]; |
|
|
|
|
|
|
|
|
sprintf( temp, "font name : %s (%s)", face->family_name, |
|
|
face->style_name ); |
|
|
nv_pixmap_cell_text( target, 0, 0, temp, TEXT_COLOR ); |
|
|
|
|
|
FT_Get_Glyph_Name( face, glyph_index, temp2, 63 ); |
|
|
temp2[63] = 0; |
|
|
|
|
|
sprintf( temp, "glyph %4d: %s", glyph_index, temp2 ); |
|
|
nv_pixmap_cell_text( target, 0, 8, temp, TEXT_COLOR ); |
|
|
|
|
|
if ( temp_message[0] ) |
|
|
{ |
|
|
nv_pixmap_cell_text( target, 0, 16, temp_message, TEXT_COLOR ); |
|
|
temp_message[0] = 0; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#define TOGGLE_OPTION(var,prefix) \ |
|
|
do \ |
|
|
{ \ |
|
|
var = !var; \ |
|
|
sprintf( temp_message, prefix " is now %s", \ |
|
|
var ? "on" : "off" ); \ |
|
|
} \ |
|
|
while() |
|
|
|
|
|
|
|
|
#define TOGGLE_OPTION_NEG(var,prefix) \ |
|
|
do \ |
|
|
{ \ |
|
|
var = !var; \ |
|
|
sprintf( temp_message, prefix " is now %s", \ |
|
|
!var ? "on" : "off" ); \ |
|
|
} \ |
|
|
while |
|
|
|
|
|
|
|
|
static void |
|
|
handle_event( NVV_EventRec* ev ) |
|
|
{ |
|
|
switch ( ev->key ) |
|
|
{ |
|
|
case NVV_Key_Left: |
|
|
if ( glyph_index > 0 ) |
|
|
glyph_index--; |
|
|
break; |
|
|
|
|
|
case NVV_Key_Right: |
|
|
if ( glyph_index + 1 < face->num_glyphs ) |
|
|
glyph_index++; |
|
|
break; |
|
|
|
|
|
case NVV_KEY( 'x' ): |
|
|
TOGGLE_OPTION( option_show_axis, "grid axis display" ); |
|
|
break; |
|
|
|
|
|
case NVV_KEY( 's' ): |
|
|
TOGGLE_OPTION( option_show_stroke, "glyph stroke display" ); |
|
|
break; |
|
|
|
|
|
case NVV_KEY( 'g' ): |
|
|
TOGGLE_OPTION( option_show_glyph, "glyph fill display" ); |
|
|
break; |
|
|
|
|
|
case NVV_KEY( 'd' ): |
|
|
TOGGLE_OPTION( option_show_dots, "control points display" ); |
|
|
break |
|
|
|
|
|
case NVV_KEY( 'e' ): |
|
|
TOGGLE_OPTION( option_show_em, "EM square display" ); |
|
|
break; |
|
|
|
|
|
case NVV_KEY( '+' ): |
|
|
grid_scale *= 1.2; |
|
|
reset_scale( grid_scale ); |
|
|
break; |
|
|
|
|
|
case NVV_KEY( '-' ): |
|
|
if ( grid_scale > 0.3 ) |
|
|
{ |
|
|
grid_scale /= 1.2; |
|
|
reset_scale( grid_scale ); |
|
|
} |
|
|
break; |
|
|
|
|
|
case NVV_Key_Up: |
|
|
pixel_size++; |
|
|
reset_size( pixel_size, grid_scale ); |
|
|
sprintf( temp_message, "pixel size = %d", pixel_size ); |
|
|
break; |
|
|
|
|
|
case NVV_Key_Down: |
|
|
if ( pixel_size > 1 ) |
|
|
{ |
|
|
pixel_size--; |
|
|
reset_size( pixel_size, grid_scale ); |
|
|
sprintf( temp_message, "pixel size = %d", pixel_size ); |
|
|
} |
|
|
break; |
|
|
|
|
|
case NVV_KEY( 'z' ): |
|
|
TOGGLE_OPTION_NEG( ps_debug_no_vert_hints, "vertical hints processing" ); |
|
|
break; |
|
|
|
|
|
case NVV_KEY( 'a' ): |
|
|
TOGGLE_OPTION_NEG( ps_debug_no_horz_hints, "horizontal hints processing" ); |
|
|
break; |
|
|
|
|
|
case NVV_KEY( 'Z' ): |
|
|
TOGGLE_OPTION( option_show_vert_hints, "vertical hints display" ); |
|
|
break; |
|
|
|
|
|
case NVV_KEY( 'A' ): |
|
|
TOGGLE_OPTION( option_show_horz_hints, "horizontal hints display" ); |
|
|
break; |
|
|
|
|
|
case NVV_KEY( 'S' ): |
|
|
TOGGLE_OPTION( option_show_smooth, "smooth points display" ); |
|
|
break; |
|
|
|
|
|
case NVV_KEY( 'i' ): |
|
|
TOGGLE_OPTION( option_show_indices, "point index display" ); |
|
|
break; |
|
|
|
|
|
case NVV_KEY( 'b' ): |
|
|
TOGGLE_OPTION( option_show_blues, "blue zones display" ); |
|
|
break; |
|
|
|
|
|
case NVV_KEY( 'h' ): |
|
|
ps_debug_no_horz_hints = option_hinting; |
|
|
ps_debug_no_vert_hints = option_hinting; |
|
|
|
|
|
TOGGLE_OPTION( option_hinting, "hinting" ); |
|
|
break; |
|
|
|
|
|
case NVV_KEY( 'H' ): |
|
|
ps_print_hints(); |
|
|
break; |
|
|
|
|
|
default: |
|
|
; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void |
|
|
usage() |
|
|
{ |
|
|
Panic( "no usage" ); |
|
|
} |
|
|
|
|
|
|
|
|
#define OPTION1(n,code) \ |
|
|
case n : \ |
|
|
code \ |
|
|
argc--; \ |
|
|
argv++; \ |
|
|
break; |
|
|
|
|
|
#define OPTION2(n,code) \ |
|
|
case n : \ |
|
|
code \ |
|
|
argc -= 2; \ |
|
|
argv += 2; \ |
|
|
break; |
|
|
|
|
|
|
|
|
static void |
|
|
parse_options( int* argc_p, |
|
|
char*** argv_p ) |
|
|
{ |
|
|
int argc = *argc_p; |
|
|
char** argv = *argv_p; |
|
|
|
|
|
|
|
|
while ( argc > 2 && argv[1][0] == '-' ) |
|
|
{ |
|
|
switch ( argv[1][1] ) |
|
|
{ |
|
|
OPTION2( 'f', first_glyph = atoi( argv[2] ); ) |
|
|
|
|
|
OPTION2( 's', pixel_size = atoi( argv[2] ); ) |
|
|
|
|
|
default: |
|
|
usage(); |
|
|
} |
|
|
} |
|
|
|
|
|
*argc_p = argc; |
|
|
*argv_p = argv; |
|
|
} |
|
|
|
|
|
|
|
|
int |
|
|
main( int argc, |
|
|
char** argv ) |
|
|
{ |
|
|
char* filename = "/winnt/fonts/arial.ttf"; |
|
|
|
|
|
|
|
|
parse_options( &argc, &argv ); |
|
|
|
|
|
if ( argc >= 2 ) |
|
|
filename = argv[1]; |
|
|
|
|
|
|
|
|
/* create library */ |
|
|
error = nv_renderer_new( 0, &renderer ); |
|
|
if ( error ) |
|
|
Panic( "could not create Nirvana renderer" ); |
|
|
|
|
|
memory = nv_renderer_get_memory( renderer ); |
|
|
init_symbols(); |
|
|
|
|
|
error = nvv_display_new( renderer, &display ); |
|
|
if ( error ) |
|
|
Panic( "could not create display" ); |
|
|
|
|
|
error = nvv_surface_new( display, 460, 460, nv_pixmap_type_argb, &surface ); |
|
|
if ( error ) |
|
|
Panic( "could not create surface" ); |
|
|
|
|
|
target = nvv_surface_get_pixmap( surface ); |
|
|
|
|
|
error = nv_painter_new( renderer, &painter ); |
|
|
if ( error ) |
|
|
Panic( "could not create painter" ); |
|
|
|
|
|
nv_painter_set_target( painter, target ); |
|
|
|
|
|
clear_background(); |
|
|
|
|
|
error = FT_Init_FreeType( &freetype ); |
|
|
if ( error ) |
|
|
Panic( "could not initialize FreeType" ); |
|
|
|
|
|
error = FT_New_Face( freetype, filename, 0, &face ); |
|
|
if ( error ) |
|
|
Panic( "could not open font face" ); |
|
|
|
|
|
reset_size( pixel_size, grid_scale ); |
|
|
|
|
|
nvv_surface_set_title( surface, "FreeType Glyph Viewer" ); |
|
|
|
|
|
{ |
|
|
NVV_EventRec event; |
|
|
|
|
|
|
|
|
glyph_index = first_glyph; |
|
|
for ( ;; ) |
|
|
{ |
|
|
clear_background(); |
|
|
draw_grid(); |
|
|
|
|
|
ps_debug_hints = 0; |
|
|
ah_debug_hinter = 0; |
|
|
|
|
|
ah_debug_disable_vert = ps_debug_no_vert_hints; |
|
|
ah_debug_disable_horz = ps_debug_no_horz_hints; |
|
|
|
|
|
draw_ps_blue_zones(); |
|
|
draw_glyph( glyph_index ); |
|
|
ps_draw_control_points(); |
|
|
|
|
|
nvv_surface_refresh( surface, NULL ); |
|
|
|
|
|
nvv_surface_listen( surface, 0, &event ); |
|
|
if ( event.key == NVV_Key_Esc ) |
|
|
break; |
|
|
|
|
|
handle_event( &event ); |
|
|
switch ( event.key ) |
|
|
{ |
|
|
case NVV_Key_Esc: |
|
|
goto Exit; |
|
|
|
|
|
default: |
|
|
; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
Exit: |
|
|
/* wait for escape */ |
|
|
|
|
|
/* destroy display (and surface) */ |
|
|
nvv_display_unref( display ); |
|
|
|
|
|
done_symbols(); |
|
|
nv_renderer_unref( renderer ); |
|
|
|
|
|
return 0; |
|
|
}
|
|
|
|