commited new Postscript hinter module

This commit is contained in:
David Turner 2001-10-05 08:59:06 +00:00
parent fbb7617183
commit 49884d3eeb
21 changed files with 3157 additions and 1147 deletions

14
Jamfile
View File

@ -15,6 +15,13 @@ FT2_SRC = [ FT2_SubDir src ] ;
FT2_LIB = $(LIBPREFIX)freetype ;
if $(DEBUG_HINTER)
{
CCFLAGS += -DDEBUG_HINTER ;
}
# We need "freetype2/include" in the current include path in order to
# compile any part of FreeType 2.
#
@ -38,8 +45,11 @@ HDRMACRO [ FT2_SubDir include freetype internal internal.h ] ;
SubInclude FT2_TOP src ;
# tests files
# tests files (hinter debugging)
#
SubInclude FT2_TOP tests ;
if $(DEBUG_HINTER)
{
SubInclude FT2_TOP tests ;
}
# end of top Jamfile

View File

@ -141,7 +141,7 @@
FT_String* name = (FT_String*)decoder->glyph_names[n];
if ( name && strcmp( name,glyph_name ) == 0 )
if ( name && name[0] == glyph_name[0] && strcmp( name,glyph_name ) == 0 )
return n;
}
@ -245,6 +245,7 @@
glyph->format = ft_glyph_format_composite;
loader->current.num_subglyphs = 2;
goto Exit;
}
/* First load `bchar' in builder */
@ -318,7 +319,7 @@
FT_Byte* ip;
FT_Byte* limit;
T1_Builder* builder = &decoder->builder;
FT_Pos x, y;
FT_Pos x, y, orig_x, orig_y;
T1_Hints_Funcs hinter;
@ -345,8 +346,8 @@
error = PSaux_Err_Ok;
x = builder->pos_x;
y = builder->pos_y;
x = orig_x = builder->pos_x;
y = orig_y = builder->pos_y;
/* begin hints recording session, if any */
if ( hinter )
@ -740,8 +741,8 @@
builder->advance.x = top[1];
builder->advance.y = 0;
builder->last.x = x = builder->pos_x + top[0];
builder->last.y = y = builder->pos_y;
orig_x = builder->last.x = x = builder->pos_x + top[0];
orig_y = builder->last.y = y = builder->pos_y;
/* the `metrics_only' indicates that we only want to compute */
/* the glyph's metrics (lsb + advance width), not load the */
@ -1016,7 +1017,7 @@
/* record vertical hint */
if ( hinter )
{
top[0] += builder->left_bearing.x;
top[0] += orig_x;
hinter->stem( hinter->hints, 1, top );
}
@ -1027,8 +1028,14 @@
/* record vertical counter-controlled hints */
if ( hinter )
{
FT_Pos dx = orig_x;
top[0] += dx;
top[2] += dx;
top[4] += dx;
hinter->stem3( hinter->hints, 1, top );
}
break;
case op_setcurrentpoint:

View File

