forked from minhngoc25a/freetype2
1337 lines
35 KiB
C
1337 lines
35 KiB
C
#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/pshalgo1.h>
|
||
#include <../src/pshinter/pshalgo2.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 1 ROUTINES *****/
|
||
/***** *****/
|
||
/************************************************************************/
|
||
/************************************************************************/
|
||
|
||
#include <../src/pshinter/pshalgo1.h>
|
||
|
||
static int pshint_cpos = 0;
|
||
static int pshint_vertical = -1;
|
||
|
||
static void
|
||
draw_ps1_hint( PSH1_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,
|
||
psh1_hint_is_ghost(hint)
|
||
? GHOST_HINT_COLOR : STEM_HINT_COLOR );
|
||
|
||
if ( psh1_hint_is_ghost(hint) )
|
||
{
|
||
x1 --;
|
||
x2 = x1 + 2;
|
||
}
|
||
else
|
||
nv_pixmap_fill_rect( target, x2, 0, 1, target->height,
|
||
psh1_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,
|
||
psh1_hint_is_ghost(hint)
|
||
? GHOST_HINT_COLOR : STEM_HINT_COLOR );
|
||
|
||
if ( psh1_hint_is_ghost(hint) )
|
||
{
|
||
x1 --;
|
||
x2 = x1 + 2;
|
||
}
|
||
else
|
||
nv_pixmap_fill_rect( target, 0, x2, target->width, 1,
|
||
psh1_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;
|
||
}
|
||
|
||
|
||
|
||
/************************************************************************/
|
||
/************************************************************************/
|
||
/***** *****/
|
||
/***** POSTSCRIPT HINTER ALGORITHM 2 ROUTINES *****/
|
||
/***** *****/
|
||
/************************************************************************/
|
||
/************************************************************************/
|
||
|
||
#include <../src/pshinter/pshalgo2.h>
|
||
|
||
static void
|
||
draw_ps2_hint( PSH2_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,
|
||
psh2_hint_is_ghost(hint)
|
||
? GHOST_HINT_COLOR : STEM_HINT_COLOR );
|
||
|
||
if ( psh2_hint_is_ghost(hint) )
|
||
{
|
||
x1 --;
|
||
x2 = x1 + 2;
|
||
}
|
||
else
|
||
nv_pixmap_fill_rect( target, x2, 0, 1, target->height,
|
||
psh2_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,
|
||
psh2_hint_is_ghost(hint)
|
||
? GHOST_HINT_COLOR : STEM_HINT_COLOR );
|
||
|
||
if ( psh2_hint_is_ghost(hint) )
|
||
{
|
||
x1 --;
|
||
x2 = x1 + 2;
|
||
}
|
||
else
|
||
nv_pixmap_fill_rect( target, 0, x2, target->width, 1,
|
||
psh2_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
|
||
ps2_draw_control_points( void )
|
||
{
|
||
if ( ps2_debug_glyph )
|
||
{
|
||
PSH2_Glyph glyph = ps2_debug_glyph;
|
||
PSH2_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 && !psh2_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 & PSH2_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 & PSH2_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;
|
||
PSH_Dimension dim;
|
||
|
||
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 verticla 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_Point *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, 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_Point *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, 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;
|
||
|
||
ps1_debug_hint_func = option_show_ps_hints ? draw_ps1_hint : 0;
|
||
ps2_debug_hint_func = option_show_ps_hints ? draw_ps2_hint : 0;
|
||
|
||
ah_debug_hinter = NULL;
|
||
|
||
error = FT_Load_Glyph( face, glyph_index, option_hinting
|
||
? FT_LOAD_NO_BITMAP
|
||
: FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING );
|
||
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<61> 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<61> 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) \
|
||
{ \
|
||
var = !var; \
|
||
sprintf( temp_message, prefix " is now %s", \
|
||
var ? "on" : "off" ); \
|
||
break; \
|
||
}
|
||
|
||
|
||
#define TOGGLE_OPTION_NEG(var,prefix) \
|
||
{ \
|
||
var = !var; \
|
||
sprintf( temp_message, prefix " is now %s", \
|
||
!var ? "on" : "off" ); \
|
||
break; \
|
||
}
|
||
|
||
|
||
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" )
|
||
|
||
case NVV_KEY('s'):
|
||
TOGGLE_OPTION( option_show_stroke, "glyph stroke display" )
|
||
|
||
case NVV_KEY('g'):
|
||
TOGGLE_OPTION( option_show_glyph, "glyph fill display" )
|
||
|
||
case NVV_KEY('d'):
|
||
TOGGLE_OPTION( option_show_dots, "control points display" )
|
||
|
||
case NVV_KEY('e'):
|
||
TOGGLE_OPTION( option_show_em, "EM square display" )
|
||
|
||
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" )
|
||
|
||
case NVV_KEY('a'):
|
||
TOGGLE_OPTION_NEG( ps_debug_no_horz_hints, "horizontal hints processing" )
|
||
|
||
case NVV_KEY('Z'):
|
||
TOGGLE_OPTION( option_show_vert_hints, "vertical hints display" )
|
||
|
||
case NVV_KEY('A'):
|
||
TOGGLE_OPTION( option_show_horz_hints, "horizontal hints display" )
|
||
|
||
case NVV_KEY('S'):
|
||
TOGGLE_OPTION( option_show_smooth, "smooth points display" );
|
||
|
||
case NVV_KEY('i'):
|
||
TOGGLE_OPTION( option_show_indices, "point index display" );
|
||
|
||
case NVV_KEY('b'):
|
||
TOGGLE_OPTION( option_show_blues, "blue zones display" );
|
||
|
||
case NVV_KEY('h'):
|
||
TOGGLE_OPTION( option_hinting, "hinting" )
|
||
|
||
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 initialise 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 );
|
||
ps2_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;
|
||
}
|