summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Turner <david@freetype.org>2001-10-05 08:59:06 +0000
committerDavid Turner <david@freetype.org>2001-10-05 08:59:06 +0000
commit49884d3eebfe6b1bc6883927362a2ed267930dd9 (patch)
tree3a6e919c46ef6d707c3ae301f60b3f388158b7a5
parentfbb76171837aa4906d531b6d5610c836e1457f02 (diff)
downloadfreetype2-49884d3eebfe6b1bc6883927362a2ed267930dd9.tar.gz
commited new Postscript hinter module
-rw-r--r--Jamfile14
-rw-r--r--src/psaux/t1decode.c23
-rw-r--r--src/pshinter/Jamfile2
-rw-r--r--src/pshinter/pshalgo.h19
-rw-r--r--src/pshinter/pshalgo1.c736
-rw-r--r--src/pshinter/pshalgo1.h100
-rw-r--r--src/pshinter/pshalgo2.c1484
-rw-r--r--src/pshinter/pshalgo2.h185
-rw-r--r--src/pshinter/pshfit.c555
-rw-r--r--src/pshinter/pshfit.h110
-rw-r--r--src/pshinter/pshglob.c89
-rw-r--r--src/pshinter/pshglob.h15
-rw-r--r--src/pshinter/pshinter.c5
-rw-r--r--src/pshinter/pshmod.c1
-rw-r--r--src/pshinter/pshoptim.c145
-rw-r--r--src/pshinter/pshoptim.h41
-rw-r--r--src/pshinter/pshrec.c14
-rw-r--r--src/pshinter/pshrec.h7
-rw-r--r--src/smooth/ftgrays.c175
-rw-r--r--tests/Jamfile2
-rw-r--r--tests/gview.c582
21 files changed, 3157 insertions, 1147 deletions
diff --git a/Jamfile b/Jamfile
index fa774b3b9..8fc419bc0 100644
--- a/Jamfile
+++ b/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
diff --git a/src/psaux/t1decode.c b/src/psaux/t1decode.c
index d3af4163c..2ceaccc6b 100644
--- a/src/psaux/t1decode.c
+++ b/src/psaux/t1decode.c
@@ -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:
diff --git a/src/pshinter/Jamfile b/src/pshinter/Jamfile
index 081ded470..3b749f171 100644
--- a/src/pshinter/Jamfile
+++ b/src/pshinter/Jamfile
@@ -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
{
diff --git a/src/pshinter/pshalgo.h b/src/pshinter/pshalgo.h
new file mode 100644
index 000000000..641931124
--- /dev/null
+++ b/src/pshinter/pshalgo.h
@@ -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__ */
diff --git a/src/pshinter/pshalgo1.c b/src/pshinter/pshalgo1.c
new file mode 100644
index 000000000..eaa82de3d
--- /dev/null
+++ b/src/pshinter/pshalgo1.c
@@ -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;
+ }
diff --git a/src/pshinter/pshalgo1.h b/src/pshinter/pshalgo1.h
new file mode 100644
index 000000000..1b0dd5dc2
--- /dev/null
+++ b/src/pshinter/pshalgo1.h
@@ -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__ */
diff --git a/src/pshinter/pshalgo2.c b/src/pshinter/pshalgo2.c
new file mode 100644
index 000000000..c98aa78d2
--- /dev/null
+++ b/src/pshinter/pshalgo2.c
@@ -0,0 +1,1484 @@
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include "pshalgo2.h"
+
+
+#ifdef DEBUG_HINTER
+ extern PSH2_Hint_Table ps2_debug_hint_table = 0;
+ extern PSH2_HintFunc ps2_debug_hint_func = 0;
+ extern PSH2_Glyph ps2_debug_glyph = 0;
+#endif
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** BASIC HINTS RECORDINGS *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ /* return true iff two stem hints overlap */
+ static FT_Int
+ psh2_hint_overlap( PSH2_Hint hint1,
+ PSH2_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
+ psh2_hint_table_done( PSH2_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
+ psh2_hint_table_deactivate( PSH2_Hint_Table table )
+ {
+ FT_UInt count = table->max_hints;
+ PSH2_Hint hint = table->hints;
+
+ for ( ; count > 0; count--, hint++ )
+ {
+ psh2_hint_deactivate(hint);
+ hint->order = -1;
+ }
+ }
+
+
+ /* internal function used to record a new hint */
+ static void
+ psh2_hint_table_record( PSH2_Hint_Table table,
+ FT_UInt index )
+ {
+ PSH2_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 ( psh2_hint_is_active(hint) )
+ return;
+
+ psh2_hint_activate(hint);
+
+ /* now scan the current active hint set in order to determine */
+ /* if we're overlapping with another segment.. */
+ {
+ PSH2_Hint* sorted = table->sort_global;
+ FT_UInt count = table->num_hints;
+ PSH2_Hint hint2;
+
+ hint->parent = 0;
+ for ( ; count > 0; count--, sorted++ )
+ {
+ hint2 = sorted[0];
+
+ if ( psh2_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
+ psh2_hint_table_record_mask( PSH2_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 )
+ psh2_hint_table_record( table, index );
+
+ mask >>= 1;
+ }
+ }
+
+
+ /* create hints table */
+ static FT_Error
+ psh2_hint_table_init( PSH2_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, PSH2_Hint ) ||
+ ALLOC_ARRAY( table->hints, count, PSH2_HintRec ) ||
+ ALLOC_ARRAY( table->zones, 2*count+1, PSH2_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 */
+ {
+ PSH2_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++ )
+ psh2_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++ )
+ psh2_hint_table_record( table, index );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+
+ static void
+ psh2_hint_table_activate_mask( PSH2_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;
+
+ psh2_hint_table_deactivate( table );
+
+ for ( index = 0; index < limit; index++ )
+ {
+ if ( mask == 0 )
+ {
+ val = *cursor++;
+ mask = 0x80;
+ }
+
+ if ( val & mask )
+ {
+ PSH2_Hint hint = &table->hints[index];
+
+ if ( !psh2_hint_is_active(hint) )
+ {
+ PSH2_Hint* sort = table->sort;
+ FT_UInt count2;
+ PSH2_Hint hint2;
+
+#if 0
+ for ( count2 = count; count2 > 0; count2--, sort++ )
+ {
+ hint2 = sort[0];
+ if ( psh2_hint_overlap( hint, hint2 ) )
+ {
+ FT_ERROR(( "%s.activate_mask: found overlapping hints\n",
+ "psf.hint" ));
+ }
+ }
+#else
+ count2 = 0;
+#endif
+
+ if ( count2 == 0 )
+ {
+ psh2_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;
+ PSH2_Hint hint1, hint2;
+ PSH2_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
+ static void
+ ps_simple_scale( PSH2_Hint_Table table,
+ FT_Fixed scale,
+ FT_Fixed delta,
+ FT_Bool vertical )
+ {
+ PSH2_Hint hint;
+ FT_UInt count;
+
+ for ( count = 0; count < table->max_hints; count++ )
+ {
+ hint = table->hints + count;
+
+ hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
+ hint->cur_len = FT_MulFix( hint->org_len, scale );
+
+ if (ps2_debug_hint_func)
+ ps2_debug_hint_func( hint, vertical );
+ }
+ }
+#endif
+
+
+ static void
+ psh2_hint_align( PSH2_Hint hint,
+ PSH_Globals globals,
+ FT_Bool vertical )
+ {
+ PSH_Dimension dim = &globals->dimension[vertical];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+
+ if ( !psh2_hint_is_fitted(hint) )
+ {
+ 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 = 0;
+ if ( hint->org_len )
+ {
+ 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:
+ {
+ PSH2_Hint parent = hint->parent;
+
+ if ( parent )
+ {
+ FT_Pos par_org_center, par_cur_center;
+ FT_Pos cur_org_center, cur_delta;
+
+ /* ensure that parent is already fitted */
+ if ( !psh2_hint_is_fitted(parent) )
+ psh2_hint_align( parent, globals, vertical );
+
+ par_org_center = parent->org_pos + (parent->org_len/2);
+ par_cur_center = parent->cur_pos + (parent->cur_len/2);
+ cur_org_center = hint->org_pos + (hint->org_len/2);
+
+ cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
+#if 0
+ if ( cur_delta >= 0 )
+ cur_delta = (cur_delta+16) & -64;
+ else
+ cur_delta = -((-cur_delta+16) & -64);
+#endif
+ pos = par_cur_center + cur_delta - (len >> 1);
+ }
+
+ /* 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);
+ }
+ }
+
+ psh2_hint_set_fitted(hint);
+
+#ifdef DEBUG_HINTER
+ if (ps2_debug_hint_func)
+ ps2_debug_hint_func( hint, vertical );
+#endif
+ }
+ }
+
+
+ static void
+ psh2_hint_table_align_hints( PSH2_Hint_Table table,
+ PSH_Globals globals,
+ FT_Bool vertical )
+ {
+ PSH_Dimension dim = &globals->dimension[vertical];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+
+ PSH2_Hint hint;
+ FT_UInt count;
+
+#ifdef DEBUG_HINTER
+ if ( ps_debug_no_vert_hints && vertical )
+ {
+ ps_simple_scale( table, scale, delta, vertical );
+ return;
+ }
+
+ if ( ps_debug_no_horz_hints && !vertical )
+ {
+ ps_simple_scale( table, scale, delta, vertical );
+ return;
+ }
+#endif
+
+ hint = table->hints;
+ count = table->max_hints;
+ for ( ; count > 0; count--, hint++ )
+ psh2_hint_align( hint, globals, vertical );
+ }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** POINTS INTERPOLATION ROUTINES *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#define PSH2_ZONE_MIN -3200000
+#define PSH2_ZONE_MAX +3200000
+
+
+#define xxDEBUG_ZONES
+
+#ifdef DEBUG_ZONES
+
+#include <stdio.h>
+
+ static void
+ print_zone( PSH2_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
+ psh2_hint_table_setup_zones( PSH2_Hint_Table table,
+ FT_Fixed scale,
+ FT_Fixed delta )
+ {
+ FT_UInt count;
+ PSH2_Zone zone;
+ PSH2_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 = PSH2_ZONE_MIN;
+ zone->max = PSH2_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 = PSH2_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 = PSH2_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
+ psh2_hint_table_tune_coord( PSH2_Hint_Table table,
+ FT_Int coord )
+ {
+ PSH2_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;
+ }
+
+
+#if 0
+ /* tune a given outline with current interpolation zones */
+ /* the function only works in a single dimension.. */
+ static void
+ psh2_hint_table_tune_outline( PSH2_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;
+
+ psh2_hint_table_activate_mask( table, mask );
+ psh2_hint_table_optimize( table, globals, outline, vertical );
+ psh2_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 = psh2_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;
+ }
+ }
+ }
+#endif
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** HINTER GLYPH MANAGEMENT *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ static int
+ psh2_point_is_extremum( PSH2_Point point )
+ {
+ PSH2_Point before = point;
+ PSH2_Point after = point;
+ FT_Pos d_before;
+ FT_Pos d_after;
+
+ do
+ {
+ before = before->prev;
+ if ( before == point )
+ return 0;
+
+ d_before = before->org_u - point->org_u;
+ }
+ while ( d_before == 0 );
+
+ do
+ {
+ after = after->next;
+ if ( after == point )
+ return 0;
+
+ d_after = after->org_u - point->org_u;
+ }
+ while ( d_after == 0 );
+
+ return ( ( d_before > 0 && d_after > 0 ) ||
+ ( d_before < 0 && d_after < 0 ) );
+ }
+
+
+
+ static void
+ psh2_glyph_done( PSH2_Glyph glyph )
+ {
+ FT_Memory memory = glyph->memory;
+
+ psh2_hint_table_done( &glyph->hint_tables[1], memory );
+ psh2_hint_table_done( &glyph->hint_tables[0], memory );
+
+ FREE( glyph->points );
+ FREE( glyph->contours );
+
+ glyph->num_points = 0;
+ glyph->num_contours = 0;
+
+ glyph->memory = 0;
+ }
+
+
+ static int
+ psh2_compute_dir( FT_Pos dx, FT_Pos dy )
+ {
+ FT_Pos ax, ay;
+ int result = PSH2_DIR_NONE;
+
+ ax = ( dx >= 0 ) ? dx : -dx;
+ ay = ( dy >= 0 ) ? dy : -dy;
+
+ if ( ay*12 < ax )
+ {
+ /* |dy| <<< |dx| means a near-horizontal segment */
+ result = ( dx >= 0 ) ? PSH2_DIR_RIGHT : PSH2_DIR_LEFT;
+ }
+ else if ( ax*12 < ay )
+ {
+ /* |dx| <<< |dy| means a near-vertical segment */
+ result = ( dy >= 0 ) ? PSH2_DIR_UP : PSH2_DIR_DOWN;
+ }
+ return result;
+ }
+
+
+ static FT_Error
+ psh2_glyph_init( PSH2_Glyph glyph,
+ FT_Outline* outline,
+ PS_Hints ps_hints,
+ PSH_Globals globals )
+ {
+ FT_Error error;
+ FT_Memory memory;
+
+ /* clear all fields */
+ memset( glyph, 0, sizeof(*glyph) );
+
+ memory = globals->memory;
+
+ /* allocate and setup points + contours arrays */
+ if ( ALLOC_ARRAY( glyph->points, outline->n_points, PSH2_PointRec ) ||
+ ALLOC_ARRAY( glyph->contours, outline->n_contours, PSH2_ContourRec ) )
+ goto Exit;
+
+ glyph->num_points = outline->n_points;
+ glyph->num_contours = outline->n_contours;
+
+ {
+ FT_UInt first = 0, next, n;
+ PSH2_Point points = glyph->points;
+ PSH2_Contour contour = glyph->contours;
+
+ for ( n = 0; n < glyph->num_contours; n++ )
+ {
+ FT_Int count;
+ PSH2_Point point;
+
+ next = outline->contours[n] + 1;
+ count = next - first;
+
+ contour->start = points + first;
+ contour->count = (FT_UInt)count;
+
+ if ( count > 0 )
+ {
+ point = points + first;
+
+ point->prev = points + next - 1;
+ point->contour = contour;
+ for ( ; count > 1; count-- )
+ {
+ point[0].next = point + 1;
+ point[1].prev = point;
+ point++;
+ point->contour = contour;
+ }
+ point->next = points + first;
+ }
+
+ contour++;
+ first = next;
+ }
+ }
+
+ {
+ PSH2_Point points = glyph->points;
+ PSH2_Point point = points;
+ FT_Vector* vec = outline->points;
+ FT_UInt n;
+
+ for ( n = 0; n < glyph->num_points; n++, point++ )
+ {
+ FT_Int n_prev = point->prev - points;
+ FT_Int n_next = point->next - points;
+ FT_Pos dxi, dyi, dxo, dyo;
+
+ if ( !(outline->tags[n] & FT_Curve_Tag_On) )
+ point->flags = PSH2_POINT_OFF;
+
+ dxi = vec[n].x - vec[n_prev].x;
+ dyi = vec[n].y - vec[n_prev].y;
+
+ point->dir_in = psh2_compute_dir( dxi, dyi );
+
+ dxo = vec[n_next].x - vec[n].x;
+ dyo = vec[n_next].y - vec[n].y;
+
+ point->dir_out = psh2_compute_dir( dxo, dyo );
+
+ /* detect smooth points */
+ if ( point->flags & PSH2_POINT_OFF )
+ {
+ point->flags |= PSH2_POINT_SMOOTH;
+ }
+ else if ( point->dir_in != PSH2_DIR_NONE ||
+ point->dir_out != PSH2_DIR_NONE )
+ {
+ if ( point->dir_in == point->dir_out )
+ point->flags |= PSH2_POINT_SMOOTH;
+ }
+ else
+ {
+ FT_Angle angle_in, angle_out, diff;
+
+ angle_in = FT_Atan2( dxi, dyi );
+ angle_out = FT_Atan2( dxo, dyo );
+
+ diff = angle_in - angle_out;
+ if ( diff < 0 )
+ diff = -diff;
+
+ if ( diff > FT_ANGLE_PI )
+ diff = FT_ANGLE_2PI - diff;
+
+ if ( (diff < FT_ANGLE_PI/16) )
+ point->flags |= PSH2_POINT_SMOOTH;
+ }
+ }
+ }
+
+ glyph->memory = memory;
+ glyph->outline = outline;
+ glyph->globals = globals;
+
+ /* now deal with hints tables */
+ error = psh2_hint_table_init( &glyph->hint_tables [0],
+ &ps_hints->dimension[0].hints,
+ &ps_hints->dimension[0].masks,
+ &ps_hints->dimension[0].counters,
+ memory );
+ if (error) goto Exit;
+
+ error = psh2_hint_table_init( &glyph->hint_tables [1],
+ &ps_hints->dimension[1].hints,
+ &ps_hints->dimension[1].masks,
+ &ps_hints->dimension[1].counters,
+ memory );
+ if (error) goto Exit;
+
+ Exit:
+ return error;
+ }
+
+
+ /* load outline point coordinates into hinter glyph */
+ static void
+ psh2_glyph_load_points( PSH2_Glyph glyph,
+ FT_Bool vertical )
+ {
+ FT_Vector* vec = glyph->outline->points;
+ PSH2_Point point = glyph->points;
+ FT_UInt count = glyph->num_points;
+
+ for ( ; count > 0; count--, point++, vec++ )
+ {
+ point->flags &= PSH2_POINT_OFF | PSH2_POINT_SMOOTH;
+ point->hint = 0;
+ if (vertical)
+ point->org_u = vec->x;
+ else
+ point->org_u = vec->y;
+
+#ifdef DEBUG_HINTER
+ point->org_x = vec->x;
+ point->org_y = vec->y;
+#endif
+ }
+ }
+
+
+ /* save hinted point coordinates back to outline */
+ static void
+ psh2_glyph_save_points( PSH2_Glyph glyph,
+ FT_Bool vertical )
+ {
+ FT_UInt n;
+ PSH2_Point point = glyph->points;
+ FT_Vector* vec = glyph->outline->points;
+ char* tags = glyph->outline->tags;
+
+ for ( n = 0; n < glyph->num_points; n++ )
+ {
+ if (vertical)
+ vec[n].x = point->cur_u;
+ else
+ vec[n].y = point->cur_u;
+
+ if ( psh2_point_is_strong(point) )
+ tags[n] |= vertical ? 32 : 64;
+
+#ifdef DEBUG_HINTER
+ if (vertical)
+ {
+ point->cur_x = point->cur_u;
+ point->flags_x = point->flags;
+ }
+ else
+ {
+ point->cur_y = point->cur_u;
+ point->flags_y = point->flags;
+ }
+#endif
+ point++;
+ }
+ }
+
+
+ static void
+ psh2_hint_table_find_strong_point( PSH2_Hint_Table table,
+ PSH2_Point point,
+ FT_Int major_dir )
+ {
+ PSH2_Hint* sort = table->sort;
+ FT_UInt num_hints = table->num_hints;
+
+ for ( ; num_hints > 0; num_hints--, sort++ )
+ {
+ PSH2_Hint hint = sort[0];
+
+ if ( ABS(point->dir_in) == major_dir ||
+ ABS(point->dir_out) == major_dir )
+ {
+ FT_Pos d;
+
+ d = point->org_u - hint->org_pos;
+ if ( ABS(d) < 3 )
+ {
+ Is_Strong:
+ psh2_point_set_strong(point);
+ point->hint = hint;
+ break;
+ }
+
+ d -= hint->org_len;
+ if ( ABS(d) < 3 )
+ goto Is_Strong;
+ }
+
+#if 1
+ if ( point->org_u >= hint->org_pos &&
+ point->org_u <= hint->org_pos + hint->org_len &&
+ psh2_point_is_extremum( point ) )
+ {
+ /* attach to hint, but don't mark as strong */
+ point->hint = hint;
+ break;
+ }
+#endif
+ }
+ }
+
+
+
+ /* find strong points in a glyph */
+ static void
+ psh2_glyph_find_strong_points( PSH2_Glyph glyph,
+ FT_Bool vertical )
+ {
+ /* a point is strong if it is located on a stem */
+ /* edge and has an "in" or "out" tangent to the hint's direction */
+ {
+ PSH2_Hint_Table table = &glyph->hint_tables[vertical];
+ PS_Mask mask = table->hint_masks->masks;
+ FT_UInt num_masks = table->hint_masks->num_masks;
+ FT_UInt first = 0;
+ FT_Int major_dir = vertical ? PSH2_DIR_UP : PSH2_DIR_RIGHT;
+ FT_Int minor_dir = vertical ? PSH2_DIR_RIGHT : PSH2_DIR_UP;
+
+ /* process secondary hints to "selected" points */
+ if ( num_masks > 1 )
+ {
+ mask++;
+ for ( ; num_masks > 1; num_masks--, mask++ )
+ {
+ FT_UInt next;
+ FT_Int count;
+
+ next = mask->end_point;
+ count = next - first;
+ if ( count > 0 )
+ {
+ PSH2_Point point = glyph->points + first;
+
+ psh2_hint_table_activate_mask( table, mask );
+
+ for ( ; count > 0; count--, point++ )
+ psh2_hint_table_find_strong_point( table, point, major_dir );
+ }
+ first = next;
+ }
+ }
+
+ /* process primary hints for all points */
+ if ( num_masks == 1 )
+ {
+ FT_UInt count = glyph->num_points;
+ PSH2_Point point = glyph->points;
+
+ psh2_hint_table_activate_mask( table, table->hint_masks->masks );
+ for ( ; count > 0; count--, point++ )
+ {
+ if ( !psh2_point_is_strong(point) )
+ psh2_hint_table_find_strong_point( table, point, major_dir );
+ }
+ }
+
+ /* now, certain points may have been attached to hint and */
+ /* not marked as strong, update their flags then.. */
+ {
+ FT_UInt count = glyph->num_points;
+ PSH2_Point point = glyph->points;
+
+ for ( ; count > 0; count--, point++ )
+ if ( point->hint && !psh2_point_is_strong(point) )
+ psh2_point_set_strong(point);
+ }
+ }
+ }
+
+
+
+ /* interpolate strong points with the help of hinted coordinates */
+ static void
+ psh2_glyph_interpolate_strong_points( PSH2_Glyph glyph,
+ FT_Bool vertical )
+ {
+ PSH_Dimension dim = &glyph->globals->dimension[vertical];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+
+ {
+ FT_UInt count = glyph->num_points;
+ PSH2_Point point = glyph->points;
+
+ for ( ; count > 0; count--, point++ )
+ {
+ PSH2_Hint hint = point->hint;
+
+ if ( hint )
+ {
+ FT_Pos delta;
+
+ delta = point->org_u - hint->org_pos;
+
+ if ( delta <= 0 )
+ point->cur_u = hint->cur_pos + FT_MulFix( delta, scale );
+
+ else if ( delta >= hint->org_len )
+ point->cur_u = hint->cur_pos + hint->cur_len +
+ FT_MulFix( delta - hint->org_len, scale );
+
+ else if ( hint->org_len > 0 )
+ point->cur_u = hint->cur_pos +
+ FT_MulDiv( delta, hint->cur_len, hint->org_len );
+ else
+ point->cur_u = hint->cur_pos;
+
+ psh2_point_set_fitted(point);
+ }
+ }
+ }
+ }
+
+
+ static void
+ psh2_glyph_interpolate_normal_points( PSH2_Glyph glyph,
+ FT_Bool vertical )
+ {
+#if 1
+ PSH_Dimension dim = &glyph->globals->dimension[vertical];
+ FT_Fixed scale = dim->scale_mult;
+
+ /* first technique: a point is strong if it is a local extrema */
+ {
+ FT_UInt count = glyph->num_points;
+ PSH2_Point point = glyph->points;
+
+ for ( ; count > 0; count--, point++ )
+ {
+ if ( psh2_point_is_strong(point) )
+ continue;
+
+ /* sometimes, some local extremas are smooth points */
+ if ( psh2_point_is_smooth(point) )
+ {
+ if ( point->dir_in == PSH2_DIR_NONE ||
+ point->dir_in != point->dir_out )
+ continue;
+
+ if ( !psh2_point_is_extremum( point ) )
+ continue;
+
+ point->flags &= ~PSH2_POINT_SMOOTH;
+ }
+
+ /* find best enclosing point coordinates */
+ {
+ PSH2_Point before = 0;
+ PSH2_Point after = 0;
+
+ FT_Pos diff_before = -32000;
+ FT_Pos diff_after = 32000;
+ FT_Pos u = point->org_u;
+
+ FT_Int count2 = glyph->num_points;
+ PSH2_Point cur = glyph->points;
+
+ for ( ; count2 > 0; count2--, cur++ )
+ {
+ if ( psh2_point_is_strong(cur) )
+ {
+ FT_Pos diff = cur->org_u - u;;
+
+ if ( diff <= 0 )
+ {
+ if ( diff > diff_before )
+ {
+ diff_before = diff;
+ before = cur;
+ }
+ }
+ else if ( diff >= 0 )
+ {
+ if ( diff < diff_after )
+ {
+ diff_after = diff;
+ after = cur;
+ }
+ }
+ }
+ }
+
+ if ( !before )
+ {
+ if ( !after )
+ continue;
+
+ /* we're before the first strong point coordinate */
+ /* simply translate the point.. */
+ point->cur_u = after->cur_u +
+ FT_MulFix( point->org_u - after->org_u, scale );
+ }
+ else if ( !after )
+ {
+ /* we're after the last strong point coordinate */
+ /* simply translate the point.. */
+ point->cur_u = before->cur_u +
+ FT_MulFix( point->org_u - before->org_u, scale );
+ }
+ else
+ {
+ if ( diff_before == 0 )
+ point->cur_u = before->cur_u;
+
+ else if ( diff_after == 0 )
+ point->cur_u = after->cur_u;
+
+ else
+ point->cur_u = before->cur_u +
+ FT_MulDiv( u - before->org_u,
+ after->cur_u - before->cur_u,
+ after->org_u - before->org_u );
+ }
+
+ psh2_point_set_fitted(point);
+ }
+ }
+ }
+#endif
+ }
+
+
+
+ /* interpolate other points */
+ static void
+ psh2_glyph_interpolate_other_points( PSH2_Glyph glyph,
+ FT_Bool vertical )
+ {
+ PSH_Dimension dim = &glyph->globals->dimension[vertical];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+ PSH2_Contour contour = glyph->contours;
+ FT_UInt num_contours = glyph->num_contours;
+
+ for ( ; num_contours > 0; num_contours--, contour++ )
+ {
+ PSH2_Point start = contour->start;
+ PSH2_Point first, next, point;
+ FT_UInt fit_count;
+
+ /* count the number of strong points in this contour */
+ next = start + contour->count;
+ fit_count = 0;
+ first = 0;
+
+ for ( point = start; point < next; point++ )
+ if ( psh2_point_is_fitted(point) )
+ {
+ if ( !first )
+ first = point;
+
+ fit_count++;
+ }
+
+ /* if there is less than 2 fitted points in the contour, we'll */
+ /* simply scale and eventually translate the contour points */
+ if ( fit_count < 2 )
+ {
+ if ( fit_count == 1 )
+ delta = first->cur_u - FT_MulFix( first->org_u, scale );
+
+ for ( point = start; point < next; point++ )
+ if ( point != first )
+ point->cur_u = FT_MulFix( point->org_u, scale ) + delta;
+
+ goto Next_Contour;
+ }
+
+ /* there are more than 2 strong points in this contour, we'll */
+ /* need to interpolate weak points between them.. */
+ start = first;
+ do
+ {
+ point = first;
+
+ /* skip consecutive fitted points */
+ for (;;)
+ {
+ next = first->next;
+ if ( next == start )
+ goto Next_Contour;
+
+ if ( !psh2_point_is_fitted(next) )
+ break;
+
+ first = next;
+ }
+
+ /* find next fitted point after unfitted one */
+ for (;;)
+ {
+ next = next->next;
+ if ( psh2_point_is_fitted(next) )
+ break;
+ }
+
+ /* now interpolate between them */
+ {
+ FT_Pos org_a, org_ab, cur_a, cur_ab;
+ FT_Pos org_c, org_ac, cur_c;
+ FT_Fixed scale_ab;
+
+ if ( first->org_u <= next->org_u )
+ {
+ org_a = first->org_u;
+ cur_a = first->cur_u;
+ org_ab = next->org_u - org_a;
+ cur_ab = next->cur_u - cur_a;
+ }
+ else
+ {
+ org_a = next->org_u;
+ cur_a = next->cur_u;
+ org_ab = first->org_u - org_a;
+ cur_ab = first->cur_u - cur_a;
+ }
+
+ scale_ab = 0x10000L;
+ if ( org_ab > 0 )
+ scale_ab = FT_DivFix( cur_ab, org_ab );
+
+ point = first->next;
+ do
+ {
+ org_c = point->org_u;
+ org_ac = org_c - org_a;
+
+ if ( org_ac <= 0 )
+ {
+ /* on the left of the interpolation zone */
+ cur_c = cur_a + FT_MulFix( org_ac, scale );
+ }
+ else if ( org_ac >= org_ab )
+ {
+ /* on the right on the interpolation zone */
+ cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale );
+ }
+ else
+ {
+ /* within the interpolation zone */
+ cur_c = cur_a + FT_MulFix( org_ac, scale_ab );
+ }
+
+ point->cur_u = cur_c;
+
+ point = point->next;
+ }
+ while ( point != next );
+ }
+
+ /* keep going until all points in the contours have been processed */
+ first = next;
+ }
+ while ( first != start );
+
+ Next_Contour:
+ ;
+ }
+ }
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** HIGH-LEVEL INTERFACE *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ FT_Error
+ ps2_hints_apply( PS_Hints ps_hints,
+ FT_Outline* outline,
+ PSH_Globals globals )
+ {
+ PSH2_Glyph glyph;
+ PSH2_GlyphRec glyphrec;
+ FT_Error error;
+ FT_Memory memory;
+ FT_Int dimension;
+
+ memory = globals->memory;
+
+#ifdef DEBUG_HINTER
+ if ( ps2_debug_glyph )
+ {
+ psh2_glyph_done( ps2_debug_glyph );
+ FREE( ps2_debug_glyph );
+ }
+
+ if ( ALLOC( glyph, sizeof(*glyph) ) )
+ return error;
+
+ ps2_debug_glyph = glyph;
+#else
+ glyph = &glyphrec;
+#endif
+
+ error = psh2_glyph_init( glyph, outline, ps_hints, globals );
+ if (error) goto Exit;
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ /* load outline coordinates into glyph */
+ psh2_glyph_load_points( glyph, dimension );
+
+ /* compute aligned stem/hints positions */
+ psh2_hint_table_align_hints( &glyph->hint_tables[dimension],
+ glyph->globals,
+ dimension );
+
+ /* find strong points, align them, then interpolate others */
+ psh2_glyph_find_strong_points( glyph, dimension );
+ psh2_glyph_interpolate_strong_points( glyph, dimension );
+ psh2_glyph_interpolate_normal_points( glyph, dimension );
+ psh2_glyph_interpolate_other_points( glyph, dimension );
+
+ /* save hinted coordinates back to outline */
+ psh2_glyph_save_points( glyph, dimension );
+ }
+
+ Exit:
+#ifndef DEBUG_HINTER
+ psh2_glyph_done( glyph );
+#endif
+ return error;
+ }
diff --git a/src/pshinter/pshalgo2.h b/src/pshinter/pshalgo2.h
new file mode 100644
index 000000000..575712cc3
--- /dev/null
+++ b/src/pshinter/pshalgo2.h
@@ -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__ */
diff --git a/src/pshinter/pshfit.c b/src/pshinter/pshfit.c
deleted file mode 100644
index 1f9a70bf0..000000000
--- a/src/pshinter/pshfit.c
+++ /dev/null
@@ -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;
- } \ No newline at end of file
diff --git a/src/pshinter/pshfit.h b/src/pshinter/pshfit.h
deleted file mode 100644
index 22b85373e..000000000
--- a/src/pshinter/pshfit.h
+++ /dev/null
@@ -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__ */
diff --git a/src/pshinter/pshglob.c b/src/pshinter/pshglob.c
index 02c2e14a2..3dfdd2400 100644
--- a/src/pshinter/pshglob.c
+++ b/src/pshinter/pshglob.c
@@ -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;
diff --git a/src/pshinter/pshglob.h b/src/pshinter/pshglob.h
index 6fdda05b0..dae74b471 100644
--- a/src/pshinter/pshglob.h
+++ b/src/pshinter/pshglob.h
@@ -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
diff --git a/src/pshinter/pshinter.c b/src/pshinter/pshinter.c
index 592cda3f9..07c63303c 100644
--- a/src/pshinter/pshinter.c
+++ b/src/pshinter/pshinter.c
@@ -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 */
diff --git a/src/pshinter/pshmod.c b/src/pshinter/pshmod.c
index 2838400e7..65b360d07 100644
--- a/src/pshinter/pshmod.c
+++ b/src/pshinter/pshmod.c
@@ -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
diff --git a/src/pshinter/pshoptim.c b/src/pshinter/pshoptim.c
deleted file mode 100644
index eef2f846f..000000000
--- a/src/pshinter/pshoptim.c
+++ /dev/null
@@ -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;
- }
diff --git a/src/pshinter/pshoptim.h b/src/pshinter/pshoptim.h
deleted file mode 100644
index eb1605e87..000000000
--- a/src/pshinter/pshoptim.h
+++ /dev/null
@@ -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__ */
diff --git a/src/pshinter/pshrec.c b/src/pshinter/pshrec.c
index 5c63f68c2..8eb6810f7 100644
--- a/src/pshinter/pshrec.c
+++ b/src/pshinter/pshrec.c
@@ -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;
}
diff --git a/src/pshinter/pshrec.h b/src/pshinter/pshrec.h
index fbf7ddbb2..cdcf05777 100644
--- a/src/pshinter/pshrec.h
+++ b/src/pshinter/pshrec.h
@@ -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
/* */
diff --git a/src/smooth/ftgrays.c b/src/smooth/ftgrays.c
index a12a9ecfb..9de014176 100644
--- a/src/smooth/ftgrays.c
+++ b/src/smooth/ftgrays.c
@@ -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;
diff --git a/tests/Jamfile b/tests/Jamfile
index 74d3aef23..06625a93e 100644
--- a/tests/Jamfile
+++ b/tests/Jamfile
@@ -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" ;
diff --git a/tests/gview.c b/tests/gview.c
index b894aa207..35d236911 100644
--- a/tests/gview.c
+++ b/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,117 @@ 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 ( psh1_hint_is_ghost(hint) )
+ {
+ x1 --;
+ x2 = x1 + 2;
+ }
+ else
+ nv_pixmap_fill_rect( target, x2, 0, 1, target->height,
+ psh1_hint_is_ghost(hint)
+ ? GHOST_HINT_COLOR : STEM_HINT_COLOR );
+
+ nv_pixmap_fill_rect( target, x1, pshint_cpos, x2+1-x1, 1,
+ STEM_JOIN_COLOR );
+ }
+ else
+ {
+ if (!option_show_horz_hints)
+ return;
+
+ v.y = hint->cur_pos;
+ v.x = 0;
+ nv_vector_transform( &v, &size_transform );
+ x1 = (int)(v.y + 0.5);
+
+ v.y = hint->cur_pos + hint->cur_len;
+ v.x = 0;
+ nv_vector_transform( &v, &size_transform );
+ x2 = (int)(v.y + 0.5);
+
+ nv_pixmap_fill_rect( target, 0, x1, target->width, 1,
+ psh1_hint_is_ghost(hint)
+ ? GHOST_HINT_COLOR : STEM_HINT_COLOR );
+
+ if ( psh1_hint_is_ghost(hint) )
+ {
+ x1 --;
+ x2 = x1 + 2;
+ }
+ else
+ nv_pixmap_fill_rect( target, 0, x2, target->width, 1,
+ psh1_hint_is_ghost(hint)
+ ? GHOST_HINT_COLOR : STEM_HINT_COLOR );
+
+ nv_pixmap_fill_rect( target, pshint_cpos, x2, 1, x1+1-x2,
+ STEM_JOIN_COLOR );
+ }
+
+#if 0
+ printf( "[%7.3f %7.3f] %c\n", hint->cur_pos/64.0, (hint->cur_pos+hint->cur_len)/64.0, vertical ? 'v' : 'h' );
+#endif
+
+ pshint_cpos += 10;
+}
+
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** POSTSCRIPT HINTER ALGORITHM 2 ROUTINES *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#include <../src/pshinter/pshalgo2.h>
+
+static void
+draw_ps2_hint( PSH2_Hint hint, FT_Bool vertical )
+{
+ int x1, x2;
+ NV_Vector v;
+
+ if ( pshint_vertical != vertical )
+ {
+ if (vertical)
+ pshint_cpos = 40;
+ else
+ pshint_cpos = 10;
+
+ pshint_vertical = vertical;
+ }
+
+ if (vertical)
+ {
+ if ( !option_show_vert_hints )
+ return;
+
+ v.x = hint->cur_pos;
+ v.y = 0;
+ nv_vector_transform( &v, &size_transform );
+ x1 = (int)(v.x + 0.5);
+
+ v.x = hint->cur_pos + hint->cur_len;
+ v.y = 0;
+ nv_vector_transform( &v, &size_transform );
+ x2 = (int)(v.x + 0.5);
+
+ nv_pixmap_fill_rect( target, x1, 0, 1, target->height,
+ psh2_hint_is_ghost(hint)
? GHOST_HINT_COLOR : STEM_HINT_COLOR );
- if ( psh_hint_is_ghost(hint) )
+ if ( psh2_hint_is_ghost(hint) )
{
x1 --;
x2 = x1 + 2;
}
else
nv_pixmap_fill_rect( target, x2, 0, 1, target->height,
- psh_hint_is_ghost(hint)
+ psh2_hint_is_ghost(hint)
? GHOST_HINT_COLOR : STEM_HINT_COLOR );
nv_pixmap_fill_rect( target, x1, pshint_cpos, x2+1-x1, 1,
@@ -256,29 +487,98 @@ 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)
+ psh2_hint_is_ghost(hint)
? GHOST_HINT_COLOR : STEM_HINT_COLOR );
- if ( psh_hint_is_ghost(hint) )
+ if ( psh2_hint_is_ghost(hint) )
{
x1 --;
x2 = x1 + 2;
}
else
nv_pixmap_fill_rect( target, 0, x2, target->width, 1,
- psh_hint_is_ghost(hint)
+ 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 )
@@ -286,7 +586,9 @@ 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 );