@ -10,7 +10,7 @@ SubDirHdrs [ FT2_SubDir src pshinter ] ;
if $(FT2_MULTI)
{
_sources = pshrec pshglob pshfit pshmod pshoptim ;
_sources = pshrec pshglob pshalgo1 pshalgo2 pshmod ;
}
else
{

19
src/pshinter/pshalgo.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef __PS_HINTER_ALGO_H__
#define __PS_HINTER_ALGO_H__
FT_BEGIN_HEADER
/* define to choose hinting algorithm */
#define PSH_ALGORITHM_2
#ifdef PSH_ALGORITHM_1
# include "pshalgo1.h"
# define PS_HINTS_APPLY_FUNC ps1_hints_apply
#else
# include "pshalgo2.h"
# define PS_HINTS_APPLY_FUNC ps2_hints_apply
#endif
FT_END_HEADER
#endif /* __PS_HINTER_ALGO_H__ */

736
src/pshinter/pshalgo1.c Normal file
View File

@ -0,0 +1,736 @@
#include <ft2build.h>
#include FT_INTERNAL_OBJECTS_H
#include FT_INTERNAL_DEBUG_H
#include "pshalgo1.h"
#ifdef DEBUG_HINTER
extern PSH1_Hint_Table ps1_debug_hint_table = 0;
extern PSH1_HintFunc ps1_debug_hint_func = 0;
#endif
/************************************************************************/
/************************************************************************/
/***** *****/
/***** BASIC HINTS RECORDINGS *****/
/***** *****/
/************************************************************************/
/************************************************************************/
/* return true iff two stem hints overlap */
static FT_Int
psh1_hint_overlap( PSH1_Hint hint1,
PSH1_Hint hint2 )
{
return ( hint1->org_pos + hint1->org_len >= hint2->org_pos &&
hint2->org_pos + hint2->org_len >= hint1->org_pos );
}
/* destroy hints table */
static void
psh1_hint_table_done( PSH1_Hint_Table table,
FT_Memory memory )
{
FREE( table->zones );
table->num_zones = 0;
table->zone = 0;
FREE( table->sort );
FREE( table->hints );
table->num_hints = 0;
table->max_hints = 0;
table->sort_global = 0;
}
/* deactivate all hints in a table */
static void
psh1_hint_table_deactivate( PSH1_Hint_Table table )
{
FT_UInt count = table->max_hints;
PSH1_Hint hint = table->hints;
for ( ; count > 0; count--, hint++ )
{
psh1_hint_deactivate(hint);
hint->order = -1;
}
}
/* internal function used to record a new hint */
static void
psh1_hint_table_record( PSH1_Hint_Table table,
FT_UInt index )
{
PSH1_Hint hint = table->hints + index;
if ( index >= table->max_hints )
{
FT_ERROR(( "%s.activate: invalid hint index %d\n", index ));
return;
}
/* ignore active hints */
if ( psh1_hint_is_active(hint) )
return;
psh1_hint_activate(hint);
/* now scan the current active hint set in order to determine */
/* if we're overlapping with another segment.. */
{
PSH1_Hint* sorted = table->sort_global;
FT_UInt count = table->num_hints;
PSH1_Hint hint2;
hint->parent = 0;
for ( ; count > 0; count--, sorted++ )
{
hint2 = sorted[0];
if ( psh1_hint_overlap( hint, hint2 ) )
{
hint->parent = hint2;
break;
}
}
}
if ( table->num_hints < table->max_hints )
table->sort_global[ table->num_hints++ ] = hint;
else
{
FT_ERROR(( "%s.activate: too many sorted hints !! BUG !!\n",
"ps.fitter" ));
}
}
static void
psh1_hint_table_record_mask( PSH1_Hint_Table table,
PS_Mask hint_mask )
{
FT_Int mask = 0, val = 0;
FT_Byte* cursor = hint_mask->bytes;
FT_UInt index, limit;
limit = hint_mask->num_bits;
if ( limit != table->max_hints )
{
FT_ERROR(( "%s.activate_mask: invalid bit count (%d instead of %d)\n",
"ps.fitter", hint_mask->num_bits, table->max_hints ));
}
for ( index = 0; index < limit; index++ )
{
if ( mask == 0 )
{
val = *cursor++;
mask = 0x80;
}
if ( val & mask )
psh1_hint_table_record( table, index );
mask >>= 1;
}
}
/* create hints table */
static FT_Error
psh1_hint_table_init( PSH1_Hint_Table table,
PS_Hint_Table hints,
PS_Mask_Table hint_masks,
PS_Mask_Table counter_masks,
FT_Memory memory )
{
FT_UInt count = hints->num_hints;
FT_Error error;
FT_UNUSED(counter_masks);
/* allocate our tables */
if ( ALLOC_ARRAY( table->sort, 2*count, PSH1_Hint ) ||
ALLOC_ARRAY( table->hints, count, PSH1_HintRec ) ||
ALLOC_ARRAY( table->zones, 2*count+1, PSH1_ZoneRec ) )
goto Exit;
table->max_hints = count;
table->sort_global = table->sort + count;
table->num_hints = 0;
table->num_zones = 0;
table->zone = 0;
/* now, initialise the "hints" array */
{
PSH1_Hint write = table->hints;
PS_Hint read = hints->hints;
for ( ; count > 0; count--, write++, read++ )
{
write->org_pos = read->pos;
write->org_len = read->len;
write->flags = read->flags;
}
}
/* we now need to determine the initial "parent" stems, first */
/* activate the hints that are given by the initial hint masks */
if ( hint_masks )
{
FT_UInt count = hint_masks->num_masks;
PS_Mask mask = hint_masks->masks;
table->hint_masks = hint_masks;
for ( ; count > 0; count--, mask++ )
psh1_hint_table_record_mask( table, mask );
}
/* now, do a linear parse in case some hints were left alone */
if ( table->num_hints != table->max_hints )
{
FT_UInt index, count;
FT_ERROR(( "%s.init: missing/incorrect hint masks !!\n" ));
count = table->max_hints;
for ( index = 0; index < count; index++ )
psh1_hint_table_record( table, index );
}
Exit:
return error;
}
static void
psh1_hint_table_activate_mask( PSH1_Hint_Table table,
PS_Mask hint_mask )
{
FT_Int mask = 0, val = 0;
FT_Byte* cursor = hint_mask->bytes;
FT_UInt index, limit, count;
limit = hint_mask->num_bits;
count = 0;
psh1_hint_table_deactivate( table );
for ( index = 0; index < limit; index++ )
{
if ( mask == 0 )
{
val = *cursor++;
mask = 0x80;
}
if ( val & mask )
{
PSH1_Hint hint = &table->hints[index];
if ( !psh1_hint_is_active(hint) )
{
PSH1_Hint* sort = table->sort;
FT_UInt count2;
PSH1_Hint hint2;
for ( count2 = count; count2 > 0; count2--, sort++ )
{
hint2 = sort[0];
if ( psh1_hint_overlap( hint, hint2 ) )
{
FT_ERROR(( "%s.activate_mask: found overlapping hints\n",
"psf.hint" ));
break;
}
}
if ( count2 == 0 )
{
psh1_hint_activate( hint );
if ( count < table->max_hints )
table->sort[count++] = hint;
else
{
FT_ERROR(( "%s.activate_mask: too many active hints\n",
"psf.hint" ));
}
}
}
}
mask >>= 1;
}
table->num_hints = count;
/* now, sort the hints, they're guaranteed to not overlap */
/* so we can compare their "org_pos" field directly.. */
{
FT_Int i1, i2;
PSH1_Hint hint1, hint2;
PSH1_Hint* sort = table->sort;
/* a simple bubble sort will do, since in 99% of cases, the hints */
/* will be already sorted.. and the sort will be linear */
for ( i1 = 1; i1 < (FT_Int)count; i1++ )
{
hint1 = sort[i1];
for ( i2 = i1-1; i2 >= 0; i2-- )
{
hint2 = sort[i2];
if ( hint2->org_pos < hint1->org_pos )
break;
sort[i1] = hint2;
sort[i2] = hint1;
}
}
}
}
/************************************************************************/
/************************************************************************/
/***** *****/
/***** HINTS GRID-FITTING AND OPTIMISATION *****/
/***** *****/
/************************************************************************/
/************************************************************************/
#ifdef DEBUG_HINTER
void
ps_simple_scale( PSH1_Hint_Table table,
FT_Fixed scale,
FT_Fixed delta,
FT_Bool vertical )
{
PSH1_Hint hint;
FT_UInt count;
for ( count = 0; count < table->num_hints; count++ )
{
hint = table->sort[count];
if ( psh1_hint_is_active(hint) )
{
hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
hint->cur_len = FT_MulFix( hint->org_len, scale );
if (ps1_debug_hint_func)
ps1_debug_hint_func( hint, vertical );
}
}
}
#endif
FT_LOCAL_DEF FT_Error
psh1_hint_table_optimize( PSH1_Hint_Table table,
PSH_Globals globals,
FT_Outline* outline,
FT_Bool vertical )
{
PSH_Dimension dim = &globals->dimension[vertical];
FT_Fixed scale = dim->scale_mult;
FT_Fixed delta = dim->scale_delta;
#ifdef DEBUG_HINTER
if ( ps_debug_no_vert_hints && vertical )
{
ps_simple_scale( table, scale, delta, vertical );
return 0;
}
if ( ps_debug_no_horz_hints && !vertical )
{
ps_simple_scale( table, scale, delta, vertical );
return 0;
}
#endif
/* XXXX: for now, we only scale the hints to test all other aspects */
/* of the Postscript Hinter.. */
{
PSH1_Hint hint;
FT_UInt count;
for ( count = 0; count < table->num_hints; count++ )
{
hint = table->sort[count];
if ( psh1_hint_is_active(hint) )
{
# if 1
FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
FT_Pos len = FT_MulFix( hint->org_len, scale );
FT_Pos fit_center;
FT_Pos fit_len;
PSH_AlignmentRec align;
/* compute fitted width/height */
fit_len = psh_dimension_snap_width( dim, hint->org_len );
if ( fit_len < 64 )
fit_len = 64;
else
fit_len = (fit_len + 32 ) & -64;
hint->cur_len = fit_len;
/* check blue zones for horizontal stems */
align.align = 0;
if (!vertical)
{
psh_blues_snap_stem( &globals->blues,
hint->org_pos + hint->org_len,
hint->org_pos,
&align );
}
switch (align.align)
{
case PSH_BLUE_ALIGN_TOP:
{
/* the top of the stem is aligned against a blue zone */
hint->cur_pos = align.align_top - fit_len;
break;
}
case PSH_BLUE_ALIGN_BOT:
{
/* the bottom of the stem is aligned against a blue zone */
hint->cur_pos = align.align_bot;
break;
}
case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
{
/* both edges of the stem are aligned against blue zones */
hint->cur_pos = align.align_bot;
hint->cur_len = align.align_top - align.align_bot;
}
break;
default:
/* normal processing */
if ( (fit_len/64) & 1 )
{
/* odd number of pixels */
fit_center = ((pos + (len >> 1)) & -64) + 32;
}
else
{
/* even number of pixels */
fit_center = (pos + (len >> 1) + 32) & -64;
}
hint->cur_pos = fit_center - (fit_len >> 1);
}
# else
hint->cur_pos = (FT_MulFix( hint->org_pos, scale ) + delta + 32) & -64;
hint->cur_len = FT_MulFix( hint->org_len, scale );
# endif
#ifdef DEBUG_HINTER
if (ps1_debug_hint_func)
ps1_debug_hint_func( hint, vertical );
#endif
}
}
}
return 0;
}
/************************************************************************/
/************************************************************************/
/***** *****/
/***** POINTS INTERPOLATION ROUTINES *****/
/***** *****/
/************************************************************************/
/************************************************************************/
#define PSH1_ZONE_MIN -3200000
#define PSH1_ZONE_MAX +3200000
#define xxDEBUG_ZONES
#ifdef DEBUG_ZONES
#include <stdio.h>
static void
print_zone( PSH1_Zone zone )
{
printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
zone->scale/65536.0,
zone->delta/64.0,
zone->min,
zone->max );
}
#else
# define print_zone(x) do { } while (0)
#endif
/* setup interpolation zones once the hints have been grid-fitted */
/* by the optimizer.. */
static void
psh1_hint_table_setup_zones( PSH1_Hint_Table table,
FT_Fixed scale,
FT_Fixed delta )
{
FT_UInt count;
PSH1_Zone zone;
PSH1_Hint *sort, hint, hint2;
zone = table->zones;
/* special case, no hints defined */
if ( table->num_hints == 0 )
{
zone->scale = scale;
zone->delta = delta;
zone->min = PSH1_ZONE_MIN;
zone->max = PSH1_ZONE_MAX;
table->num_zones = 1;
table->zone = zone;
return;
}
/* the first zone is before the first hint */
/* x' = (x-x0)*s + x0' = x*s + ( x0' - x0*s ) */
sort = table->sort;
hint = sort[0];
zone->scale = scale;
zone->delta = hint->cur_pos - FT_MulFix( hint->org_pos, scale );
zone->min = PSH1_ZONE_MIN;
zone->max = hint->org_pos;
print_zone( zone );
zone++;
for ( count = table->num_hints; count > 0; count-- )
{
FT_Fixed scale2;
if ( hint->org_len > 0 )
{
/* setup a zone for inner-stem interpolation */
/* (x' - x0') = (x - x0)*(x1'-x0')/(x1-x0) */
/* x' = x*s2 + x0' - x0*s2 */
scale2 = FT_DivFix( hint->cur_len, hint->org_len );
zone->scale = scale2;
zone->min = hint->org_pos;
zone->max = hint->org_pos + hint->org_len;
zone->delta = hint->cur_pos - FT_MulFix( zone->min, scale2 );
print_zone( zone );
zone++;
}
if ( count == 1 )
break;
sort++;
hint2 = sort[0];
/* setup zone for inter-stem interpolation */
/* (x'-x1') = (x-x1)*(x2'-x1')/(x2-x1) */
/* x' = x*s3 + x1' - x1*s3 */
scale2 = FT_DivFix( hint2->cur_pos - (hint->cur_pos + hint->cur_len),
hint2->org_pos - (hint->org_pos + hint->org_len) );
zone->scale = scale2;
zone->min = hint->org_pos + hint->org_len;
zone->max = hint2->org_pos;
zone->delta = hint->cur_pos + hint->cur_len - FT_MulFix( zone->min, scale2 );
print_zone( zone );
zone++;
hint = hint2;
}
/* the last zone */
zone->scale = scale;
zone->min = hint->org_pos + hint->org_len;
zone->max = PSH1_ZONE_MAX;
zone->delta = hint->cur_pos + hint->cur_len - FT_MulFix( zone->min, scale );
print_zone( zone );
zone++;
table->num_zones = zone - table->zones;
table->zone = table->zones;
}
/* tune a single coordinate with the current interpolation zones */
static FT_Pos
psh1_hint_table_tune_coord( PSH1_Hint_Table table,
FT_Int coord )
{
PSH1_Zone zone;
zone = table->zone;
if ( coord < zone->min )
{
do
{
if ( zone == table->zones )
break;
zone--;
}
while ( coord < zone->min );
table->zone = zone;
}
else if ( coord > zone->max )
{
do
{
if ( zone == table->zones + table->num_zones - 1 )
break;
zone++;
}
while ( coord > zone->max );
table->zone = zone;
}
return FT_MulFix( coord, zone->scale ) + zone->delta;
}
/* tune a given outline with current interpolation zones */
/* the function only works in a single dimension.. */
static void
psh1_hint_table_tune_outline( PSH1_Hint_Table table,
FT_Outline* outline,
PSH_Globals globals,
FT_Bool vertical )
{
FT_UInt count, first, last;
PS_Mask_Table hint_masks = table->hint_masks;
PS_Mask mask;
PSH_Dimension dim = &globals->dimension[vertical];
FT_Fixed scale = dim->scale_mult;
FT_Fixed delta = dim->scale_delta;
if ( hint_masks && hint_masks->num_masks > 0 )
{
first = 0;
mask = hint_masks->masks;
count = hint_masks->num_masks;
for ( ; count > 0; count--, mask++ )
{
last = mask->end_point;
if ( last > first )
{
FT_Vector* vec;
FT_Int count2;
psh1_hint_table_activate_mask( table, mask );
psh1_hint_table_optimize( table, globals, outline, vertical );
psh1_hint_table_setup_zones( table, scale, delta );
last = mask->end_point;
vec = outline->points + first;
count2 = last - first;
for ( ; count2 > 0; count2--, vec++ )
{
FT_Pos x, *px;
px = vertical ? &vec->x : &vec->y;
x = *px;
*px = psh1_hint_table_tune_coord( table, (FT_Int)x );
}
}
first = last;
}
}
else /* no hints in this glyph, simply scale the outline */
{
FT_Vector* vec;
vec = outline->points;
count = outline->n_points;
if ( vertical )
{
for ( ; count > 0; count--, vec++ )
vec->x = FT_MulFix( vec->x, scale ) + delta;
}
else
{
for ( ; count > 0; count--, vec++ )
vec->y = FT_MulFix( vec->y, scale ) + delta;
}
}
}
/************************************************************************/
/************************************************************************/
/***** *****/
/***** HIGH-LEVEL INTERFACE *****/
/***** *****/
/************************************************************************/
/************************************************************************/
FT_Error
ps1_hints_apply( PS_Hints ps_hints,
FT_Outline* outline,
PSH_Globals globals )
{
PSH1_Hint_TableRec hints;
FT_Error error;
FT_Int dimension;
for ( dimension = 1; dimension >= 0; dimension-- )
{
PS_Dimension dim = &ps_hints->dimension[dimension];
/* initialise hints table */
memset( &hints, 0, sizeof(hints) );
error = psh1_hint_table_init( &hints,
&dim->hints,
&dim->masks,
&dim->counters,
ps_hints->memory );
if (error) goto Exit;
psh1_hint_table_tune_outline( &hints,
outline,
globals,
dimension );
psh1_hint_table_done( &hints, ps_hints->memory );
}
Exit:
return error;
}

