* src/pshinter/{pshalgo2.c, pshalgo1.c}: fixed stupid bug in sorting

routine that created nasty alignment artefacts.

        * src/pshinter/pshrec.c, tests/gview.c: debugging updates..

        * src/smooth/ftgrays.c: de-activated experimental gamme support,
        apparently, "optimal" gamma tables depend on the monitor type,
        resolution and general karma, so it's better to compute them outside
        of the rasterizer itself..
This commit is contained in:
David Turner 2001-11-20 01:29:34 +00:00
parent adf07a930c
commit f2c56515f5
7 changed files with 565 additions and 493 deletions

View File

@ -1,13 +1,26 @@
2001-11-20 David Turner <david@freetype.org>
* src/pshinter/{pshalgo2.c, pshalgo1.c}: fixed stupid bug in sorting
routine that created nasty alignment artefacts.
* src/pshinter/pshrec.c, tests/gview.c: debugging updates..
* src/smooth/ftgrays.c: de-activated experimental gamme support,
apparently, "optimal" gamma tables depend on the monitor type,
resolution and general karma, so it's better to compute them outside
of the rasterizer itself..
2001-10-29 David Turner <david@freetype.org>
* src/smooth/ftgrays.c: adding experimental "gamma" support. This
produces smoother glyphs at small sizes for very little cost
* src/autohint/ahglyph.c, src/autohint/ahhint.c: various fixes to
the auto-hinter. They merely improve the output of sans-serif fonts.
Note that there are still problems with serifed fonts and composites
(accented characters)
* tests/gview.c: updated the debugging glyph viewer to show the
hints generated by the "autohint" module
@ -22,15 +35,15 @@
* include/freetype/ftcache.h, include/freetype/cache/*.h,
src/cache/*.c: Major re-design of the cache sub-system to provide
better performance as well as an "Acquire"/"Release" API..
seems to work well here.. but probably needs a bit more testing..
2001-10-26 Leonard Rosenthol <leonardr@lazerware.com>
* updated Mac OS README (builds/mac/) to reflect my taking over
the project and that is now being actively maintained.
* Applied patches from Paul Miller (<paulm@profoundeffects.com>)
to /src/base/ftmac.c to support loading a face other than the
first from a FOND resource.
@ -61,7 +74,7 @@
improvements to the memory debugger to report more information in
case of errors. Also, some allocations that occured through
REALLOC couldn't be previously catched correctly..
* src/autohint/ahglyph.c, src/raster/ftraster.c,
src/smooth/ftgrays.c: replaced liberal uses of "memset" by the
@ -87,10 +100,10 @@
the FT_DEBUG_MEMORY macro in "ftoption.h" to enable it. It will record
every memory block allocated and report simple errors like memory
leaks and double deletes.
* include/freetype/config/ftoption.h: added the FT_DEBUG_MEMORY macro
definition
* src/base/ftsystem.c (FT_New_Memory, FT_Done_Memory): modified the
base component to use the debugging memory manager when the macro
FT_DEBUG_MEMORY is defined..
@ -115,7 +128,7 @@
2001-10-20 Tom Kacvinsky <tkacvins@freetype.org>
* src/type1/t1load.c (parse_encoding): Add a test to make sure
that custom encodings (i.e., neither StandardEncoding nor
ExpertEncoding) are not loaded twice when the Type 1 font is
@ -162,7 +175,7 @@
some strange bugs in the Postscript hinter
* src/cid/cidgload.c: adding support to new postscript hinter
* include/freetype/internal/psglobal.h,
include/freetype/internal/pshints.h,
include/freetype/config/ftmodule.h,
@ -276,7 +289,7 @@
Provide a public API to manage multiple size objects for a given
FT_Face in the new header file `ftsizes.h'.
* include/freetype/ftsizes.h: New header file,
* include/freetype/ftsizes.h: New header file,
* include/freetype/internal/ftobjs.h: Use it.
Remove declarations of FT_New_Size and FT_Done_Size (moved to
ftsizes.h).
@ -520,7 +533,7 @@
2001-06-22 David Turner <david@freetype.org>
* docs/PATENTS: Added patents disclaimer. This one was missing!
* docs/CHANGES, docs/todo: Updated for the upcoming 2.0.4 release.
2001-06-20 Werner Lemberg <wl@gnu.org>

View File

@ -15,7 +15,7 @@
/***** *****/
/************************************************************************/
/************************************************************************/
/* return true iff two stem hints overlap */
static FT_Int
psh1_hint_overlap( PSH1_Hint hint1,
@ -24,8 +24,8 @@
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,
@ -34,7 +34,7 @@
FREE( table->zones );
table->num_zones = 0;
table->zone = 0;
FREE( table->sort );
FREE( table->hints );
table->num_hints = 0;
@ -49,7 +49,7 @@
{
FT_UInt count = table->max_hints;
PSH1_Hint hint = table->hints;
for ( ; count > 0; count--, hint++ )
{
psh1_hint_deactivate(hint);
@ -70,13 +70,13 @@
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.. */
{
@ -84,11 +84,11 @@
FT_UInt count = table->num_hints;
PSH1_Hint hint2;
hint->parent = 0;
hint->parent = 0;
for ( ; count > 0; count--, sorted++ )
{
hint2 = sorted[0];
if ( psh1_hint_overlap( hint, hint2 ) )
{
hint->parent = hint2;
@ -96,7 +96,7 @@
}
}
}
if ( table->num_hints < table->max_hints )
table->sort_global[ table->num_hints++ ] = hint;
else
@ -115,14 +115,14 @@
FT_Byte* cursor = hint_mask->bytes;
FT_UInt index, limit;
limit = hint_mask->num_bits;
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 )
@ -130,10 +130,10 @@
val = *cursor++;
mask = 0x80;
}
if ( val & mask )
psh1_hint_table_record( table, index );
mask >>= 1;
}
}
@ -151,24 +151,24 @@
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;
@ -185,22 +185,22 @@
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;
}
@ -215,11 +215,11 @@
FT_Byte* cursor = hint_mask->bytes;
FT_UInt index, limit, count;
limit = hint_mask->num_bits;
limit = hint_mask->num_bits;
count = 0;
psh1_hint_table_deactivate( table );
for ( index = 0; index < limit; index++ )
{
if ( mask == 0 )
@ -227,17 +227,17 @@
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];
@ -248,7 +248,7 @@
break;
}
}
if ( count2 == 0 )
{
psh1_hint_activate( hint );
@ -258,15 +258,15 @@
{
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.. */
{
@ -284,9 +284,9 @@
hint2 = sort[i2];
if ( hint2->org_pos < hint1->org_pos )
break;
sort[i1] = hint2;
sort[i2] = hint1;
sort[i2+1] = hint2;
sort[i2] = hint1;
}
}
}
@ -305,7 +305,7 @@
/***** *****/
/************************************************************************/
/************************************************************************/
#ifdef DEBUG_HINTER
void
ps_simple_scale( PSH1_Hint_Table table,
@ -315,7 +315,7 @@
{
PSH1_Hint hint;
FT_UInt count;
for ( count = 0; count < table->num_hints; count++ )
{
hint = table->sort[count];
@ -323,12 +323,12 @@
{
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
@ -349,7 +349,7 @@
ps_simple_scale( table, scale, delta, vertical );
return 0;
}
if ( ps_debug_no_horz_hints && !vertical )
{
ps_simple_scale( table, scale, delta, vertical );
@ -359,10 +359,10 @@
/* 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];
@ -371,10 +371,10 @@
# 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 */
@ -383,9 +383,9 @@
fit_len = 64;
else
fit_len = (fit_len + 32 ) & -64;
hint->cur_len = fit_len;
/* check blue zones for horizontal stems */
align.align = 0;
align.align_bot = align.align_top = 0;
@ -405,14 +405,14 @@
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 */
@ -420,7 +420,7 @@
hint->cur_len = align.align_top - align.align_bot;
}
break;
default:
/* normal processing */
if ( (fit_len/64) & 1 )
@ -433,22 +433,22 @@
/* 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
# endif
#ifdef DEBUG_HINTER
if (ps1_debug_hint_func)
ps1_debug_hint_func( hint, vertical );
#endif
#endif
}
}
}
return 0;
}
@ -462,7 +462,7 @@
/***** *****/
/************************************************************************/
/************************************************************************/
#define PSH1_ZONE_MIN -3200000
#define PSH1_ZONE_MAX +3200000
@ -497,9 +497,9 @@
FT_UInt count;
PSH1_Zone zone;
PSH1_Hint *sort, hint, hint2;
zone = table->zones;
/* special case, no hints defined */
if ( table->num_hints == 0 )
{
@ -507,26 +507,26 @@
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;
@ -536,7 +536,7 @@
/* 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;
@ -544,16 +544,16 @@
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 */
@ -565,9 +565,9 @@
zone->delta = hint->cur_pos + hint->cur_len - FT_MulFix( zone->min, scale2 );
print_zone( zone );
zone++;
hint = hint2;
}
@ -578,30 +578,30 @@
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 */
/* 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 );
@ -613,13 +613,13 @@
{
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;
}
@ -639,7 +639,7 @@
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;
@ -648,40 +648,40 @@
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++ )
@ -694,8 +694,8 @@
}
}
}
/************************************************************************/
/************************************************************************/
/***** *****/
@ -703,7 +703,7 @@
/***** *****/
/************************************************************************/
/************************************************************************/
FT_Error
ps1_hints_apply( PS_Hints ps_hints,
FT_Outline* outline,
@ -712,11 +712,11 @@
PSH1_Hint_TableRec hints;
FT_Error error = 0;
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,
@ -725,15 +725,15 @@
&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;
return error;
}

File diff suppressed because it is too large Load Diff

View File

@ -31,11 +31,11 @@ FT_BEGIN_HEADER
PSH2_HINT_GHOST = PS_HINT_FLAG_GHOST,
PSH2_HINT_BOTTOM = PS_HINT_FLAG_BOTTOM,
PSH2_HINT_ACTIVE = 4,
PSH2_HINT_FITTED = 8
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_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
@ -51,7 +51,7 @@ FT_BEGIN_HEADER
FT_UInt flags;
PSH2_Hint parent;
FT_Int order;
} PSH2_HintRec;
@ -64,7 +64,7 @@ FT_BEGIN_HEADER
FT_Fixed delta;
FT_Pos min;
FT_Pos max;
} PSH2_ZoneRec, *PSH2_Zone;
@ -80,12 +80,13 @@ FT_BEGIN_HEADER
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,
@ -94,7 +95,7 @@ FT_BEGIN_HEADER
PSH2_DIR_LEFT = -2,
PSH2_DIR_RIGHT = 2
};
enum
{
PSH2_POINT_OFF = 1, /* point is off the curve */
@ -124,10 +125,11 @@ FT_BEGIN_HEADER
FT_Pos cur_y;
FT_UInt flags_x;
FT_UInt flags_y;
#endif
#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)
@ -140,37 +142,37 @@ FT_BEGIN_HEADER
{
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
#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

View File

@ -1009,9 +1009,9 @@
}
}
#ifdef DEBUG_VIEW
#ifdef DEBUG_HINTER
if (!error)
the_ps_hints = hints;
ps_debug_hints = hints;
#endif
return error;
}

