* 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..
BRANCH-2-1-5
David Turner 23 years ago
parent 9f892b4ef1
commit 782d522028
  1. 37
      ChangeLog
  2. 194
      src/pshinter/pshalgo1.c
  3. 423
      src/pshinter/pshalgo2.c
  4. 36
      src/pshinter/pshalgo2.h
  5. 4
      src/pshinter/pshrec.c
  6. 28
      src/smooth/ftgrays.c
  7. 336
      tests/gview.c

@ -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>

@ -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

@ -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

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

@ -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;
}

@ -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 );

Loading…
Cancel
Save