100
src/pshinter/pshalgo1.h Normal file
View File

@ -0,0 +1,100 @@
/***************************************************************************/
/* */
/* pshalgo1.h */
/* */
/* First (basic) Postscript hinting routines */
/* */
/* Copyright 2001 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
/* modified, and distributed under the terms of the FreeType project */
/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
/* this file you indicate that you have read the license and */
/* understand and accept it fully. */
/* */
/***************************************************************************/
#ifndef __PS_HINTER_ALGO1_H__
#define __PS_HINTER_ALGO1_H__
#include "pshrec.h"
FT_BEGIN_HEADER
typedef struct PSH1_HintRec_* PSH1_Hint;
typedef enum
{
PSH1_HINT_FLAG_GHOST = PS_HINT_FLAG_GHOST,
PSH1_HINT_FLAG_BOTTOM = PS_HINT_FLAG_BOTTOM,
PSH1_HINT_FLAG_ACTIVE = 4
} PSH1_Hint_Flags;
#define psh1_hint_is_active(x) (((x)->flags & PSH1_HINT_FLAG_ACTIVE) != 0)
#define psh1_hint_is_ghost(x) (((x)->flags & PSH1_HINT_FLAG_GHOST ) != 0)
#define psh1_hint_activate(x) (x)->flags |= PSH1_HINT_FLAG_ACTIVE
#define psh1_hint_deactivate(x) (x)->flags &= ~PSH1_HINT_FLAG_ACTIVE
typedef struct PSH1_HintRec_
{
FT_Int org_pos;
FT_Int org_len;
FT_Pos cur_pos;
FT_Pos cur_len;
FT_UInt flags;
PSH1_Hint parent;
FT_Int order;
} PSH1_HintRec;
/* this is an interpolation zone used for strong points */
/* weak points are interpolated according to their strong */
/* neighbours.. */
typedef struct PSH1_ZoneRec_
{
FT_Fixed scale;
FT_Fixed delta;
FT_Pos min;
FT_Pos max;
} PSH1_ZoneRec, *PSH1_Zone;
typedef struct PSH1_Hint_TableRec_
{
FT_UInt max_hints;
FT_UInt num_hints;
PSH1_Hint hints;
PSH1_Hint* sort;
PSH1_Hint* sort_global;
FT_UInt num_zones;
PSH1_Zone zones;
PSH1_Zone zone;
PS_Mask_Table hint_masks;
PS_Mask_Table counter_masks;
} PSH1_Hint_TableRec, *PSH1_Hint_Table;
extern FT_Error
ps1_hints_apply( PS_Hints ps_hints,
FT_Outline* outline,
PSH_Globals globals );
#ifdef DEBUG_HINTER
extern PSH1_Hint_Table ps1_debug_hint_table;
typedef void (*PSH1_HintFunc)( PSH1_Hint hint, FT_Bool vertical );
extern PSH1_HintFunc ps1_debug_hint_func;
#endif
FT_END_HEADER
#endif /* __PS_HINTER_FITTER_H__ */

1484
src/pshinter/pshalgo2.c Normal file

File diff suppressed because it is too large Load Diff

185
src/pshinter/pshalgo2.h Normal file
View File

@ -0,0 +1,185 @@
/***************************************************************************/
/* */
/* pshalgo2.h */
/* */
/* First (basic) Postscript hinting routines */
/* */
/* Copyright 2001 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
/* modified, and distributed under the terms of the FreeType project */
/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
/* this file you indicate that you have read the license and */
/* understand and accept it fully. */
/* */
/***************************************************************************/
#ifndef __PS_HINTER_ALGO2_H__
#define __PS_HINTER_ALGO2_H__
#include "pshrec.h"
#include "pshglob.h"
#include FT_TRIGONOMETRY_H
FT_BEGIN_HEADER
typedef struct PSH2_HintRec_* PSH2_Hint;
typedef enum
{
PSH2_HINT_GHOST = PS_HINT_FLAG_GHOST,
PSH2_HINT_BOTTOM = PS_HINT_FLAG_BOTTOM,
PSH2_HINT_ACTIVE = 4,
PSH2_HINT_FITTED = 8
} PSH2_Hint_Flags;
#define psh2_hint_is_active(x) (((x)->flags & PSH2_HINT_ACTIVE) != 0)
#define psh2_hint_is_ghost(x) (((x)->flags & PSH2_HINT_GHOST) != 0)
#define psh2_hint_is_fitted(x) (((x)->flags & PSH2_HINT_FITTED) != 0)
#define psh2_hint_activate(x) (x)->flags |= PSH2_HINT_ACTIVE
#define psh2_hint_deactivate(x) (x)->flags &= ~PSH2_HINT_ACTIVE
#define psh2_hint_set_fitted(x) (x)->flags |= PSH2_HINT_FITTED
typedef struct PSH2_HintRec_
{
FT_Int org_pos;
FT_Int org_len;
FT_Pos cur_pos;
FT_Pos cur_len;
FT_UInt flags;
PSH2_Hint parent;
FT_Int order;
} PSH2_HintRec;
/* this is an interpolation zone used for strong points */
/* weak points are interpolated according to their strong */
/* neighbours.. */
typedef struct PSH2_ZoneRec_
{
FT_Fixed scale;
FT_Fixed delta;
FT_Pos min;
FT_Pos max;
} PSH2_ZoneRec, *PSH2_Zone;
typedef struct PSH2_Hint_TableRec_
{
FT_UInt max_hints;
FT_UInt num_hints;
PSH2_Hint hints;
PSH2_Hint* sort;
PSH2_Hint* sort_global;
FT_UInt num_zones;
PSH2_Zone zones;
PSH2_Zone zone;
PS_Mask_Table hint_masks;
PS_Mask_Table counter_masks;
} PSH2_Hint_TableRec, *PSH2_Hint_Table;
typedef struct PSH2_PointRec_* PSH2_Point;
typedef struct PSH2_ContourRec_* PSH2_Contour;
enum
{
PSH2_DIR_NONE = 4,
PSH2_DIR_UP = 1,
PSH2_DIR_DOWN = -1,
PSH2_DIR_LEFT = -2,
PSH2_DIR_RIGHT = 2
};
enum
{
PSH2_POINT_OFF = 1, /* point is off the curve */
PSH2_POINT_STRONG = 2, /* point is strong */
PSH2_POINT_SMOOTH = 4, /* point is smooth */
PSH2_POINT_FITTED = 8 /* point is already fitted */
};
typedef struct PSH2_PointRec_
{
PSH2_Point prev;
PSH2_Point next;
PSH2_Contour contour;
FT_UInt flags;
FT_Char dir_in;
FT_Char dir_out;
FT_Angle angle_in;
FT_Angle angle_out;
PSH2_Hint hint;
FT_Pos org_u;
FT_Pos cur_u;
#ifdef DEBUG_HINTER
FT_Pos org_x;
FT_Pos cur_x;
FT_Pos org_y;
FT_Pos cur_y;
FT_UInt flags_x;
FT_UInt flags_y;
#endif
} PSH2_PointRec;
#define psh2_point_is_strong(p) ((p)->flags & PSH2_POINT_STRONG)
#define psh2_point_is_fitted(p) ((p)->flags & PSH2_POINT_FITTED)
#define psh2_point_is_smooth(p) ((p)->flags & PSH2_POINT_SMOOTH)
#define psh2_point_set_strong(p) (p)->flags |= PSH2_POINT_STRONG
#define psh2_point_set_fitted(p) (p)->flags |= PSH2_POINT_FITTED
#define psh2_point_set_smooth(p) (p)->flags |= PSH2_POINT_SMOOTH
typedef struct PSH2_ContourRec_
{
PSH2_Point start;
FT_UInt count;
} PSH2_ContourRec;
typedef struct PSH2_GlyphRec_
{
FT_UInt num_points;
FT_UInt num_contours;
PSH2_Point points;
PSH2_Contour contours;
FT_Memory memory;
FT_Outline* outline;
PSH_Globals globals;
PSH2_Hint_TableRec hint_tables[2];
FT_Bool vertical;
FT_Int major_dir;
FT_Int minor_dir;
} PSH2_GlyphRec, *PSH2_Glyph;
#ifdef DEBUG_HINTER
extern PSH2_Hint_Table ps2_debug_hint_table;
typedef void (*PSH2_HintFunc)( PSH2_Hint hint, FT_Bool vertical );
extern PSH2_HintFunc ps2_debug_hint_func;
extern PSH2_Glyph ps2_debug_glyph;
#endif
extern FT_Error
ps2_hints_apply( PS_Hints ps_hints,
FT_Outline* outline,
PSH_Globals globals );
FT_END_HEADER
#endif /* __PS_HINTS_ALGO_2_H__ */

View File