View File

@ -86,7 +86,7 @@
/* experimental support for gamma correction within the rasterizer */
#define GRAYS_USE_GAMMA
#define xxxGRAYS_USE_GAMMA
/*************************************************************************/
/* */
@ -209,7 +209,7 @@
/* */
/* TYPE DEFINITIONS */
/* */
/* don't change the following types to FT_Int or FT_Pos, since we might */
/* need to define them to "float" or "double" when experimenting with */
/* new algorithms */
@ -220,7 +220,7 @@
/* determine the type used to store cell areas. This normally takes at */
/* least PIXEL_BYTES*2 + 1. On 16-bit systems, we need to use `long' */
/* instead of `int', otherwise bad things happen */
#if PIXEL_BITS <= 7
typedef int TArea;
@ -1181,9 +1181,9 @@
/* start to a new position */
x = UPSCALE( to->x );
y = UPSCALE( to->y );
gray_start_cell( (PRaster)raster, TRUNC( x ), TRUNC( y ) );
((PRaster)raster)->x = x;
((PRaster)raster)->y = y;
return 0;
@ -1243,7 +1243,7 @@
#ifdef GRAYS_USE_GAMMA
coverage = raster->gamma[(FT_Byte)coverage];
#endif
if ( coverage )
#if 1
MEM_Set( p + spans->x, (unsigned char)coverage, spans->len );
@ -1400,7 +1400,7 @@
if ( ras.num_cells == 0 )
return;
cur = ras.cells;
limit = cur + ras.num_cells;
@ -1748,7 +1748,7 @@
};
volatile int error = 0;
if ( setjmp( ras.jump_buffer ) == 0 )
{
error = FT_Outline_Decompose( &ras.outline, &interface, &ras );
@ -1778,7 +1778,7 @@
/* clip to target bitmap, exit if nothing to do */
clip = &ras.clip_box;
if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax ||
ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax )
return 0;
@ -1841,7 +1841,7 @@
#if 1
error = gray_convert_glyph_inner( RAS_VAR );
#else
#else
error = FT_Outline_Decompose( outline, &interface, &ras ) ||
gray_record_cell( RAS_VAR );
#endif
@ -1987,18 +1987,18 @@
grays_init_gamma( PRaster raster )
{
FT_UInt x, a;
for ( x = 0; x < 256; x++ )
{
if ( x <= M_X )
a = (x * M_Y + (M_X/2)) / M_X;
else
a = M_Y + ((x-M_X)*(M_MAX-M_Y) + (M_MAX-M_X)/2)/(M_MAX-M_X);
raster->gamma[x] = (FT_Byte)a;
}
}
#endif /* GRAYS_USE_GAMMA */
#ifdef _STANDALONE_
@ -2018,7 +2018,7 @@
#ifdef GRAYS_USE_GAMMA
grays_init_gamma( (PRaster)*araster );
#endif
return 0;
}

