commited new Postscript hinter module
This commit is contained in:
parent
fbb7617183
commit
49884d3eeb
14
Jamfile
14
Jamfile
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
/* */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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" ;
|
||||
|
|
582
tests/gview.c
582
tests/gview.c
|
@ -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 );
|
||||
|
||||
|
|
Loading…
Reference in New Issue