@ -1,555 +0,0 @@
#include <ft2build.h>
#include FT_INTERNAL_OBJECTS_H
#include FT_INTERNAL_DEBUG_H
#include "pshfit.h"
#include "pshoptim.h"
/* return true iff two stem hints overlap */
static FT_Int
psh_hint_overlap( PSH_Hint hint1,
PSH_Hint hint2 )
{
return ( hint1->org_pos + hint1->org_len >= hint2->org_pos &&
hint2->org_pos + hint2->org_len >= hint1->org_pos );
}
/* destroy hints table */
static void
psh_hint_table_done( PSH_Hint_Table table,
FT_Memory memory )
{
FREE( table->zones );
table->num_zones = 0;
table->zone = 0;
FREE( table->sort );
FREE( table->hints );
table->num_hints = 0;
table->max_hints = 0;
table->sort_global = 0;
}
/* deactivate all hints in a table */
static void
psh_hint_table_deactivate( PSH_Hint_Table table )
{
FT_UInt count = table->max_hints;
PSH_Hint hint = table->hints;
for ( ; count > 0; count--, hint++ )
{
psh_hint_deactivate(hint);
hint->order = -1;
}
}
/* internal function used to record a new hint */
static void
psh_hint_table_record( PSH_Hint_Table table,
FT_UInt index )
{
PSH_Hint hint = table->hints + index;
if ( index >= table->max_hints )
{
FT_ERROR(( "%s.activate: invalid hint index %d\n", index ));
return;
}
/* ignore active hints */
if ( psh_hint_is_active(hint) )
return;
psh_hint_activate(hint);
/* now scan the current active hint set in order to determine */
/* if we're overlapping with another segment.. */
{
PSH_Hint* sorted = table->sort_global;
FT_UInt count = table->num_hints;
PSH_Hint hint2;
hint->parent = 0;
for ( ; count > 0; count--, sorted++ )
{
hint2 = sorted[0];
if ( psh_hint_overlap( hint, hint2 ) )
{
hint->parent = hint2;
break;
}
}
}
if ( table->num_hints < table->max_hints )
table->sort_global[ table->num_hints++ ] = hint;
else
{
FT_ERROR(( "%s.activate: too many sorted hints !! BUG !!\n",
"ps.fitter" ));
}
}
static void
psh_hint_table_record_mask( PSH_Hint_Table table,
PS_Mask hint_mask )
{
FT_Int mask = 0, val = 0;
FT_Byte* cursor = hint_mask->bytes;
FT_UInt index, limit;
limit = hint_mask->num_bits;
if ( limit != table->max_hints )
{
FT_ERROR(( "%s.activate_mask: invalid bit count (%d instead of %d)\n",
"ps.fitter", hint_mask->num_bits, table->max_hints ));
}
for ( index = 0; index < limit; index++ )
{
if ( mask == 0 )
{
val = *cursor++;
mask = 0x80;
}
if ( val & mask )
psh_hint_table_record( table, index );
mask >>= 1;
}
}
/* create hints table */
static FT_Error
psh_hint_table_init( PSH_Hint_Table table,
PS_Hint_Table hints,
PS_Mask_Table hint_masks,
PS_Mask_Table counter_masks,
FT_Memory memory )
{
FT_UInt count = hints->num_hints;
FT_Error error;
FT_UNUSED(counter_masks);
/* allocate our tables */
if ( ALLOC_ARRAY( table->sort, 2*count, PSH_Hint ) ||
ALLOC_ARRAY( table->hints, count, PSH_HintRec ) ||
ALLOC_ARRAY( table->zones, 2*count+1, PSH_ZoneRec ) )
goto Exit;
table->max_hints = count;
table->sort_global = table->sort + count;
table->num_hints = 0;
table->num_zones = 0;
table->zone = 0;
/* now, initialise the "hints" array */
{
PSH_Hint write = table->hints;
PS_Hint read = hints->hints;
for ( ; count > 0; count--, write++, read++ )
{
write->org_pos = read->pos;
write->org_len = read->len;
write->flags = read->flags;
}
}
/* we now need to determine the initial "parent" stems, first */
/* activate the hints that are given by the initial hint masks */
if ( hint_masks )
{
FT_UInt count = hint_masks->num_masks;
PS_Mask mask = hint_masks->masks;
table->hint_masks = hint_masks;
for ( ; count > 0; count--, mask++ )
psh_hint_table_record_mask( table, mask );
}
/* now, do a linear parse in case some hints were left alone */
if ( table->num_hints != table->max_hints )
{
FT_UInt index, count;
FT_ERROR(( "%s.init: missing/incorrect hint masks !!\n" ));
count = table->max_hints;
for ( index = 0; index < count; index++ )
psh_hint_table_record( table, index );
}
Exit:
return error;
}
static void
psh_hint_table_activate_mask( PSH_Hint_Table table,
PS_Mask hint_mask )
{
FT_Int mask = 0, val = 0;
FT_Byte* cursor = hint_mask->bytes;
FT_UInt index, limit, count;
limit = hint_mask->num_bits;
count = 0;
psh_hint_table_deactivate( table );
for ( index = 0; index < limit; index++ )
{
if ( mask == 0 )
{
val = *cursor++;
mask = 0x80;
}
if ( val & mask )
{
PSH_Hint hint = &table->hints[index];
if ( !psh_hint_is_active(hint) )
{
PSH_Hint* sort = table->sort;
FT_UInt count2;
PSH_Hint hint2;
for ( count2 = count; count2 > 0; count2--, sort++ )
{
hint2 = sort[0];
if ( psh_hint_overlap( hint, hint2 ) )
{
FT_ERROR(( "%s.activate_mask: found overlapping hints\n",
"psf.hint" ));
break;
}
}
if ( count2 == 0 )
{
psh_hint_activate( hint );
if ( count < table->max_hints )
table->sort[count++] = hint;
else
{
FT_ERROR(( "%s.activate_mask: too many active hints\n",
"psf.hint" ));
}
}
}
}
mask >>= 1;
}
table->num_hints = count;
/* now, sort the hints, they're guaranteed to not overlap */
/* so we can compare their "org_pos" field directly.. */
{
FT_Int i1, i2;
PSH_Hint hint1, hint2;
PSH_Hint* sort = table->sort;
/* a simple bubble sort will do, since in 99% of cases, the hints */
/* will be already sorted.. and the sort will be linear */
for ( i1 = 1; i1 < (FT_Int)count; i1++ )
{
hint1 = sort[i1];
for ( i2 = i1-1; i2 >= 0; i2-- )
{
hint2 = sort[i2];
if ( hint2->org_pos < hint1->org_pos )
break;
sort[i1] = hint2;
sort[i2] = hint1;
}
}
}
}
#define PSH_ZONE_MIN -3200000
#define PSH_ZONE_MAX +3200000
#define xxDEBUG_ZONES
#ifdef DEBUG_ZONES
#include <stdio.h>
static void
print_zone( PSH_Zone zone )
{
printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
zone->scale/65536.0,
zone->delta/64.0,
zone->min,
zone->max );
}
#else
# define print_zone(x) do { } while (0)
#endif
/* setup interpolation zones once the hints have been grid-fitted */
/* by the optimizer.. */
static void
psh_hint_table_setup_zones( PSH_Hint_Table table,
FT_Fixed scale,
FT_Fixed delta )
{
FT_UInt count;
PSH_Zone zone;
PSH_Hint *sort, hint, hint2;
zone = table->zones;
/* special case, no hints defined */
if ( table->num_hints == 0 )
{
zone->scale = scale;
zone->delta = delta;
zone->min = PSH_ZONE_MIN;
zone->max = PSH_ZONE_MAX;
table->num_zones = 1;
return;
}
/* the first zone is before the first hint */
/* x' = (x-x0)*s + x0' = x*s + ( x0' - x0*s ) */
sort = table->sort;
hint = sort[0];
zone->scale = scale;
zone->delta = hint->cur_pos - FT_MulFix( hint->org_pos, scale );
zone->min = PSH_ZONE_MIN;
zone->max = hint->org_pos;
print_zone( zone );
zone++;
for ( count = table->num_hints; count > 0; count-- )
{
FT_Fixed scale2;
if ( hint->org_len > 0 )
{
/* setup a zone for inner-stem interpolation */
/* (x' - x0') = (x - x0)*(x1'-x0')/(x1-x0) */
/* x' = x*s2 + x0' - x0*s2 */
scale2 = FT_DivFix( hint->cur_len, hint->org_len );
zone->scale = scale2;
zone->min = hint->org_pos;
zone->max = hint->org_pos + hint->org_len;
zone->delta = hint->cur_pos - FT_MulFix( zone->min, scale2 );
print_zone( zone );
zone++;
}
if ( count == 1 )
break;
sort++;
hint2 = sort[0];
/* setup zone for inter-stem interpolation */
/* (x'-x1') = (x-x1)*(x2'-x1')/(x2-x1) */
/* x' = x*s3 + x1' - x1*s3 */
scale2 = FT_DivFix( hint2->cur_pos - (hint->cur_pos + hint->cur_len),
hint2->org_pos - (hint->org_pos + hint->org_len) );
zone->scale = scale2;
zone->min = hint->org_pos + hint->org_len;
zone->max = hint2->org_pos;
zone->delta = hint->cur_pos + hint->cur_len - FT_MulFix( zone->min, scale2 );
print_zone( zone );
zone++;
hint = hint2;
}
/* the last zone */
zone->scale = scale;
zone->min = hint->org_pos + hint->org_len;
zone->max = PSH_ZONE_MAX;
zone->delta = hint->cur_pos + hint->cur_len - FT_MulFix( zone->min, scale );
print_zone( zone );
zone++;
table->num_zones = zone - table->zones;
table->zone = table->zones;
}
/* tune a single coordinate with the current interpolation zones */
static FT_Pos
psh_hint_table_tune_coord( PSH_Hint_Table table,
FT_Int coord )
{
PSH_Zone zone;
zone = table->zone;
if ( coord < zone->min )
{
do
{
if ( zone == table->zones )
break;
zone--;
}
while ( coord < zone->min );
table->zone = zone;
}
else if ( coord > zone->max )
{
do
{
if ( zone == table->zones + table->num_zones - 1 )
break;
zone++;
}
while ( coord > zone->max );
table->zone = zone;
}
return FT_MulFix( coord, zone->scale ) + zone->delta;
}
/* tune a given outline with current interpolation zones */
/* the function only works in a single dimension.. */
static void
psh_hint_table_tune_outline( PSH_Hint_Table table,
FT_Outline* outline,
PSH_Globals globals,
FT_Bool vertical )
{
FT_UInt count, first, last;
PS_Mask_Table hint_masks = table->hint_masks;
PS_Mask mask;
PSH_Dimension dim = &globals->dimension[vertical];
FT_Fixed scale = dim->scale_mult;
FT_Fixed delta = dim->scale_delta;
if ( hint_masks && hint_masks->num_masks > 0 )
{
first = 0;
mask = hint_masks->masks;
count = hint_masks->num_masks;
for ( ; count > 0; count--, mask++ )
{
last = mask->end_point;
if ( last > first )
{
FT_Vector* vec;
FT_Int count2;
psh_hint_table_activate_mask( table, mask );
psh_hint_table_optimize( table, globals, outline, vertical );
psh_hint_table_setup_zones( table, scale, delta );
last = mask->end_point;
vec = outline->points + first;
count2 = last - first;
for ( ; count2 > 0; count2--, vec++ )
{
FT_Pos x, *px;
px = vertical ? &vec->x : &vec->y;
x = *px;
*px = psh_hint_table_tune_coord( table, (FT_Int)x );
}
}
first = last;
}
}
else /* no hints in this glyph, simply scale the outline */
{
FT_Vector* vec;
vec = outline->points;
count = outline->n_points;
if ( vertical )
{
for ( ; count > 0; count--, vec++ )
vec->x = FT_MulFix( vec->x, scale ) + delta;
}
else
{
for ( ; count > 0; count--, vec++ )
vec->y = FT_MulFix( vec->y, scale ) + delta;
}
}
}
FT_LOCAL_DEF FT_Error
ps_hints_apply( PS_Hints ps_hints,
FT_Outline* outline,
PSH_Globals globals )
{
PSH_Hint_TableRec hints;
FT_Error error;
FT_Int dimension;
for ( dimension = 1; dimension >= 0; dimension-- )
{
PS_Dimension dim = &ps_hints->dimension[dimension];
/* initialise hints table */
memset( &hints, 0, sizeof(hints) );
error = psh_hint_table_init( &hints,
&dim->hints,
&dim->masks,
&dim->counters,
ps_hints->memory );
if (error) goto Exit;
psh_hint_table_tune_outline( &hints,
outline,
globals,
dimension );
psh_hint_table_done( &hints, ps_hints->memory );
}
Exit:
return error;
}