View File

@ -74,6 +74,7 @@ static int option_show_blues = 0;
static int option_show_edges = 0;
static int option_show_segments = 1;
static int option_show_links = 1;
static int option_show_indices = 0;
static int option_show_ps_hints = 1;
static int option_show_horz_hints = 1;
@ -112,7 +113,7 @@ static NV_Path symbol_rect_v = NULL;
#define EDGE_COLOR 0xF0704070
#define SEGMENT_COLOR 0xF0206040
#define LINK_COLOR 0xF0FFFF00
#define SERIF_LINK_COLOR 0xF0FF808F
#define SERIF_LINK_COLOR 0xF0FF808F
/* print message and abort program */
static void
@ -160,15 +161,15 @@ done_symbols( void )
static void
reset_scale( NV_Scale scale )
{
{
/* compute font units -> grid pixels scale factor */
glyph_scale = target->width*0.75 / face->units_per_EM * scale;
/* setup font units -> grid pixels transform */
nv_transform_set_scale( &glyph_transform, glyph_scale, -glyph_scale );
glyph_org_x = glyph_transform.delta.x = target->width*0.125;
glyph_org_y = glyph_transform.delta.y = target->height*0.875;
/* setup subpixels -> grid pixels transform */
nv_transform_set_scale( &size_transform,
glyph_scale/nv_fromfixed(face->size->metrics.x_scale),
@ -176,8 +177,8 @@ reset_scale( NV_Scale scale )
size_transform.delta = glyph_transform.delta;
}
static void
reset_size( int pixel_size, NV_Scale scale )
{
@ -204,7 +205,7 @@ draw_grid( void )
if ( option_show_grid )
{
NV_Scale min, max, x, step;
/* draw vertical grid bars */
step = 64. * size_transform.matrix.xx;
if (step > 1.)
@ -212,12 +213,12 @@ draw_grid( void )
min = max = glyph_org_x;
while ( min - step >= 0 ) min -= step;
while ( max + step < target->width ) max += step;
for ( x = min; x <= max; x += step )
nv_pixmap_fill_rect( target, (NV_Int)(x+.5), 0,
1, target->height, GRID_COLOR );
}
/* draw horizontal grid bars */
step = -64. * size_transform.matrix.yy;
if (step > 1.)
@ -225,29 +226,29 @@ draw_grid( void )
min = max = glyph_org_y;
while ( min - step >= 0 ) min -= step;
while ( max + step < target->height ) max += step;
for ( x = min; x <= max; x += step )
nv_pixmap_fill_rect( target, 0, (NV_Int)(x+.5),
target->width, 1, GRID_COLOR );
}
}
}
/* draw axis */
if ( option_show_axis )
{
nv_pixmap_fill_rect( target, x, 0, 1, target->height, AXIS_COLOR );
nv_pixmap_fill_rect( target, 0, y, target->width, 1, AXIS_COLOR );
}
if ( option_show_em )
{
NV_Path path;
NV_Path stroke;
NV_UInt units = (NV_UInt)face->units_per_EM;
nv_path_new_rectangle( renderer, 0, 0, units, units, 0, 0, &path );
nv_path_transform( path, &glyph_transform );
nv_path_stroke( path, 1.5, nv_path_linecap_butt, nv_path_linejoin_miter,
4.0, &stroke );
@ -282,12 +283,12 @@ draw_ps_blue_zones( void )
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;
@ -302,7 +303,7 @@ draw_ps_blue_zones( void )
nv_vector_transform( &v, &glyph_transform );
}
y1 = (int)(v.y + 0.5);
v.x = 0;
if ( !ps_debug_no_horz_hints )
{
@ -315,34 +316,34 @@ draw_ps_blue_zones( void )
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
#if 0
printf( "top [%.3f %.3f]\n", zone->cur_bottom/64.0, zone->cur_top/64.0 );
#endif
#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 );
@ -372,23 +373,23 @@ draw_ps1_hint( PSH1_Hint hint, FT_Bool vertical )
{
int x1, x2;
NV_Vector v;
if ( pshint_vertical != vertical )
{
if (vertical)
pshint_cpos = 40;
else
pshint_cpos = 10;
pshint_vertical = vertical;
}
if (vertical)
{
if ( !option_show_vert_hints )
return;
v.x = hint->cur_pos;
v.y = 0;
nv_vector_transform( &v, &size_transform );
@ -420,7 +421,7 @@ draw_ps1_hint( PSH1_Hint hint, FT_Bool vertical )
{
if (!option_show_horz_hints)
return;
v.y = hint->cur_pos;
v.x = 0;
nv_vector_transform( &v, &size_transform );
@ -452,7 +453,7 @@ draw_ps1_hint( PSH1_Hint hint, FT_Bool vertical )
#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;
}
@ -473,22 +474,22 @@ 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 );
@ -520,7 +521,7 @@ draw_ps2_hint( PSH2_Hint hint, FT_Bool vertical )
{
if (!option_show_horz_hints)
return;
v.y = hint->cur_pos;
v.x = 0;
nv_vector_transform( &v, &size_transform );
@ -552,7 +553,7 @@ draw_ps2_hint( PSH2_Hint hint, FT_Bool vertical )
#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;
}
@ -569,15 +570,15 @@ ps2_draw_control_points( void )
NV_Path vert_rect;
NV_Path horz_rect;
NV_Path dot, circle;
for ( ; count > 0; count--, point++ )
{
NV_Vector vec;
vec.x = point->cur_x;
vec.y = point->cur_y;
nv_vector_transform( &vec, &size_transform );
nv_transform_set_translate( trans, vec.x, vec.y );
if ( option_show_smooth && !psh2_point_is_smooth(point) )
@ -585,7 +586,7 @@ ps2_draw_control_points( void )
nv_painter_set_color( painter, SMOOTH_COLOR, 256 );
nv_painter_fill_path( painter, trans, 0, symbol_circle );
}
if (option_show_horz_hints)
{
if ( point->flags_y & PSH2_POINT_STRONG )
@ -594,7 +595,7 @@ ps2_draw_control_points( void )
nv_painter_fill_path( painter, trans, 0, symbol_rect_h );
}
}
if (option_show_vert_hints)
{
if ( point->flags_x & PSH2_POINT_STRONG )
@ -607,6 +608,44 @@ ps2_draw_control_points( void )
}
}
static void
ps_print_hints( void )
{
if ( ps_debug_hints )
{
FT_Int dimension;
PSH_Dimension dim;
for ( dimension = 1; dimension >= 0; dimension-- )
{
PS_Dimension dim = &ps_debug_hints->dimension[ dimension ];
PS_Mask mask = dim->masks.masks;
FT_UInt count = dim->masks.num_masks;
printf( "%s hints -------------------------\n",
dimension ? "vertical" : "horizontal" );
for ( ; count > 0; count--, mask++ )
{
FT_UInt index;
printf( "mask -> %d\n", mask->end_point );
for ( index = 0; index < mask->num_bits; index++ )
{
if ( mask->bytes[ index >> 3 ] & (0x80 >> (index & 7)) )
{
PS_Hint hint = dim->hints.hints + index;
printf( "%c [%3d %3d (%4d)]\n", dimension ? "v" : "h",
hint->pos, hint->pos + hint->len, hint->len );
}
}
}
}
}
}
/************************************************************************/
/************************************************************************/
/***** *****/
@ -628,7 +667,7 @@ ah_link_path( NV_Vector* p1,
{
p2.x = p4->x;
p2.y = p1->y;
p3.x = p1->x;
p3.y = p4->y;
}
@ -636,25 +675,25 @@ ah_link_path( NV_Vector* p1,
{
p2.x = p1->x;
p2.y = p4->y;
p3.x = p4->x;
p3.y = p1->y;
}
}
nv_path_writer_new( renderer, &writer );
nv_path_writer_moveto( writer, p1 );
nv_path_writer_cubicto( writer, &p2, &p3, p4 );
nv_path_writer_end( writer );
path = nv_path_writer_get_path( writer );
nv_path_writer_destroy( writer );
nv_path_stroke( path, 1., nv_path_linecap_butt, nv_path_linejoin_round, 1., &stroke );
nv_path_destroy( path );
return stroke;
}
}
static void
@ -665,20 +704,20 @@ ah_draw_smooth_points( void )
AH_Outline* glyph = ah_debug_hinter->glyph;
FT_UInt count = glyph->num_points;
AH_Point* point = glyph->points;
nv_painter_set_color( painter, SMOOTH_COLOR, 256 );
for ( ; count > 0; count--, point++ )
{
if ( !( point->flags & ah_flag_weak_interpolation ) )
{
NV_Transform transform, *trans = &transform;
NV_Vector vec;
vec.x = point->x - ah_debug_hinter->pp1.x;
vec.y = point->y;
nv_vector_transform( &vec, &size_transform );
nv_transform_set_translate( &transform, vec.x, vec.y );
nv_painter_fill_path( painter, trans, 0, symbol_circle );
}
@ -696,31 +735,31 @@ ah_draw_edges( void )
FT_UInt count;
AH_Edge* edge;
FT_Pos pp1 = ah_debug_hinter->pp1.x;
nv_painter_set_color( painter, EDGE_COLOR, 256 );
if ( option_show_edges )
{
/* draw verticla edges */
if ( option_show_vert_hints )
{
{
count = glyph->num_vedges;
edge = glyph->vert_edges;
for ( ; count > 0; count--, edge++ )
{
NV_Vector vec;
NV_Pos x;
vec.x = edge->pos - pp1;
vec.y = 0;
nv_vector_transform( &vec, &size_transform );
x = (FT_Pos)( vec.x + 0.5 );
nv_pixmap_fill_rect( target, x, 0, 1, target->height, EDGE_COLOR );
}
}
/* draw horizontal edges */
if ( option_show_horz_hints )
{
@ -730,18 +769,18 @@ ah_draw_edges( void )
{
NV_Vector vec;
NV_Pos x;
vec.x = 0;
vec.y = edge->pos;
nv_vector_transform( &vec, &size_transform );
x = (FT_Pos)( vec.y + 0.5 );
nv_pixmap_fill_rect( target, 0, x, target->width, 1, EDGE_COLOR );
}
}
}
if ( option_show_segments )
{
/* draw vertical segments */
@ -749,18 +788,18 @@ ah_draw_edges( void )
{
AH_Segment* seg = glyph->vert_segments;
FT_UInt count = glyph->num_vsegments;
for ( ; count > 0; count--, seg++ )
{
AH_Point *first, *last;
NV_Vector v1, v2;
NV_Pos y1, y2, x;
first = seg->first;
last = seg->last;
v1.x = v2.x = first->x - pp1;
if ( first->y <= last->y )
{
v1.y = first->y;
@ -771,35 +810,35 @@ ah_draw_edges( void )
v1.y = last->y;
v2.y = first->y;
}
nv_vector_transform( &v1, &size_transform );
nv_vector_transform( &v2, &size_transform );
y1 = (NV_Pos)( v1.y + 0.5 );
y2 = (NV_Pos)( v2.y + 0.5 );
x = (NV_Pos)( v1.x + 0.5 );
nv_pixmap_fill_rect( target, x-1, y2, 3, ABS(y1-y2)+1, SEGMENT_COLOR );
}
}
/* draw horizontal segments */
if ( option_show_horz_hints )
{
AH_Segment* seg = glyph->horz_segments;
FT_UInt count = glyph->num_hsegments;
for ( ; count > 0; count--, seg++ )
{
AH_Point *first, *last;
NV_Vector v1, v2;
NV_Pos y1, y2, x;
first = seg->first;
last = seg->last;
v1.y = v2.y = first->y;
if ( first->x <= last->x )
{
v1.x = first->x - pp1;
@ -810,14 +849,14 @@ ah_draw_edges( void )
v1.x = last->x - pp1;
v2.x = first->x - pp1;
}
nv_vector_transform( &v1, &size_transform );
nv_vector_transform( &v2, &size_transform );
y1 = (NV_Pos)( v1.x + 0.5 );
y2 = (NV_Pos)( v2.x + 0.5 );
x = (NV_Pos)( v1.y + 0.5 );
nv_pixmap_fill_rect( target, y1, x-1, ABS(y1-y2)+1, 3, SEGMENT_COLOR );
}
}
@ -827,13 +866,13 @@ ah_draw_edges( void )
{
AH_Segment* seg = glyph->vert_segments;
FT_UInt count = glyph->num_vsegments;
for ( ; count > 0; count--, seg++ )
{
AH_Segment* seg2 = NULL;
NV_Path link;
NV_Vector v1, v2;
if ( seg->link )
{
if ( seg->link > seg )
@ -841,19 +880,19 @@ ah_draw_edges( void )
}
else if ( seg->serif )
seg2 = seg->serif;
if ( seg2 )
{
v1.x = seg->first->x - pp1;
v2.x = seg2->first->x - pp1;
v1.y = (seg->first->y + seg->last->y)/2;
v2.y = (seg2->first->y + seg2->last->y)/2;
link = ah_link_path( &v1, &v2, 1 );
nv_painter_set_color( painter, seg->serif ? SERIF_LINK_COLOR : LINK_COLOR, 256 );
nv_painter_fill_path( painter, &size_transform, 0, link );
nv_path_destroy( link );
}
}
@ -863,13 +902,13 @@ ah_draw_edges( void )
{
AH_Segment* seg = glyph->horz_segments;
FT_UInt count = glyph->num_hsegments;
for ( ; count > 0; count--, seg++ )
{
AH_Segment* seg2 = NULL;
NV_Path link;
NV_Vector v1, v2;
if ( seg->link )
{
if ( seg->link > seg )
@ -877,19 +916,19 @@ ah_draw_edges( void )
}
else if ( seg->serif )
seg2 = seg->serif;
if ( seg2 )
{
v1.y = seg->first->y;
v2.y = seg2->first->y;
v1.x = (seg->first->x + seg->last->x)/2 - pp1;
v2.x = (seg2->first->x + seg2->last->x)/2 - pp1;
link = ah_link_path( &v1, &v2, 0 );
nv_painter_set_color( painter, seg->serif ? SERIF_LINK_COLOR : LINK_COLOR, 256 );
nv_painter_fill_path( painter, &size_transform, 0, link );
nv_path_destroy( link );
}
}
@ -912,7 +951,7 @@ draw_glyph( int glyph_index )
NV_Path path;
pshint_vertical = -1;
ps1_debug_hint_func = option_show_ps_hints ? draw_ps1_hint : 0;
ps2_debug_hint_func = option_show_ps_hints ? draw_ps2_hint : 0;
@ -922,16 +961,16 @@ draw_glyph( int glyph_index )
? FT_LOAD_NO_BITMAP
: FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING );
if (error) Panic( "could not load glyph" );
if ( face->glyph->format != ft_glyph_format_outline )
Panic( "could not load glyph outline" );
error = nv_path_new_from_outline( renderer,
(NV_Outline*)&face->glyph->outline,
&size_transform,
&path );
if (error) Panic( "could not create glyph path" );
/* tracé du glyphe plein */
if ( option_show_glyph )
{
@ -942,16 +981,16 @@ draw_glyph( int glyph_index )
if ( option_show_stroke )
{
NV_Path stroke;
error = nv_path_stroke( path, 0.6,
nv_path_linecap_butt,
nv_path_linejoin_miter,
1.0, &stroke );
if (error) Panic( "could not stroke glyph path" );
nv_painter_set_color ( painter, 0xFF000040, 256 );
nv_painter_fill_path ( painter, 0, 0, stroke );
nv_path_destroy( stroke );
}
@ -964,7 +1003,7 @@ draw_glyph( int glyph_index )
NV_Int n, first, last;
nv_path_get_outline( path, NULL, memory, &out );
first = 0;
for ( n = 0; n < out.n_contours; n++ )
{
@ -972,47 +1011,55 @@ draw_glyph( int glyph_index )
NV_Transform trans;
NV_Color color;
NV_SubVector* vec;
last = out.contours[n];
for ( m = first; m <= last; m++ )
{
color = (out.tags[m] & FT_Curve_Tag_On)
? ON_COLOR
: OFF_COLOR;
vec = out.points + m;
nv_transform_set_translate( &trans, vec->x/64.0, vec->y/64.0 );
nv_transform_set_translate( &trans, vec->x/64.0, vec->y/64.0 );
nv_painter_set_color( painter, color, 256 );
nv_painter_fill_path( painter, &trans, 0, symbol_dot );
if ( option_show_indices )
{
char temp[5];
sprintf( temp, "%d", m );
nv_pixmap_cell_text( target, vec->x/64 + 4, vec->y/64 - 4,
temp, TEXT_COLOR );
}
}
first = last + 1;
}
}
ah_draw_smooth_points();
ah_draw_edges();
nv_path_destroy( path );
/* autre infos */
{
char temp[1024];
char temp2[64];
sprintf( temp, "font name : %s (%s)", face->family_name, face->style_name );
nv_pixmap_cell_text( target, 0, 0, temp, TEXT_COLOR );
FT_Get_Glyph_Name( face, glyph_index, temp2, 63 );
temp2[63] = 0;
sprintf( temp, "glyph %4d: %s", glyph_index, temp2 );
nv_pixmap_cell_text( target, 0, 8, temp, TEXT_COLOR );
if ( temp_message[0] )
{
nv_pixmap_cell_text( target, 0, 16, temp_message, TEXT_COLOR );
@ -1040,7 +1087,7 @@ draw_glyph( int glyph_index )
break; \
}
static void
handle_event( NVV_EventRec* ev )
{
@ -1065,23 +1112,23 @@ handle_event( NVV_EventRec* ev )
case NVV_KEY('s'):
TOGGLE_OPTION( option_show_stroke, "glyph stroke display" )
case NVV_KEY('g'):
TOGGLE_OPTION( option_show_glyph, "glyph fill display" )
case NVV_KEY('d'):
TOGGLE_OPTION( option_show_dots, "control points display" )
case NVV_KEY('e'):
TOGGLE_OPTION( option_show_em, "EM square display" )
case NVV_KEY('+'):
{
grid_scale *= 1.2;
reset_scale( grid_scale );
break;
}
case NVV_KEY('-'):
{
if (grid_scale > 0.3)
@ -1126,12 +1173,19 @@ handle_event( NVV_EventRec* ev )
case NVV_KEY('S'):
TOGGLE_OPTION( option_show_smooth, "smooth points display" );
case NVV_KEY('i'):
TOGGLE_OPTION( option_show_indices, "point index display" );
case NVV_KEY('b'):
TOGGLE_OPTION( option_show_blues, "blue zones display" );
case NVV_KEY('h'):
TOGGLE_OPTION( option_hinting, "hinting" )
case NVV_KEY('H'):
ps_print_hints();
break;
default:
;
}
@ -1166,7 +1220,7 @@ 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])
@ -1174,28 +1228,28 @@ parse_options( int* argc_p, char*** argv_p )
OPTION2( 'f', first_glyph = atoi( argv[2] ); )
OPTION2( 's', pixel_size = atoi( argv[2] ); )
default:
usage();
}
}
*argc_p = argc;
*argv_p = argv;
}
int main( int argc, char** argv )
{
char* filename = "/winnt/fonts/arial.ttf";
parse_options( &argc, &argv );
if ( argc >= 2 )
filename = argv[1];
/* create library */
error = nv_renderer_new( 0, &renderer );
if (error) Panic( "could not create Nirvana renderer" );
@ -1205,7 +1259,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, 460, 460, nv_pixmap_type_argb, &surface );
if (error) Panic( "could not create surface" );
@ -1213,26 +1267,26 @@ int main( int argc, char** argv )
error = nv_painter_new( renderer, &painter );
if (error) Panic( "could not create painter" );
nv_painter_set_target( painter, target );
clear_background();
error = FT_Init_FreeType( &freetype );
if (error) Panic( "could not initialise FreeType" );
error = FT_New_Face( freetype, filename, 0, &face );
if (error) Panic( "could not open font face" );
reset_size( pixel_size, grid_scale );
nvv_surface_set_title( surface, "FreeType Glyph Viewer" );
{
NVV_EventRec event;
glyph_index = first_glyph;
glyph_index = first_glyph;
for ( ;; )
{
clear_background();
@ -1247,29 +1301,29 @@ int main( int argc, char** argv )
draw_ps_blue_zones();
draw_glyph( glyph_index );
ps2_draw_control_points();
nvv_surface_refresh( surface, NULL );
nvv_surface_listen( surface, 0, &event );
if ( event.key == NVV_Key_Esc )
break;
handle_event( &event );
switch (event.key)
{
case NVV_Key_Esc:
goto Exit;
default:
;
}
}
}
Exit:
/* wait for escape */
/* destroy display (and surface) */
nvv_display_unref( display );