View File

@ -1,110 +0,0 @@
/***************************************************************************/
/* */
/* pshfit.h */
/* */
/* Postscript (Type 1/CFF) outline grid-fitter */
/* */
/* Copyright 2001 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
/* modified, and distributed under the terms of the FreeType project */
/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
/* this file you indicate that you have read the license and */
/* understand and accept it fully. */
/* */
/* */
/* process the hints provided by the Postscript hints recorder. This */
/* means sorting and scaling the hints, calling the "optimiser" to */
/* process them, then grid-fitting the glyph outline based on the */
/* optimised hints information. */
/* */
/* (the real hinting "intelligence" is in "pshoptim.h", not here) */
/* */
/***************************************************************************/
#ifndef __PS_HINTER_FITTER_H__
#define __PS_HINTER_FITTER_H__
#include "pshrec.h"
FT_BEGIN_HEADER
typedef struct PSH_HintRec_* PSH_Hint;
typedef enum
{
PSH_HINT_FLAG_GHOST = PS_HINT_FLAG_GHOST,
PSH_HINT_FLAG_BOTTOM = PS_HINT_FLAG_BOTTOM,
PSH_HINT_FLAG_ACTIVE = 4
} PSH_Hint_Flags;
#define psh_hint_is_active(x) (((x)->flags & PSH_HINT_FLAG_ACTIVE) != 0)
#define psh_hint_is_ghost(x) (((x)->flags & PSH_HINT_FLAG_GHOST ) != 0)
#define psh_hint_activate(x) (x)->flags |= PSH_HINT_FLAG_ACTIVE
#define psh_hint_deactivate(x) (x)->flags &= ~PSH_HINT_FLAG_ACTIVE
typedef struct PSH_HintRec_
{
FT_Int org_pos;
FT_Int org_len;
FT_Pos cur_pos;
FT_Pos cur_len;
FT_UInt flags;
PSH_Hint parent;
FT_Int order;
} PSH_HintRec;
/* this is an interpolation zone used for strong points */
/* weak points are interpolated according to their strong */
/* neighbours.. */
typedef struct PSH_ZoneRec_
{
FT_Fixed scale;
FT_Fixed delta;
FT_Pos min;
FT_Pos max;
} PSH_ZoneRec, *PSH_Zone;
typedef struct PSH_Hint_TableRec_
{
FT_UInt max_hints;
FT_UInt num_hints;
PSH_Hint hints;
PSH_Hint* sort;
PSH_Hint* sort_global;
FT_UInt num_zones;
PSH_Zone zones;
PSH_Zone zone;
PS_Mask_Table hint_masks;
PS_Mask_Table counter_masks;
} PSH_Hint_TableRec, *PSH_Hint_Table;
FT_LOCAL FT_Error
ps_hints_apply( PS_Hints ps_hints,
FT_Outline* outline,
PSH_Globals globals );
#ifdef DEBUG_VIEW
extern int ps_debug_no_horz_hints;
extern int ps_debug_no_vert_hints;
extern PSH_Hint_Table ps_debug_hint_table;
typedef void (*PSH_HintFunc)( PSH_Hint hint, FT_Bool vertical );
extern PSH_HintFunc ps_debug_hint_func;
#endif
FT_END_HEADER
#endif /* __PS_HINTER_FITTER_H__ */

View File

@ -3,6 +3,10 @@
#include FT_INTERNAL_OBJECTS_H
#include "pshglob.h"
#ifdef DEBUG_HINTER
extern PSH_Globals ps_debug_globals = 0;
#endif
/* "simple" ps hinter globals management, inspired from the new auto-hinter */
/*************************************************************************/
@ -87,6 +91,7 @@
static void
psh_blues_set_zones_0( PSH_Blues target,
FT_Bool is_others,
FT_UInt read_count,
FT_Short* read,
PSH_Blue_Table top_table,
@ -94,26 +99,34 @@
{
FT_UInt count_top = top_table->count;
FT_UInt count_bot = bot_table->count;
FT_Bool first = 1;
for ( ; read_count > 0; read_count -= 2 )
{
FT_Int reference, delta;
FT_UInt count;
PSH_Blue_Zone zones, zone;
FT_Bool top;
/* read blue zone entry, and select target top/bottom zone */
reference = read[0];
delta = read[1] - reference;
if ( delta >= 0 )
top = 0;
if ( first || is_others )
{
zones = top_table->zones;
count = count_top;
reference = read[1];
delta = read[0] - reference;
zones = bot_table->zones;
count = count_bot;
first = 0;
}
else
{
zones = bot_table->zones;
count = count_bot;
reference = read[0];
delta = read[1] - reference;
zones = top_table->zones;
count = count_top;
top = 1;
}
/* insert into sorted table */
@ -149,7 +162,7 @@
zone->org_ref = reference;
zone->org_delta = delta;
if ( delta >= 0 )
if ( top )
count_top ++;
else
count_bot ++;
@ -195,8 +208,8 @@
bot_table->count = 0;
/* first, the blues */
psh_blues_set_zones_0( target, count, blues, top_table, bot_table );
psh_blues_set_zones_0( target, count_others, other_blues, top_table, bot_table );
psh_blues_set_zones_0( target, 0, count, blues, top_table, bot_table );
psh_blues_set_zones_0( target, 1, count_others, other_blues, top_table, bot_table );
count_top = top_table->count;
count_bot = bot_table->count;
@ -206,13 +219,16 @@
{
PSH_Blue_Zone zone = top_table->zones;
for ( count = count_top-1; count > 0; count--, zone++ )
for ( count = count_top; count > 0; count--, zone++ )
{
FT_Int delta;
delta = zone[1].org_ref - zone[0].org_ref;
if ( zone->org_delta > delta )
zone->org_delta = delta;
if ( count > 1 )
{
delta = zone[1].org_ref - zone[0].org_ref;
if ( zone->org_delta > delta )
zone->org_delta = delta;
}
zone->org_bottom = zone->org_ref;
zone->org_top = zone->org_delta + zone->org_ref;
@ -224,13 +240,16 @@
{
PSH_Blue_Zone zone = bot_table->zones;
for ( count = count_bot-1; count > 0; count--, zone++ )
for ( count = count_bot; count > 0; count--, zone++ )
{
FT_Int delta;
delta = zone[0].org_ref - zone[1].org_ref;
if ( zone->org_delta < delta )
zone->org_delta = delta;
if ( count > 1 )
{
delta = zone[0].org_ref - zone[1].org_ref;
if ( zone->org_delta < delta )
zone->org_delta = delta;
}
zone->org_top = zone->org_ref;
zone->org_bottom = zone->org_delta + zone->org_ref;
@ -256,7 +275,7 @@
/* checking that the interval is smaller than the fuzz */
top = zone->org_top;
for ( count--; count > 0; count--, zone++ )
for ( count--; count > 0; count-- )
{
bot = zone[1].org_bottom;
delta = bot - top;
@ -318,6 +337,13 @@
/* round scaled reference position */
zone->cur_ref = ( zone->cur_ref + 32 ) & -64;
#if 0
if ( zone->cur_ref > zone->cur_top )
zone->cur_ref -= 64;
else if ( zone->cur_ref < zone->cur_bottom )
zone->cur_ref += 64;
#endif
}
}
@ -326,10 +352,10 @@
FT_LOCAL_DEF void
psh_blues_snap_stem( PSH_Blues blues,
FT_Int stem_top,
FT_Int stem_bot,
PSH_Blue_Alignement alignment )
psh_blues_snap_stem( PSH_Blues blues,
FT_Int stem_top,
FT_Int stem_bot,
PSH_Alignment alignment )
{
PSH_Blue_Table table;
FT_UInt count;
@ -341,7 +367,7 @@
table = &blues->normal_top;
count = table->count;
zone = table->zones;
for ( ; count > 0; count-- )
for ( ; count > 0; count--, zone++ )
{
if ( stem_top < zone->org_bottom )
break;
@ -358,7 +384,7 @@
table = &blues->normal_bottom;
count = table->count;
zone = table->zones;
for ( ; count > 0; count-- )
for ( ; count > 0; count--, zone++ )
{
if ( stem_bot < zone->org_bottom )
break;
@ -367,6 +393,7 @@
{
alignment->align |= PSH_BLUE_ALIGN_BOT;
alignment->align_bot = zone->cur_ref;
break;
}
}
}
@ -397,6 +424,10 @@
globals->blues.family_bottom.count = 0;
FREE( globals );
#ifdef DEBUG_HINTER
ps_debug_globals = 0;
#endif
}
}
@ -467,6 +498,10 @@
globals->dimension[0].scale_delta = 0;
globals->dimension[1].scale_mult = 0;
globals->dimension[1].scale_delta = 0;
#ifdef DEBUG_HINTER
ps_debug_globals = globals;
#endif
}
*aglobals = globals;

View File

@ -141,7 +141,7 @@ FT_BEGIN_HEADER
FT_Pos align_top;
FT_Pos align_bot;
} PSH_Blue_AlignementRec, *PSH_Blue_Alignement;
} PSH_AlignmentRec, *PSH_Alignment;
FT_LOCAL void
@ -156,12 +156,15 @@ FT_BEGIN_HEADER
/* snap a stem to one or two blue zones */
FT_LOCAL void
psh_blues_snap_stem( PSH_Blues blues,
FT_Int stem_top,
FT_Int stem_bot,
PSH_Blue_Alignement alignment );
psh_blues_snap_stem( PSH_Blues blues,
FT_Int stem_top,
FT_Int stem_bot,
PSH_Alignment alignment );
/* */
#ifdef DEBUG_HINTER
extern PSH_Globals ps_debug_globals;
#endif
FT_END_HEADER

View File

@ -21,8 +21,9 @@
#include <ft2build.h>
#include "pshrec.c"
#include "pshglob.c"
#include "pshfit.c"
#include "pshalgo1.c"
#include "pshalgo2.c"
#include "pshmod.c"
#include "pshoptim.c"
/* END */

View File

@ -18,6 +18,7 @@
#include <ft2build.h>
#include FT_INTERNAL_OBJECTS_H
#include "pshrec.h"
#include "pshalgo.h"
/* the Postscript Hinter module structure */
typedef struct

View File

@ -1,145 +0,0 @@
#include "pshoptim.h"
#ifdef DEBUG_VIEW
void
ps_simple_scale( PSH_Hint_Table table,
FT_Fixed scale,
FT_Fixed delta,
FT_Bool vertical )
{
PSH_Hint hint;
FT_UInt count;
for ( count = 0; count < table->num_hints; count++ )
{
hint = table->sort[count];
if ( psh_hint_is_active(hint) )
{
hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
hint->cur_len = FT_MulFix( hint->org_len, scale );
if (ps_debug_hint_func)
ps_debug_hint_func( hint, vertical );
}
}
}
#endif
FT_LOCAL_DEF FT_Error
psh_hint_table_optimize( PSH_Hint_Table table,
PSH_Globals globals,
FT_Outline* outline,
FT_Bool vertical )
{
PSH_Dimension dim = &globals->dimension[vertical];
FT_Fixed scale = dim->scale_mult;
FT_Fixed delta = dim->scale_delta;
#ifdef DEBUG_VIEW
if ( ps_debug_no_vert_hints && vertical )
{
ps_simple_scale( table, scale, delta, vertical );
return 0;
}
if ( ps_debug_no_horz_hints && !vertical )
{
ps_simple_scale( table, scale, delta, vertical );
return 0;
}
#endif
/* XXXX: for now, we only scale the hints to test all other aspects */
/* of the Postscript Hinter.. */
{
PSH_Hint hint;
FT_UInt count;
for ( count = 0; count < table->num_hints; count++ )
{
hint = table->sort[count];
if ( psh_hint_is_active(hint) )
{
# if 1
FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
FT_Pos len = FT_MulFix( hint->org_len, scale );
FT_Pos fit_center;
FT_Pos fit_len;
PSH_Blue_AlignementRec align;
/* compute fitted width/height */
fit_len = psh_dimension_snap_width( dim, hint->org_len );
if ( fit_len < 64 )
fit_len = 64;
else
fit_len = (fit_len + 16 ) & -64;
hint->cur_len = fit_len;
/* check blue zones for horizontal stems */
align.align = 0;
if (!vertical)
{
psh_blues_snap_stem( &globals->blues,
hint->org_pos + hint->org_len,
hint->org_pos,
&align );
}
switch (align.align)
{
case PSH_BLUE_ALIGN_TOP:
{
/* the top of the stem is aligned against a blue zone */
hint->cur_pos = align.align_top - fit_len;
break;
}
case PSH_BLUE_ALIGN_BOT:
{
/* the bottom of the stem is aligned against a blue zone */
hint->cur_pos = align.align_bot;
break;
}
case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
{
/* both edges of the stem are aligned against blue zones */
hint->cur_pos = align.align_bot;
hint->cur_len = align.align_top - align.align_bot;
}
break;
default:
/* normal processing */
if ( (fit_len/64) & 1 )
{
/* odd number of pixels */
fit_center = ((pos + (len >> 1)) & -64) + 32;
}
else
{
/* even number of pixels */
fit_center = (pos + (len >> 1) + 32) & -64;
}
hint->cur_pos = fit_center - (fit_len >> 1);
}
# else
hint->cur_pos = (FT_MulFix( hint->org_pos, scale ) + delta + 32) & -64;
hint->cur_len = FT_MulFix( hint->org_len, scale );
# endif
#ifdef DEBUG_VIEW
if (ps_debug_hint_func)
ps_debug_hint_func( hint, vertical );
#endif
}
}
}
return 0;
}

View File

@ -1,41 +0,0 @@
/***************************************************************************/
/* */
/* pshoptim.h */
/* */
/* Postscript Hints optimiser and grid-fitter */
/* */
/* Copyright 2001 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
/* modified, and distributed under the terms of the FreeType project */
/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
/* this file you indicate that you have read the license and */
/* understand and accept it fully. */
/* */
/* */
/* process the hints provided by the fitter in order to optimize them */
/* for the pixel grid, depending on the current glyph outline and */
/* globals. This is where most of the PS Hinter's intelligence is */
/* */
/* XXXX: Until now, only a dummy implementation is provided in order */
/* to test all other functions of the Postscript Hinter. */
/* */
/***************************************************************************/
#ifndef __PS_HINTER_OPTIMISER_H__
#define __PS_HINTER_OPTIMISER_H__
#include "pshfit.h"
FT_BEGIN_HEADER
FT_LOCAL FT_Error
psh_hint_table_optimize( PSH_Hint_Table table,
PSH_Globals globals,
FT_Outline* outline,
FT_Bool vertical );
FT_END_HEADER
#endif /* __PS_HINTER_OPTIMISER_H__ */

View File

@ -3,7 +3,15 @@
#include FT_INTERNAL_OBJECTS_H
#include FT_INTERNAL_DEBUG_H
#include "pshrec.h"
#include "pshfit.h"
#include "pshalgo.h"
#ifdef DEBUG_HINTER
extern PS_Hints ps_debug_hints = 0;
extern int ps_debug_no_horz_hints = 0;
extern int ps_debug_no_vert_hints = 0;
#endif
/***********************************************************************/
/***********************************************************************/
@ -1041,7 +1049,7 @@
funcs->stem = (T1_Hints_SetStemFunc) t1_hints_stem;
funcs->stem3 = (T1_Hints_SetStem3Func) ps_hints_t1stem3;
funcs->reset = (T1_Hints_ResetFunc) ps_hints_t1reset;
funcs->apply = (T1_Hints_ApplyFunc) ps_hints_apply;
funcs->apply = (T1_Hints_ApplyFunc) PS_HINTS_APPLY_FUNC;
}
@ -1097,7 +1105,7 @@
funcs->stems = (T2_Hints_StemsFunc) t2_hints_stems;
funcs->hintmask = (T2_Hints_MaskFunc) ps_hints_t2mask;
funcs->counter = (T2_Hints_CounterFunc) ps_hints_t2counter;
funcs->apply = (T2_Hints_ApplyFunc) ps_hints_apply;
funcs->apply = (T2_Hints_ApplyFunc) PS_HINTS_APPLY_FUNC;
}

View File

@ -151,10 +151,11 @@ FT_BEGIN_HEADER
FT_LOCAL void
t2_hints_funcs_init( T2_Hints_FuncsRec* funcs );
#define xxxDEBUG_VIEW
#ifdef DEBUG_VIEW
extern PS_Hints the_ps_hints;
#ifdef DEBUG_HINTER
extern PS_Hints ps_debug_hints;
extern int ps_debug_no_horz_hints;
extern int ps_debug_no_vert_hints;
#endif
/* */

View File

@ -82,7 +82,7 @@
#include <string.h> /* for memcpy() */
#include <setjmp.h>
/*************************************************************************/
/* */
@ -94,6 +94,8 @@
#define FT_COMPONENT trace_aaraster
#define ErrRaster_MemoryOverflow -4
#ifdef _STANDALONE_
@ -264,12 +266,13 @@
void* render_span_data;
int span_y;
int band_size;
int band_shoot;
int conic_level;
int cubic_level;
int band_size;
int band_shoot;
int conic_level;
int cubic_level;
void* memory;
void* memory;
jmp_buf jump_buffer;
} TRaster, *PRaster;
@ -296,10 +299,11 @@
/* Compute the outline bounding box. */
/* */
static
void compute_cbox( RAS_ARG_ FT_Outline* outline )
void compute_cbox( RAS_ARG )
{
FT_Vector* vec = outline->points;
FT_Vector* limit = vec + outline->n_points;
FT_Outline* outline = &ras.outline;
FT_Vector* vec = outline->points;
FT_Vector* limit = vec + outline->n_points;
if ( outline->n_points <= 0 )
@ -339,7 +343,7 @@
/* Record the current cell in the table. */
/* */
static
int record_cell( RAS_ARG )
void record_cell( RAS_ARG )
{
PCell cell;
@ -347,7 +351,7 @@
if ( !ras.invalid && ( ras.area | ras.cover ) )
{
if ( ras.num_cells >= ras.max_cells )
return 1;
longjmp( ras.jump_buffer, 1 );
cell = ras.cells + ras.num_cells++;
cell->x = ras.ex - ras.min_ex;
@ -355,8 +359,6 @@
cell->area = ras.area;
cell->cover = ras.cover;
}
return 0;
}
@ -365,8 +367,8 @@
/* Set the current cell to a new position. */
/* */
static
int set_cell( RAS_ARG_ TScan ex,
TScan ey )
void set_cell( RAS_ARG_ TScan ex,
TScan ey )
{
int invalid, record, clean;
@ -402,8 +404,8 @@
/* record the previous cell if needed (i.e., if we changed the cell */
/* position, of changed the `invalid' flag) */
if ( ( ras.invalid != invalid || record ) && record_cell( RAS_VAR ) )
return 1;
if ( ras.invalid != invalid || record )
record_cell( RAS_VAR );
if ( clean )
{
@ -414,7 +416,6 @@
ras.invalid = invalid;
ras.ex = ex;
ras.ey = ey;
return 0;
}
@ -436,7 +437,7 @@
ras.last_ey = SUBPIXELS( ey );
ras.invalid = 0;
(void)set_cell( RAS_VAR_ ex, ey );
set_cell( RAS_VAR_ ex, ey );
}
@ -445,11 +446,11 @@
/* Render a scanline as one or more cells. */
/* */
static
int render_scanline( RAS_ARG_ TScan ey,
TPos x1,
TScan y1,
TPos x2,
TScan y2 )
void render_scanline( RAS_ARG_ TScan ey,
TPos x1,
TScan y1,
TPos x2,
TScan y2 )
{
TScan ex1, ex2, fx1, fx2, delta;
long p, first, dx;
@ -465,7 +466,10 @@
/* trivial case. Happens often */
if ( y1 == y2 )
return set_cell( RAS_VAR_ ex2, ey );
{
set_cell( RAS_VAR_ ex2, ey );
return;
}
/* everything is located in a single cell. That is easy! */
/* */
@ -474,7 +478,7 @@
delta = y2 - y1;
ras.area += ( fx1 + fx2 ) * delta;
ras.cover += delta;
return 0;
return;
}
/* ok, we'll have to render a run of adjacent cells on the same */
@ -504,8 +508,7 @@
ras.cover += delta;
ex1 += incr;
if ( set_cell( RAS_VAR_ ex1, ey ) )
goto Error;
set_cell( RAS_VAR_ ex1, ey );
y1 += delta;
if ( ex1 != ex2 )
@ -535,19 +538,13 @@
ras.cover += delta;
y1 += delta;
ex1 += incr;
if ( set_cell( RAS_VAR_ ex1, ey ) )
goto Error;
set_cell( RAS_VAR_ ex1, ey );
}
}
delta = y2 - y1;
ras.area += ( fx2 + ONE_PIXEL - first ) * delta;
ras.cover += delta;
return 0;
Error:
return 1;
}
@ -556,7 +553,7 @@
/* Render a given line as a series of scanlines. */
/* */
static
int render_line( RAS_ARG_ TPos to_x,
void render_line( RAS_ARG_ TPos to_x,
TPos to_y )
{
TScan ey1, ey2, fy1, fy2;
@ -594,8 +591,7 @@
/* everything is on a single scanline */
if ( ey1 == ey2 )
{
if ( render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 ) )
goto Error;
render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
goto End;
}
@ -621,12 +617,10 @@
}
x = ras.x + delta;
if ( render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, first ) )
goto Error;
render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, first );
ey1 += incr;
if ( set_cell( RAS_VAR_ TRUNC( x ), ey1 ) )
goto Error;
set_cell( RAS_VAR_ TRUNC( x ), ey1 );
if ( ey1 != ey2 )
{
@ -651,29 +645,20 @@
}
x2 = x + delta;
if ( render_scanline( RAS_VAR_ ey1,
x, ONE_PIXEL - first, x2, first ) )
goto Error;
render_scanline( RAS_VAR_ ey1, x, ONE_PIXEL - first, x2, first );
x = x2;
ey1 += incr;
if ( set_cell( RAS_VAR_ TRUNC( x ), ey1 ) )
goto Error;
set_cell( RAS_VAR_ TRUNC( x ), ey1 );
}
}
if ( render_scanline( RAS_VAR_ ey1,
x, ONE_PIXEL - first, to_x, fy2 ) )
goto Error;
render_scanline( RAS_VAR_ ey1, x, ONE_PIXEL - first, to_x, fy2 );
End:
ras.x = to_x;
ras.y = to_y;
ras.last_ey = SUBPIXELS( ey2 );
return 0;
Error:
return 1;
}
@ -698,7 +683,7 @@
static
int render_conic( RAS_ARG_ FT_Vector* control,
void render_conic( RAS_ARG_ FT_Vector* control,
FT_Vector* to )
{
TPos dx, dy;
@ -737,8 +722,9 @@
mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4;
mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4;
return render_line( RAS_VAR_ mid_x, mid_y ) ||
render_line( RAS_VAR_ to_x, to_y );
render_line( RAS_VAR_ mid_x, mid_y );
render_line( RAS_VAR_ to_x, to_y );
return;
}
arc = ras.bez_stack;
@ -792,15 +778,14 @@
mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4;
mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4;
if ( render_line( RAS_VAR_ mid_x, mid_y ) ||
render_line( RAS_VAR_ to_x, to_y ) )
return 1;
render_line( RAS_VAR_ mid_x, mid_y );
render_line( RAS_VAR_ to_x, to_y );
top--;
arc -= 2;
}
}
return 0;
return;
}
@ -833,7 +818,7 @@
static
int render_cubic( RAS_ARG_ FT_Vector* control1,
void render_cubic( RAS_ARG_ FT_Vector* control1,
FT_Vector* control2,
FT_Vector* to )
{
@ -885,8 +870,9 @@
mid_y = ( ras.y + to_y +
3 * UPSCALE( control1->y + control2->y ) ) / 8;
return render_line( RAS_VAR_ mid_x, mid_y ) ||
render_line( RAS_VAR_ to_x, to_y );
render_line( RAS_VAR_ mid_x, mid_y );
render_line( RAS_VAR_ to_x, to_y );
return;
}
arc = ras.bez_stack;
@ -941,14 +927,13 @@
mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8;
mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8;
if ( render_line( RAS_VAR_ mid_x, mid_y ) ||
render_line( RAS_VAR_ to_x, to_y ) )
return 1;
render_line( RAS_VAR_ mid_x, mid_y );
render_line( RAS_VAR_ to_x, to_y );
top --;
arc -= 3;
}
}
return 0;
return;
}
@ -1157,7 +1142,9 @@
/* start to a new position */
x = UPSCALE( to->x );
y = UPSCALE( to->y );
start_cell( (PRaster)raster, TRUNC( x ), TRUNC( y ) );
((PRaster)raster)->x = x;
((PRaster)raster)->y = y;
return 0;
@ -1168,8 +1155,9 @@
int Line_To( FT_Vector* to,
FT_Raster raster )
{
return render_line( (PRaster)raster,
UPSCALE( to->x ), UPSCALE( to->y ) );
render_line( (PRaster)raster,
UPSCALE( to->x ), UPSCALE( to->y ) );
return 0;
}
@ -1178,7 +1166,8 @@
FT_Vector* to,
FT_Raster raster )
{
return render_conic( (PRaster)raster, control, to );
render_conic( (PRaster)raster, control, to );
return 0;
}
@ -1188,7 +1177,8 @@
FT_Vector* to,
FT_Raster raster )
{
return render_cubic( (PRaster)raster, control1, control2, to );
render_cubic( (PRaster)raster, control1, control2, to );
return 0;
}
@ -1487,7 +1477,11 @@
void* user )
{
#undef SCALED
#define SCALED( x ) ( ( (x) << shift ) - delta )
#if 0
# define SCALED( x ) ( ( (x) << shift ) - delta )
#else
# define SCALED( x) (x)
#endif
FT_Vector v_last;
FT_Vector v_control;
@ -1502,8 +1496,10 @@
int error;
char tag; /* current point's state */
#if 0
int shift = interface->shift;
FT_Pos delta = interface->delta;
#endif
first = 0;
@ -1691,8 +1687,8 @@
} TBand;
static
int grays_convert_glyph( RAS_ARG_ FT_Outline* outline )
static int
grays_convert_glyph_inner( RAS_ARG )
{
static
const FT_Outline_Funcs interface =
@ -1705,6 +1701,25 @@
0
};
volatile int error = 0;
if ( setjmp( ras.jump_buffer ) == 0 )
{
error = FT_Outline_Decompose( &ras.outline, &interface, &ras );
record_cell( RAS_VAR );
}
else
{
error = ErrRaster_MemoryOverflow;
}
return error;
}
static
int grays_convert_glyph( RAS_ARG_ FT_Outline* outline )
{
TBand bands[40], *band;
int n, num_bands;
TPos min, max, max_y;
@ -1712,7 +1727,7 @@
/* Set up state in the raster object */
compute_cbox( RAS_VAR_ outline );
compute_cbox( RAS_VAR );
/* clip to target bitmap, exit if nothing to do */
clip = &ras.clip_box;
@ -1776,8 +1791,12 @@
ras.min_ey = band->min;
ras.max_ey = band->max;
#if 1
error = grays_convert_glyph_inner( RAS_VAR );
#else
error = FT_Outline_Decompose( outline, &interface, &ras ) ||
record_cell( RAS_VAR );
#endif
if ( !error )
{
@ -1796,6 +1815,8 @@
band--;
continue;
}
else if ( error != ErrRaster_MemoryOverflow )
return 1;
/* render pool overflow, we will reduce the render band by half */
bottom = band->min;

View File

@ -16,7 +16,7 @@ NIRVANA_LINKLIBS = $(NV_TOP)\\objs\\nirvana$(SUFLIB) ;
Main $(t) : $(t).c ;
LinkLibraries $(t) : $(FT2_LIB) ;
if $(TOOLSET) = MINGW
{
LINKKLIBS on $(t)$(SUFEXE) = "-luser32 -lgdi32" ;

View File

@ -7,7 +7,17 @@
/* include FreeType internals to debug hints */
#include <../src/pshinter/pshrec.h>
#include <../src/pshinter/pshfit.h>
#include <../src/pshinter/pshalgo1.h>
#include <../src/pshinter/pshalgo2.h>
/************************************************************************/
/************************************************************************/
/***** *****/
/***** ROOT DEFINITIONS *****/
/***** *****/
/************************************************************************/
/************************************************************************/
#include <time.h> /* for clock() */
@ -18,7 +28,7 @@
#define CLOCKS_PER_SEC HZ
#endif
static int depth = 0;
static int first_glyph = 0;
static NV_Renderer renderer;
static NV_Painter painter;
@ -42,12 +52,23 @@ 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 = 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_ps_hints = 1;
static int option_show_horz_hints = 1;
@ -58,18 +79,18 @@ static int option_hinting = 1;
static char temp_message[1024];
PS_Hints the_ps_hints = 0;
int ps_debug_no_horz_hints = 0;
int ps_debug_no_vert_hints = 0;
PSH_HintFunc ps_debug_hint_func = 0;
#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
@ -84,6 +105,13 @@ Panic( const char* message )
}
/************************************************************************/
/************************************************************************/
/***** *****/
/***** COMMON GRID DRAWING ROUTINES *****/
/***** *****/
/************************************************************************/
/************************************************************************/
static void
reset_scale( NV_Scale scale )
@ -188,11 +216,114 @@ draw_grid( void )
}
/************************************************************************/
/************************************************************************/
/***** *****/
/***** 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_ps_hint( PSH_Hint hint, FT_Bool vertical )
draw_ps1_hint( PSH1_Hint hint, FT_Bool vertical )
{
int x1, x2;
NV_Vector v;
@ -224,17 +355,17 @@ draw_ps_hint( PSH_Hint hint, FT_Bool vertical )
x2 = (int)(v.x + 0.5);
nv_pixmap_fill_rect( target, x1, 0, 1, target->height,
psh_hint_is_ghost(hint)
psh1_hint_is_ghost(hint)
? GHOST_HINT_COLOR : STEM_HINT_COLOR );
if ( psh_hint_is_ghost(hint) )
if ( psh1_hint_is_ghost(hint) )
{
x1 --;
x2 = x1 + 2;
}
else
nv_pixmap_fill_rect( target, x2, 0, 1, target->height,
psh_hint_is_ghost(hint)
psh1_hint_is_ghost(hint)
? GHOST_HINT_COLOR : STEM_HINT_COLOR );
nv_pixmap_fill_rect( target, x1, pshint_cpos, x2+1-x1, 1,
@ -256,37 +387,208 @@ draw_ps_hint( PSH_Hint hint, FT_Bool vertical )
x2 = (int)(v.y + 0.5);
nv_pixmap_fill_rect( target, 0, x1, target->width, 1,
psh_hint_is_ghost(hint)
psh1_hint_is_ghost(hint)
? GHOST_HINT_COLOR : STEM_HINT_COLOR );
if ( psh_hint_is_ghost(hint) )
if ( psh1_hint_is_ghost(hint) )
{
x1 --;
x2 = x1 + 2;
}
else
nv_pixmap_fill_rect( target, 0, x2, target->width, 1,
psh_hint_is_ghost(hint)
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;
nv_path_new_rectangle( renderer, -1, -6, 2, 12, 0, 0, &vert_rect );
nv_path_new_rectangle( renderer, -6, -1, 12, 2, 0, 0, &horz_rect );
nv_path_new_circle( renderer, 0, 0, 3., &dot );
nv_path_stroke( dot, 0.6, nv_path_linecap_butt, nv_path_linejoin_miter, 1., &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, 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, horz_rect );
}
}
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, vert_rect );
}
}
}
nv_path_destroy( circle );
nv_path_destroy( dot );
nv_path_destroy( horz_rect );
nv_path_destroy( vert_rect );
}
}
/************************************************************************/
/************************************************************************/
/***** *****/
/***** 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;
ps1_debug_hint_func = option_show_ps_hints ? draw_ps1_hint : 0;
ps2_debug_hint_func = option_show_ps_hints ? draw_ps2_hint : 0;
error = FT_Load_Glyph( face, glyph_index, option_hinting
? FT_LOAD_NO_BITMAP
@ -334,6 +636,7 @@ draw_glyph( int glyph_index )
NV_Int n, first, last;
nv_path_new_circle( renderer, 0, 0, 2., &plot );
nv_path_get_outline( path, NULL, memory, &out );
first = 0;
@ -355,8 +658,10 @@ draw_glyph( int glyph_index )
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, plot );
}
first = last + 1;
@ -390,105 +695,25 @@ draw_glyph( int glyph_index )
}
#if 0
static void
draw_ps_hints( void )
{
if ( option_show_ps_hints && the_ps_hints )
{
PS_Dimension dim;
PS_Hint hint;
NV_UInt count;
NV_Int cpos;
NV_Vector v;
/* draw vertical stems */
if ( option_show_vert_hints )
{
dim = &the_ps_hints->dimension[1];
hint = dim->hints.hints;
cpos = 40;
for ( count = dim->hints.num_hints; count > 0; count--, hint++ )
{
NV_Int x1, x2;
v.x = hint->pos;
v.y = 0;
nv_vector_transform( &v, &glyph_transform );
x1 = (int)(v.x+0.5);
x1 = glyph_org_x + hint->pos*glyph_scale;
nv_pixmap_fill_rect( target, x1, 0, 1, target->height,
ps_hint_is_ghost(hint)
? GHOST_HINT_COLOR : STEM_HINT_COLOR );
if ( !ps_hint_is_ghost(hint) )
{
v.x = hint->pos + hint->len;
v.y = 0;
nv_vector_transform( &v, &glyph_transform );
x2 = (int)(v.x+0.5);
x2 = glyph_org_x + (hint->pos + hint->len)*glyph_scale;
nv_pixmap_fill_rect( target, x2, 0, 1, target->height,
STEM_HINT_COLOR );
}
else
{
x1 -= 1;
x2 = x1 + 2;
}
nv_pixmap_fill_rect( target, x1, cpos, x2-x1+1, 1,
STEM_JOIN_COLOR );
cpos += 10;
}
}
#define TOGGLE_OPTION(var,prefix) \
{ \
var = !var; \
sprintf( temp_message, prefix " is now %s", \
var ? "on" : "off" ); \
break; \
}
/* draw horizontal stems */
if ( option_show_horz_hints )
{
dim = &the_ps_hints->dimension[0];
hint = dim->hints.hints;
cpos = 10;
for ( count = dim->hints.num_hints; count > 0; count--, hint++ )
{
NV_Int y1, y2;
v.x = 0;
v.y = hint->pos;
nv_vector_transform( &v, &glyph_transform );
y1 = (int)(v.y+0.5);
y1 = glyph_org_y - hint->pos*glyph_scale;
nv_pixmap_fill_rect( target, 0, y1, target->width, 1,
ps_hint_is_ghost(hint)
? GHOST_HINT_COLOR : STEM_HINT_COLOR );
if ( !ps_hint_is_ghost(hint) )
{
v.x = 0;
v.y = hint->pos + hint->len;
nv_vector_transform( &v, &glyph_transform );
y2 = (int)(v.y+0.5);
y2 = glyph_org_y - (hint->pos + hint->len)*glyph_scale;
nv_pixmap_fill_rect( target, 0, y2, target->width, 1,
STEM_HINT_COLOR );
}
else
{
y1 -= 1;
y2 = y1 + 2;
}
nv_pixmap_fill_rect( target, cpos, y2, 1, y1-y2+1,
STEM_JOIN_COLOR );
cpos += 10;
}
}
}
}
#endif
#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 )
{
@ -509,34 +734,19 @@ handle_event( NVV_EventRec* ev )
}
case NVV_KEY('x'):
{
option_show_axis = !option_show_axis;
break;
}
TOGGLE_OPTION( option_show_axis, "grid axis display" )
case NVV_KEY('s'):
{
option_show_stroke = !option_show_stroke;
break;
}
TOGGLE_OPTION( option_show_stroke, "glyph stroke display" )
case NVV_KEY('g'):
{
option_show_glyph = !option_show_glyph;
break;
}
TOGGLE_OPTION( option_show_glyph, "glyph fill display" )
case NVV_KEY('d'):
{
option_show_dots = !option_show_dots;
break;
}
TOGGLE_OPTION( option_show_dots, "control points display" )
case NVV_KEY('e'):
{
option_show_em = !option_show_em;
break;
}
TOGGLE_OPTION( option_show_em, "EM square display" )
case NVV_KEY('+'):
{
@ -575,51 +785,90 @@ handle_event( NVV_EventRec* ev )
}
case NVV_KEY('z'):
{
ps_debug_no_vert_hints = !ps_debug_no_vert_hints;
sprintf( temp_message, "vertical hints processing is now %s",
ps_debug_no_vert_hints ? "off" : "on" );
break;
}
TOGGLE_OPTION_NEG( ps_debug_no_vert_hints, "vertical hints processing" )
case NVV_KEY('a'):
{
ps_debug_no_horz_hints = !ps_debug_no_horz_hints;
sprintf( temp_message, "horizontal hints processing is now %s",
ps_debug_no_horz_hints ? "off" : "on" );
break;
}
TOGGLE_OPTION_NEG( ps_debug_no_horz_hints, "horizontal hints processing" )
case NVV_KEY('Z'):
{
option_show_vert_hints = !option_show_vert_hints;
sprintf( temp_message, "vertical hints display is now %s",
option_show_vert_hints ? "off" : "on" );
break;
}
TOGGLE_OPTION( option_show_vert_hints, "vertical hints display" )
case NVV_KEY('A'):
{
option_show_horz_hints = !option_show_horz_hints;
sprintf( temp_message, "horizontal hints display is now %s",
option_show_horz_hints ? "off" : "on" );
break;
}
TOGGLE_OPTION( option_show_horz_hints, "horizontal hints display" )
case NVV_KEY('S'):
TOGGLE_OPTION( option_show_smooth, "smooth points display" );
case NVV_KEY('b'):
TOGGLE_OPTION( option_show_blues, "blue zones display" );
case NVV_KEY('h'):
{
option_hinting = !option_hinting;
sprintf( temp_message, "hinting is now %s",
option_hinting ? "off" : "on" );
break;
}
TOGGLE_OPTION( option_hinting, "hinting" )
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 = "/fonts/lcdxsr.pfa";
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" );
@ -629,7 +878,7 @@ int main( int argc, char** argv )
error = nvv_display_new( renderer, &display );
if (error) Panic( "could not create display" );
error = nvv_surface_new( display, 400, 400, nv_pixmap_type_argb, &surface );
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 );
@ -644,7 +893,7 @@ int main( int argc, char** argv )
error = FT_Init_FreeType( &freetype );
if (error) Panic( "could not initialise FreeType" );
error = FT_New_Face( freetype, "h:/fonts/cour.pfa", 0, &face );
error = FT_New_Face( freetype, filename, 0, &face );
if (error) Panic( "could not open font face" );
reset_size( pixel_size, grid_scale );
@ -655,15 +904,16 @@ int main( int argc, char** argv )
{
NVV_EventRec event;
glyph_index = 0;
glyph_index = first_glyph;
for ( ;; )
{
clear_background();
draw_grid();
the_ps_hints = 0;
ps_debug_hints = 0;
draw_ps_blue_zones();
draw_glyph( glyph_index );
/* draw_ps_hints(); */
ps2_draw_control_points();
nvv_surface_refresh( surface, NULL );