ref: 0bdf608f3d79e7b45983b88a7733426c06eb5f49
parent: 26fb1bcd05afc1d61ad80cd7313aa5a88713e78b
author: Werner Lemberg <[email protected]>
date: Wed May 28 18:42:41 EDT 2003
* src/pshinter/pshalgo1.[ch], src/pshinter/pshalgo2.[ch]: Removed. * src/pshinter/pshalgo.h: Removed. * src/pshinter/pshalgo3.[ch]: Renamed to... * src/pshinter/pshalgo.[ch]: New files. s/PSH3/PSH/. s/psh3/psh/. s/ps3/ps/. * src/pshinter/pshrec.c, src/pshinter/pshinter.c: Updated. * src/pshinter/rules.mk, src/pshinter/Jamfile: Updated * src/pshinter/pshglob.[ch] (psh_dimension_snap_width): Commented out. * tests/gview.c: Remove code for pshalgo1 and pshalgo2. Updated.
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2003-05-29 Werner Lemberg <[email protected]>
+
+ * src/pshinter/pshalgo1.[ch], src/pshinter/pshalgo2.[ch]: Removed.
+ * src/pshinter/pshalgo.h: Removed.
+
+ * src/pshinter/pshalgo3.[ch]: Renamed to...
+ * src/pshinter/pshalgo.[ch]: New files.
+ s/PSH3/PSH/.
+ s/psh3/psh/.
+ s/ps3/ps/.
+
+ * src/pshinter/pshrec.c, src/pshinter/pshinter.c: Updated.
+ * src/pshinter/rules.mk, src/pshinter/Jamfile: Updated
+
+ * src/pshinter/pshglob.[ch] (psh_dimension_snap_width): Commented
+ out.
+
+ * tests/gview.c: Remove code for pshalgo1 and pshalgo2.
+ Updated.
+
2003-05-28 Martin Zinser <[email protected]>
* vms_make.com: Reworked support for shareable images on VMS. The
--- a/src/base/ftglyph.c
+++ b/src/base/ftglyph.c
@@ -254,13 +254,13 @@
/* copy it */
FT_MEM_COPY( target->points, source->points,
- source->n_points * sizeof ( FT_Vector ) );
+ source->n_points * sizeof ( FT_Vector ) );
FT_MEM_COPY( target->tags, source->tags,
- source->n_points * sizeof ( FT_Byte ) );
+ source->n_points * sizeof ( FT_Byte ) );
FT_MEM_COPY( target->contours, source->contours,
- source->n_contours * sizeof ( FT_Short ) );
+ source->n_contours * sizeof ( FT_Short ) );
/* copy all flags, except the `FT_OUTLINE_OWNER' one */
target->flags = source->flags | FT_OUTLINE_OWNER;
--- a/src/base/ftsynth.c
+++ b/src/base/ftsynth.c
@@ -82,14 +82,14 @@
/* we need to compute the `previous' and `next' point */
/* for these extrema. */
- cur = outline->points + n;
- prev = cur - 1;
- next = cur + 1;
+ cur = outline->points + n;
+ prev = cur - 1;
+ next = cur + 1;
first = 0;
for ( c = 0; c < outline->n_contours; c++ )
{
- last = outline->contours[c];
+ last = outline->contours[c];
if ( n == first )
prev = outline->points + last;
--- a/src/pshinter/Jamfile
+++ b/src/pshinter/Jamfile
@@ -8,7 +8,7 @@
if $(FT2_MULTI)
{
- _sources = pshrec pshglob pshalgo1 pshalgo2 pshalgo3 pshmod ;
+ _sources = pshrec pshglob pshalgo pshmod ;
}
else
{
--- /dev/null
+++ b/src/pshinter/pshalgo.c
@@ -1,0 +1,1997 @@
+/***************************************************************************/
+/* */
+/* pshalgo.c */
+/* */
+/* PostScript hinting algorithm 3 (body). */
+/* */
+/* Copyright 2001, 2002, 2003 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. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include "pshalgo.h"
+
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_pshalgo2
+
+
+#ifdef DEBUG_HINTER
+ PSH_Hint_Table ps_debug_hint_table = 0;
+ PSH_HintFunc ps_debug_hint_func = 0;
+ PSH_Glyph ps_debug_glyph = 0;
+#endif
+
+
+#define COMPUTE_INFLEXS /* compute inflection points to optimize "S" and others */
+#define STRONGER /* slightly increase the contrast of smooth hinting */
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** BASIC HINTS RECORDINGS *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* 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 )
+ {
+ FT_FREE( table->zones );
+ table->num_zones = 0;
+ table->zone = 0;
+
+ FT_FREE( table->sort );
+ FT_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 idx )
+ {
+ PSH_Hint hint = table->hints + idx;
+
+
+ if ( idx >= table->max_hints )
+ {
+ FT_ERROR(( "psh_hint_table_record: invalid hint index %d\n", idx ));
+ 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 are 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(( "psh_hint_table_record: too many sorted hints! BUG!\n" ));
+ }
+
+
+ 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 idx, limit;
+
+
+ limit = hint_mask->num_bits;
+
+ for ( idx = 0; idx < limit; idx++ )
+ {
+ if ( mask == 0 )
+ {
+ val = *cursor++;
+ mask = 0x80;
+ }
+
+ if ( val & mask )
+ psh_hint_table_record( table, idx );
+
+ 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 ( FT_NEW_ARRAY( table->sort, 2 * count ) ||
+ FT_NEW_ARRAY( table->hints, count ) ||
+ FT_NEW_ARRAY( table->zones, 2 * count + 1 ) )
+ goto Exit;
+
+ table->max_hints = count;
+ table->sort_global = table->sort + count;
+ table->num_hints = 0;
+ table->num_zones = 0;
+ table->zone = 0;
+
+ /* now, initialize 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(( "psh_hint_table_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 idx, limit, count;
+
+
+ limit = hint_mask->num_bits;
+ count = 0;
+
+ psh_hint_table_deactivate( table );
+
+ for ( idx = 0; idx < limit; idx++ )
+ {
+ if ( mask == 0 )
+ {
+ val = *cursor++;
+ mask = 0x80;
+ }
+
+ if ( val & mask )
+ {
+ PSH_Hint hint = &table->hints[idx];
+
+
+ if ( !psh_hint_is_active( hint ) )
+ {
+ FT_UInt count2;
+
+#if 0
+ PSH_Hint* sort = table->sort;
+ PSH_Hint hint2;
+
+
+ for ( count2 = count; count2 > 0; count2--, sort++ )
+ {
+ hint2 = sort[0];
+ if ( psh_hint_overlap( hint, hint2 ) )
+ FT_ERROR(( "psh_hint_table_activate_mask:"
+ " found overlapping hints\n" ))
+ }
+#else
+ count2 = 0;
+#endif
+
+ if ( count2 == 0 )
+ {
+ psh_hint_activate( hint );
+ if ( count < table->max_hints )
+ table->sort[count++] = hint;
+ else
+ FT_ERROR(( "psh_hint_tableactivate_mask:"
+ " too many active hints\n" ));
+ }
+ }
+ }
+
+ mask >>= 1;
+ }
+ table->num_hints = count;
+
+ /* now, sort the hints; they are 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[i2 + 1] = hint2;
+ sort[i2] = hint1;
+ }
+ }
+ }
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** HINTS GRID-FITTING AND OPTIMIZATION *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+#if 1
+ static FT_Pos
+ psh_dimension_quantize_len( PSH_Dimension dim,
+ FT_Pos len,
+ FT_Bool do_snapping )
+ {
+ if ( len <= 64 )
+ len = 64;
+ else
+ {
+ FT_Pos delta = len - dim->stdw.widths[0].cur;
+
+
+ if ( delta < 0 )
+ delta = -delta;
+
+ if ( delta < 40 )
+ {
+ len = dim->stdw.widths[0].cur;
+ if ( len < 48 )
+ len = 48;
+ }
+
+ if ( len < 3 * 64 )
+ {
+ delta = ( len & 63 );
+ len &= -64;
+
+ if ( delta < 10 )
+ len += delta;
+
+ else if ( delta < 32 )
+ len += 10;
+
+ else if ( delta < 54 )
+ len += 54;
+
+ else
+ len += delta;
+ }
+ else
+ len = ( len + 32 ) & -64;
+ }
+
+ if ( do_snapping )
+ len = ( len + 32 ) & -64;
+
+ return len;
+ }
+#endif /* 0 */
+
+
+#ifdef DEBUG_HINTER
+
+ static void
+ ps_simple_scale( PSH_Hint_Table table,
+ FT_Fixed scale,
+ FT_Fixed delta,
+ FT_Int dimension )
+ {
+ PSH_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 ( ps_debug_hint_func )
+ ps_debug_hint_func( hint, dimension );
+ }
+ }
+
+#endif /* DEBUG_HINTER */
+
+
+ static FT_Fixed
+ psh_hint_snap_stem_side_delta( FT_Fixed pos,
+ FT_Fixed len )
+ {
+ FT_Fixed delta1 = ( ( pos + 32 ) & -64 ) - pos;
+ FT_Fixed delta2 = ( ( pos + len + 32 ) & -64 ) - pos - len;
+
+
+ if ( ABS( delta1 ) <= ABS( delta2 ) )
+ return delta1;
+ else
+ return delta2;
+ }
+
+
+ static void
+ psh_hint_align( PSH_Hint hint,
+ PSH_Globals globals,
+ FT_Int dimension,
+ PSH_Glyph glyph )
+ {
+ PSH_Dimension dim = &globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+
+
+ if ( !psh_hint_is_fitted( hint ) )
+ {
+ FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
+ FT_Pos len = FT_MulFix( hint->org_len, scale );
+
+ FT_Int do_snapping;
+ FT_Pos fit_len;
+ PSH_AlignmentRec align;
+
+
+ /* ignore stem alignments when requested through the hint flags */
+ if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
+ ( dimension == 1 && !glyph->do_vert_hints ) )
+ {
+ hint->cur_pos = pos;
+ hint->cur_len = len;
+
+ psh_hint_set_fitted( hint );
+ return;
+ }
+
+ /* perform stem snapping when requested - this is necessary
+ * for monochrome and LCD hinting modes only
+ */
+ do_snapping = ( dimension == 0 && glyph->do_horz_snapping ) ||
+ ( dimension == 1 && glyph->do_vert_snapping );
+
+ hint->cur_len = fit_len = len;
+
+ /* check blue zones for horizontal stems */
+ align.align = PSH_BLUE_ALIGN_NONE;
+ align.align_bot = align.align_top = 0;
+
+ if ( dimension == 1 )
+ 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:
+ {
+ PSH_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 ( !psh_hint_is_fitted( parent ) )
+ psh_hint_align( parent, globals, dimension, glyph );
+
+ par_org_center = parent->org_pos + ( parent->org_len >> 1 );
+ par_cur_center = parent->cur_pos + ( parent->cur_len >> 1 );
+ cur_org_center = hint->org_pos + ( hint->org_len >> 1 );
+
+ cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
+ pos = par_cur_center + cur_delta - ( len >> 1 );
+ }
+
+ hint->cur_pos = pos;
+ hint->cur_len = fit_len;
+
+ /* Stem adjustment tries to snap stem widths to standard
+ * ones. This is important to prevent unpleasant rounding
+ * artefacts.
+ */
+ if ( glyph->do_stem_adjust )
+ {
+ if ( len <= 64 )
+ {
+ /* the stem is less than one pixel; we will center it
+ * around the nearest pixel center
+ */
+#if 1
+ pos = ( pos + ( len >> 1 ) ) & -64;
+#else
+ /* this seems to be a bug! */
+ pos = ( pos + ( ( len >> 1 ) & -64 ) );
+#endif
+ len = 64;
+ }
+ else
+ {
+ len = psh_dimension_quantize_len( dim, len, 0 );
+ }
+ }
+
+ /* now that we have a good hinted stem width, try to position */
+ /* the stem along a pixel grid integer coordinate */
+ hint->cur_pos = pos + psh_hint_snap_stem_side_delta( pos, len );
+ hint->cur_len = len;
+ }
+ }
+
+ if ( do_snapping )
+ {
+ pos = hint->cur_pos;
+ len = hint->cur_len;
+
+ if ( len < 64 )
+ len = 64;
+ else
+ len = ( len + 32 ) & -64;
+
+ switch ( align.align )
+ {
+ case PSH_BLUE_ALIGN_TOP:
+ hint->cur_pos = align.align_top - len;
+ hint->cur_len = len;
+ break;
+
+ case PSH_BLUE_ALIGN_BOT:
+ hint->cur_len = len;
+ break;
+
+ case PSH_BLUE_ALIGN_BOT | PSH_BLUE_ALIGN_TOP:
+ /* don't touch */
+ break;
+
+
+ default:
+ hint->cur_len = len;
+ if ( len & 64 )
+ pos = ( ( pos + ( len >> 1 ) ) & -64 ) + 32;
+ else
+ pos = ( pos + ( len >> 1 ) + 32 ) & -64;
+
+ hint->cur_pos = pos - ( len >> 1 );
+ hint->cur_len = len;
+ }
+ }
+
+ psh_hint_set_fitted( hint );
+
+#ifdef DEBUG_HINTER
+ if ( ps_debug_hint_func )
+ ps_debug_hint_func( hint, dimension );
+#endif
+ }
+ }
+
+
+#if 0 /* not used for now, experimental */
+
+ /*
+ * A variant to perform "light" hinting (i.e. FT_RENDER_MODE_LIGHT)
+ * of stems
+ */
+ static void
+ psh_hint_align_light( PSH_Hint hint,
+ PSH_Globals globals,
+ FT_Int dimension,
+ PSH_Glyph glyph )
+ {
+ PSH_Dimension dim = &globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+
+
+ if ( !psh_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_len;
+
+ PSH_AlignmentRec align;
+
+
+ /* ignore stem alignments when requested through the hint flags */
+ if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
+ ( dimension == 1 && !glyph->do_vert_hints ) )
+ {
+ hint->cur_pos = pos;
+ hint->cur_len = len;
+
+ psh_hint_set_fitted( hint );
+ return;
+ }
+
+ fit_len = len;
+
+ hint->cur_len = fit_len;
+
+ /* check blue zones for horizontal stems */
+ align.align = PSH_BLUE_ALIGN_NONE;
+ align.align_bot = align.align_top = 0;
+
+ if ( dimension == 1 )
+ 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:
+ {
+ PSH_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 ( !psh_hint_is_fitted( parent ) )
+ psh_hint_align_light( parent, globals, dimension, glyph );
+
+ 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 );
+ pos = par_cur_center + cur_delta - ( len >> 1 );
+ }
+
+ /* Stems less than one pixel wide are easy -- we want to
+ * make them as dark as possible, so they must fall within
+ * one pixel. If the stem is split between two pixels
+ * then snap the edge that is nearer to the pixel boundary
+ * to the pixel boundary.
+ */
+ if ( len <= 64 )
+ {
+ if ( ( pos + len + 63 ) / 64 != pos / 64 + 1 )
+ pos += psh_hint_snap_stem_side_delta ( pos, len );
+ }
+
+ /* Position stems other to minimize the amount of mid-grays.
+ * There are, in general, two positions that do this,
+ * illustrated as A) and B) below.
+ *
+ * + + + +
+ *
+ * A) |--------------------------------|
+ * B) |--------------------------------|
+ * C) |--------------------------------|
+ *
+ * Position A) (split the excess stem equally) should be better
+ * for stems of width N + f where f < 0.5.
+ *
+ * Position B) (split the deficiency equally) should be better
+ * for stems of width N + f where f > 0.5.
+ *
+ * It turns out though that minimizing the total number of lit
+ * pixels is also important, so position C), with one edge
+ * aligned with a pixel boundary is actually preferable
+ * to A). There are also more possibile positions for C) than
+ * for A) or B), so it involves less distortion of the overall
+ * character shape.
+ */
+ else /* len > 64 */
+ {
+ FT_Fixed frac_len = len & 63;
+ FT_Fixed center = pos + ( len >> 1 );
+ FT_Fixed delta_a, delta_b;
+
+
+ if ( ( len / 64 ) & 1 )
+ {
+ delta_a = ( center & -64 ) + 32 - center;
+ delta_b = ( ( center + 32 ) & - 64 ) - center;
+ }
+ else
+ {
+ delta_a = ( ( center + 32 ) & - 64 ) - center;
+ delta_b = ( center & -64 ) + 32 - center;
+ }
+
+ /* We choose between B) and C) above based on the amount
+ * of fractinal stem width; for small amounts, choose
+ * C) always, for large amounts, B) always, and inbetween,
+ * pick whichever one involves less stem movement.
+ */
+ if ( frac_len < 32 )
+ {
+ pos += psh_hint_snap_stem_side_delta ( pos, len );
+ }
+ else if ( frac_len < 48 )
+ {
+ FT_Fixed side_delta = psh_hint_snap_stem_side_delta ( pos,
+ len );
+
+
+ if ( ABS( side_delta ) < ABS( delta_b ) )
+ pos += side_delta;
+ else
+ pos += delta_b;
+ }
+ else
+ {
+ pos += delta_b;
+ }
+ }
+
+ hint->cur_pos = pos;
+ }
+ } /* switch */
+
+ psh_hint_set_fitted( hint );
+
+#ifdef DEBUG_HINTER
+ if ( ps_debug_hint_func )
+ ps_debug_hint_func( hint, dimension );
+#endif
+ }
+ }
+
+#endif /* 0 */
+
+
+ static void
+ psh_hint_table_align_hints( PSH_Hint_Table table,
+ PSH_Globals globals,
+ FT_Int dimension,
+ PSH_Glyph glyph )
+ {
+ PSH_Hint hint;
+ FT_UInt count;
+
+#ifdef DEBUG_HINTER
+
+ PSH_Dimension dim = &globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+
+
+ if ( ps_debug_no_vert_hints && dimension == 0 )
+ {
+ ps_simple_scale( table, scale, delta, dimension );
+ return;
+ }
+
+ if ( ps_debug_no_horz_hints && dimension == 1 )
+ {
+ ps_simple_scale( table, scale, delta, dimension );
+ return;
+ }
+
+#endif /* DEBUG_HINTER*/
+
+ hint = table->hints;
+ count = table->max_hints;
+
+ for ( ; count > 0; count--, hint++ )
+ psh_hint_align( hint, globals, dimension, glyph );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** POINTS INTERPOLATION ROUTINES *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+#define PSH_ZONE_MIN -3200000L
+#define PSH_ZONE_MAX +3200000L
+
+#define xxDEBUG_ZONES
+
+
+#ifdef DEBUG_ZONES
+
+#include <stdio.h>
+
+ static void
+ psh_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 psh_print_zone( x ) do { } while ( 0 )
+
+#endif /* DEBUG_ZONES */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** HINTER GLYPH MANAGEMENT *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+#ifdef COMPUTE_INFLEXS
+
+ /* compute all inflex points in a given glyph */
+ static void
+ psh_glyph_compute_inflections( PSH_Glyph glyph )
+ {
+ FT_UInt n;
+
+
+ for ( n = 0; n < glyph->num_contours; n++ )
+ {
+ PSH_Point first, start, end, before, after;
+ FT_Angle angle_in, angle_seg, angle_out;
+ FT_Angle diff_in, diff_out;
+ FT_Int finished = 0;
+
+
+ /* we need at least 4 points to create an inflection point */
+ if ( glyph->contours[n].count < 4 )
+ continue;
+
+ /* compute first segment in contour */
+ first = glyph->contours[n].start;
+
+ start = end = first;
+ do
+ {
+ end = end->next;
+ if ( end == first )
+ goto Skip;
+
+ } while ( PSH_POINT_EQUAL_ORG( end, first ) );
+
+ angle_seg = PSH_POINT_ANGLE( start, end );
+
+ /* extend the segment start whenever possible */
+ before = start;
+ do
+ {
+ do
+ {
+ start = before;
+ before = before->prev;
+ if ( before == first )
+ goto Skip;
+
+ } while ( PSH_POINT_EQUAL_ORG( before, start ) );
+
+ angle_in = PSH_POINT_ANGLE( before, start );
+
+ } while ( angle_in == angle_seg );
+
+ first = start;
+ diff_in = FT_Angle_Diff( angle_in, angle_seg );
+
+ /* now, process all segments in the contour */
+ do
+ {
+ /* first, extend current segment's end whenever possible */
+ after = end;
+ do
+ {
+ do
+ {
+ end = after;
+ after = after->next;
+ if ( after == first )
+ finished = 1;
+
+ } while ( PSH_POINT_EQUAL_ORG( end, after ) );
+
+ angle_out = PSH_POINT_ANGLE( end, after );
+
+ } while ( angle_out == angle_seg );
+
+ diff_out = FT_Angle_Diff( angle_seg, angle_out );
+
+ if ( ( diff_in ^ diff_out ) < 0 )
+ {
+ /* diff_in and diff_out have different signs, we have */
+ /* inflection points here... */
+
+ do
+ {
+ psh_point_set_inflex( start );
+ start = start->next;
+ }
+ while ( start != end );
+
+ psh_point_set_inflex( start );
+ }
+
+ start = end;
+ end = after;
+ angle_seg = angle_out;
+ diff_in = diff_out;
+
+ } while ( !finished );
+
+ Skip:
+ ;
+ }
+ }
+
+#endif /* COMPUTE_INFLEXS */
+
+
+ static void
+ psh_glyph_done( PSH_Glyph glyph )
+ {
+ FT_Memory memory = glyph->memory;
+
+
+ psh_hint_table_done( &glyph->hint_tables[1], memory );
+ psh_hint_table_done( &glyph->hint_tables[0], memory );
+
+ FT_FREE( glyph->points );
+ FT_FREE( glyph->contours );
+
+ glyph->num_points = 0;
+ glyph->num_contours = 0;
+
+ glyph->memory = 0;
+ }
+
+
+ static int
+ psh_compute_dir( FT_Pos dx,
+ FT_Pos dy )
+ {
+ FT_Pos ax, ay;
+ int result = PSH_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 ) ? PSH_DIR_RIGHT : PSH_DIR_LEFT;
+ }
+ else if ( ax * 12 < ay )
+ {
+ /* |dx| <<< |dy| means a near-vertical segment */
+ result = ( dy >= 0 ) ? PSH_DIR_UP : PSH_DIR_DOWN;
+ }
+
+ return result;
+ }
+
+
+ /* load outline point coordinates into hinter glyph */
+ static void
+ psh_glyph_load_points( PSH_Glyph glyph,
+ FT_Int dimension )
+ {
+ FT_Vector* vec = glyph->outline->points;
+ PSH_Point point = glyph->points;
+ FT_UInt count = glyph->num_points;
+
+
+ for ( ; count > 0; count--, point++, vec++ )
+ {
+ point->flags2 = 0;
+ point->hint = NULL;
+ if ( dimension == 0 )
+ {
+ point->org_u = vec->x;
+ point->org_v = vec->y;
+ }
+ else
+ {
+ point->org_u = vec->y;
+ point->org_v = vec->x;
+ }
+
+#ifdef DEBUG_HINTER
+ point->org_x = vec->x;
+ point->org_y = vec->y;
+#endif
+
+ }
+ }
+
+
+ /* save hinted point coordinates back to outline */
+ static void
+ psh_glyph_save_points( PSH_Glyph glyph,
+ FT_Int dimension )
+ {
+ FT_UInt n;
+ PSH_Point point = glyph->points;
+ FT_Vector* vec = glyph->outline->points;
+ char* tags = glyph->outline->tags;
+
+
+ for ( n = 0; n < glyph->num_points; n++ )
+ {
+ if ( dimension == 0 )
+ vec[n].x = point->cur_u;
+ else
+ vec[n].y = point->cur_u;
+
+ if ( psh_point_is_strong( point ) )
+ tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 );
+
+#ifdef DEBUG_HINTER
+
+ if ( dimension == 0 )
+ {
+ point->cur_x = point->cur_u;
+ point->flags_x = point->flags2 | point->flags;
+ }
+ else
+ {
+ point->cur_y = point->cur_u;
+ point->flags_y = point->flags2 | point->flags;
+ }
+
+#endif
+
+ point++;
+ }
+ }
+
+
+ static FT_Error
+ psh_glyph_init( PSH_Glyph glyph,
+ FT_Outline* outline,
+ PS_Hints ps_hints,
+ PSH_Globals globals )
+ {
+ FT_Error error;
+ FT_Memory memory;
+
+
+ /* clear all fields */
+ FT_MEM_ZERO( glyph, sizeof ( *glyph ) );
+
+ memory = globals->memory;
+
+ /* allocate and setup points + contours arrays */
+ if ( FT_NEW_ARRAY( glyph->points, outline->n_points ) ||
+ FT_NEW_ARRAY( glyph->contours, outline->n_contours ) )
+ goto Exit;
+
+ glyph->num_points = outline->n_points;
+ glyph->num_contours = outline->n_contours;
+
+ {
+ FT_UInt first = 0, next, n;
+ PSH_Point points = glyph->points;
+ PSH_Contour contour = glyph->contours;
+
+
+ for ( n = 0; n < glyph->num_contours; n++ )
+ {
+ FT_Int count;
+ PSH_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;
+ }
+ }
+
+ {
+ PSH_Point points = glyph->points;
+ PSH_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 = PSH_POINT_OFF;
+
+ dxi = vec[n].x - vec[n_prev].x;
+ dyi = vec[n].y - vec[n_prev].y;
+
+ point->dir_in = (FT_Char)psh_compute_dir( dxi, dyi );
+
+ dxo = vec[n_next].x - vec[n].x;
+ dyo = vec[n_next].y - vec[n].y;
+
+ point->dir_out = (FT_Char)psh_compute_dir( dxo, dyo );
+
+ /* detect smooth points */
+ if ( point->flags & PSH_POINT_OFF )
+ point->flags |= PSH_POINT_SMOOTH;
+ else if ( point->dir_in != PSH_DIR_NONE ||
+ point->dir_out != PSH_DIR_NONE )
+ {
+ if ( point->dir_in == point->dir_out )
+ point->flags |= PSH_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 |= PSH_POINT_SMOOTH;
+ }
+ }
+ }
+
+ glyph->memory = memory;
+ glyph->outline = outline;
+ glyph->globals = globals;
+
+#ifdef COMPUTE_INFLEXS
+ psh_glyph_load_points( glyph, 0 );
+ psh_glyph_compute_inflections( glyph );
+#endif /* COMPUTE_INFLEXS */
+
+ /* now deal with hints tables */
+ error = psh_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 = psh_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;
+ }
+
+
+ /* compute all extrema in a glyph for a given dimension */
+ static void
+ psh_glyph_compute_extrema( PSH_Glyph glyph )
+ {
+ FT_UInt n;
+
+
+ /* first of all, compute all local extrema */
+ for ( n = 0; n < glyph->num_contours; n++ )
+ {
+ PSH_Point first = glyph->contours[n].start;
+ PSH_Point point, before, after;
+
+
+ if ( glyph->contours[n].count == 0 )
+ continue;
+
+ point = first;
+ before = point;
+ after = point;
+
+ do
+ {
+ before = before->prev;
+ if ( before == first )
+ goto Skip;
+
+ } while ( before->org_u == point->org_u );
+
+ first = point = before->next;
+
+ for (;;)
+ {
+ after = point;
+ do
+ {
+ after = after->next;
+ if ( after == first )
+ goto Next;
+
+ } while ( after->org_u == point->org_u );
+
+ if ( before->org_u < point->org_u )
+ {
+ if ( after->org_u < point->org_u )
+ {
+ /* local maximum */
+ goto Extremum;
+ }
+ }
+ else /* before->org_u > point->org_u */
+ {
+ if ( after->org_u > point->org_u )
+ {
+ /* local minimum */
+ Extremum:
+ do
+ {
+ psh_point_set_extremum( point );
+ point = point->next;
+
+ } while ( point != after );
+ }
+ }
+
+ before = after->prev;
+ point = after;
+
+ } /* for */
+
+ Next:
+ ;
+ }
+
+ /* for each extrema, determine its direction along the */
+ /* orthogonal axis */
+ for ( n = 0; n < glyph->num_points; n++ )
+ {
+ PSH_Point point, before, after;
+
+
+ point = &glyph->points[n];
+ before = point;
+ after = point;
+
+ if ( psh_point_is_extremum( point ) )
+ {
+ do
+ {
+ before = before->prev;
+ if ( before == point )
+ goto Skip;
+
+ } while ( before->org_v == point->org_v );
+
+ do
+ {
+ after = after->next;
+ if ( after == point )
+ goto Skip;
+
+ } while ( after->org_v == point->org_v );
+ }
+
+ if ( before->org_v < point->org_v &&
+ after->org_v > point->org_v )
+ {
+ psh_point_set_positive( point );
+ }
+ else if ( before->org_v > point->org_v &&
+ after->org_v < point->org_v )
+ {
+ psh_point_set_negative( point );
+ }
+
+ Skip:
+ ;
+ }
+ }
+
+
+#define PSH_STRONG_THRESHOLD 30
+
+
+ /* major_dir is the direction for points on the bottom/left of the stem; */
+ /* Points on the top/right of the stem will have a direction of */
+ /* -major_dir. */
+
+ static void
+ psh_hint_table_find_strong_point( PSH_Hint_Table table,
+ PSH_Point point,
+ FT_Int major_dir )
+ {
+ PSH_Hint* sort = table->sort;
+ FT_UInt num_hints = table->num_hints;
+ FT_Int point_dir = 0;
+
+
+ if ( PSH_DIR_COMPARE( point->dir_in, major_dir ) )
+ point_dir = point->dir_in;
+
+ else if ( PSH_DIR_COMPARE( point->dir_out, major_dir ) )
+ point_dir = point->dir_out;
+
+ if ( point_dir )
+ {
+ FT_UInt flag;
+
+
+ for ( ; num_hints > 0; num_hints--, sort++ )
+ {
+ PSH_Hint hint = sort[0];
+ FT_Pos d;
+
+
+ if ( point_dir == major_dir )
+ {
+ flag = PSH_POINT_EDGE_MIN;
+ d = point->org_u - hint->org_pos;
+
+ if ( ABS( d ) < PSH_STRONG_THRESHOLD )
+ {
+ Is_Strong:
+ psh_point_set_strong( point );
+ point->flags2 |= flag;
+ point->hint = hint;
+ break;
+ }
+ }
+ else if ( point_dir == -major_dir )
+ {
+ flag = PSH_POINT_EDGE_MAX;
+ d = point->org_u - hint->org_pos - hint->org_len;
+
+ if ( ABS( d ) < PSH_STRONG_THRESHOLD )
+ goto Is_Strong;
+ }
+ }
+ }
+
+#if 1
+ else if ( psh_point_is_extremum( point ) )
+ {
+ /* treat extrema as special cases for stem edge alignment */
+ FT_UInt min_flag, max_flag;
+
+
+ if ( major_dir == PSH_DIR_HORIZONTAL )
+ {
+ min_flag = PSH_POINT_POSITIVE;
+ max_flag = PSH_POINT_NEGATIVE;
+ }
+ else
+ {
+ min_flag = PSH_POINT_NEGATIVE;
+ max_flag = PSH_POINT_POSITIVE;
+ }
+
+ for ( ; num_hints > 0; num_hints--, sort++ )
+ {
+ PSH_Hint hint = sort[0];
+ FT_Pos d, flag;
+
+
+ if ( point->flags2 & min_flag )
+ {
+ flag = PSH_POINT_EDGE_MIN;
+ d = point->org_u - hint->org_pos;
+
+ if ( ABS( d ) < PSH_STRONG_THRESHOLD )
+ {
+ Is_Strong2:
+ point->flags2 |= flag;
+ point->hint = hint;
+ psh_point_set_strong( point );
+ break;
+ }
+ }
+ else if ( point->flags2 & max_flag )
+ {
+ flag = PSH_POINT_EDGE_MAX;
+ d = point->org_u - hint->org_pos - hint->org_len;
+
+ if ( ABS( d ) < PSH_STRONG_THRESHOLD )
+ goto Is_Strong2;
+ }
+
+ if ( point->org_u >= hint->org_pos &&
+ point->org_u <= hint->org_pos + hint->org_len )
+ {
+ point->hint = hint;
+ }
+ }
+ }
+
+#endif /* 1 */
+ }
+
+
+ /* find strong points in a glyph */
+ static void
+ psh_glyph_find_strong_points( PSH_Glyph glyph,
+ FT_Int dimension )
+ {
+ /* a point is strong if it is located on a stem */
+ /* edge and has an "in" or "out" tangent to the hint's direction */
+ {
+ PSH_Hint_Table table = &glyph->hint_tables[dimension];
+ PS_Mask mask = table->hint_masks->masks;
+ FT_UInt num_masks = table->hint_masks->num_masks;
+ FT_UInt first = 0;
+ FT_Int major_dir = dimension == 0 ? PSH_DIR_VERTICAL
+ : PSH_DIR_HORIZONTAL;
+
+
+ /* process secondary hints to "selected" points */
+ if ( num_masks > 1 && glyph->num_points > 0 )
+ {
+ first = mask->end_point;
+ mask++;
+ for ( ; num_masks > 1; num_masks--, mask++ )
+ {
+ FT_UInt next;
+ FT_Int count;
+
+
+ next = mask->end_point;
+ count = next - first;
+ if ( count > 0 )
+ {
+ PSH_Point point = glyph->points + first;
+
+
+ psh_hint_table_activate_mask( table, mask );
+
+ for ( ; count > 0; count--, point++ )
+ psh_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;
+ PSH_Point point = glyph->points;
+
+
+ psh_hint_table_activate_mask( table, table->hint_masks->masks );
+ for ( ; count > 0; count--, point++ )
+ {
+ if ( !psh_point_is_strong( point ) )
+ psh_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;
+ PSH_Point point = glyph->points;
+
+
+ for ( ; count > 0; count--, point++ )
+ if ( point->hint && !psh_point_is_strong( point ) )
+ psh_point_set_strong( point );
+ }
+ }
+ }
+
+
+ /* interpolate strong points with the help of hinted coordinates */
+ static void
+ psh_glyph_interpolate_strong_points( PSH_Glyph glyph,
+ FT_Int dimension )
+ {
+ PSH_Dimension dim = &glyph->globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+
+
+ {
+ FT_UInt count = glyph->num_points;
+ PSH_Point point = glyph->points;
+
+
+ for ( ; count > 0; count--, point++ )
+ {
+ PSH_Hint hint = point->hint;
+
+
+ if ( hint )
+ {
+ FT_Pos delta;
+
+
+ if ( psh_point_is_edge_min( point ) )
+ {
+ point->cur_u = hint->cur_pos;
+ }
+ else if ( psh_point_is_edge_max( point ) )
+ {
+ point->cur_u = hint->cur_pos + hint->cur_len;
+ }
+ else
+ {
+ 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;
+ }
+ psh_point_set_fitted( point );
+ }
+ }
+ }
+ }
+
+
+ static void
+ psh_glyph_interpolate_normal_points( PSH_Glyph glyph,
+ FT_Int dimension )
+ {
+
+#if 1
+
+ PSH_Dimension dim = &glyph->globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+
+
+ /* first technique: a point is strong if it is a local extrema */
+ {
+ FT_UInt count = glyph->num_points;
+ PSH_Point point = glyph->points;
+
+
+ for ( ; count > 0; count--, point++ )
+ {
+ if ( psh_point_is_strong( point ) )
+ continue;
+
+ /* sometimes, some local extremas are smooth points */
+ if ( psh_point_is_smooth( point ) )
+ {
+ if ( point->dir_in == PSH_DIR_NONE ||
+ point->dir_in != point->dir_out )
+ continue;
+
+ if ( !psh_point_is_extremum( point ) &&
+ !psh_point_is_inflex( point ) )
+ continue;
+
+ point->flags &= ~PSH_POINT_SMOOTH;
+ }
+
+ /* find best enclosing point coordinates */
+ {
+ PSH_Point before = 0;
+ PSH_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;
+ PSH_Point cur = glyph->points;
+
+
+ for ( ; count2 > 0; count2--, cur++ )
+ {
+ if ( psh_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 are 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 are 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 );
+ }
+
+ psh_point_set_fitted( point );
+ }
+ }
+ }
+
+#endif /* 1 */
+
+ }
+
+
+ /* interpolate other points */
+ static void
+ psh_glyph_interpolate_other_points( PSH_Glyph glyph,
+ FT_Int dimension )
+ {
+ PSH_Dimension dim = &glyph->globals->dimension[dimension];
+ FT_Fixed scale = dim->scale_mult;
+ FT_Fixed delta = dim->scale_delta;
+ PSH_Contour contour = glyph->contours;
+ FT_UInt num_contours = glyph->num_contours;
+
+
+ for ( ; num_contours > 0; num_contours--, contour++ )
+ {
+ PSH_Point start = contour->start;
+ PSH_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 ( psh_point_is_fitted( point ) )
+ {
+ if ( !first )
+ first = point;
+
+ fit_count++;
+ }
+
+ /* if there are less than 2 fitted points in the contour, we */
+ /* 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 */
+ /* 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 ( !psh_point_is_fitted( next ) )
+ break;
+
+ first = next;
+ }
+
+ /* find next fitted point after unfitted one */
+ for (;;)
+ {
+ next = next->next;
+ if ( psh_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
+ ps_hints_apply( PS_Hints ps_hints,
+ FT_Outline* outline,
+ PSH_Globals globals,
+ FT_Render_Mode hint_mode )
+ {
+ PSH_GlyphRec glyphrec;
+ PSH_Glyph glyph = &glyphrec;
+ FT_Error error;
+#ifdef DEBUG_HINTER
+ FT_Memory memory;
+#endif
+ FT_Int dimension;
+
+
+ /* something to do? */
+ if ( outline->n_points == 0 || outline->n_contours == 0 )
+ return FT_Err_Ok;
+
+#ifdef DEBUG_HINTER
+
+ memory = globals->memory;
+
+ if ( ps_debug_glyph )
+ {
+ psh_glyph_done( ps_debug_glyph );
+ FT_FREE( ps_debug_glyph );
+ }
+
+ if ( FT_NEW( glyph ) )
+ return error;
+
+ ps_debug_glyph = glyph;
+
+#endif /* DEBUG_HINTER */
+
+ error = psh_glyph_init( glyph, outline, ps_hints, globals );
+ if ( error )
+ goto Exit;
+
+ /* try to optimize the y_scale so that the top of non-capital letters
+ * is aligned on a pixel boundary whenever possible
+ */
+ {
+ PSH_Dimension dim_x = &glyph->globals->dimension[0];
+ PSH_Dimension dim_y = &glyph->globals->dimension[1];
+
+ FT_Fixed x_scale = dim_x->scale_mult;
+ FT_Fixed y_scale = dim_y->scale_mult;
+
+ FT_Fixed scaled;
+ FT_Fixed fitted;
+
+
+ scaled = FT_MulFix( globals->blues.normal_top.zones->org_ref, y_scale );
+ fitted = ( scaled + 32 ) & -64;
+
+ if (scaled != fitted ) {
+ y_scale = FT_MulDiv( y_scale, fitted, scaled );
+
+ if ( fitted < scaled )
+ x_scale -= x_scale / 50;
+
+ psh_globals_set_scale( glyph->globals, x_scale, y_scale, 0, 0 );
+ }
+ }
+
+ glyph->do_horz_hints = 1;
+ glyph->do_vert_hints = 1;
+
+ glyph->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
+ hint_mode == FT_RENDER_MODE_LCD );
+
+ glyph->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
+ hint_mode == FT_RENDER_MODE_LCD_V );
+
+ glyph->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT );
+
+ for ( dimension = 0; dimension < 2; dimension++ )
+ {
+ /* load outline coordinates into glyph */
+ psh_glyph_load_points( glyph, dimension );
+
+ /* compute local extrema */
+ psh_glyph_compute_extrema( glyph );
+
+ /* compute aligned stem/hints positions */
+ psh_hint_table_align_hints( &glyph->hint_tables[dimension],
+ glyph->globals,
+ dimension,
+ glyph );
+
+ /* find strong points, align them, then interpolate others */
+ psh_glyph_find_strong_points( glyph, dimension );
+ psh_glyph_interpolate_strong_points( glyph, dimension );
+ psh_glyph_interpolate_normal_points( glyph, dimension );
+ psh_glyph_interpolate_other_points( glyph, dimension );
+
+ /* save hinted coordinates back to outline */
+ psh_glyph_save_points( glyph, dimension );
+ }
+
+ Exit:
+
+#ifndef DEBUG_HINTER
+ psh_glyph_done( glyph );
+#endif
+
+ return error;
+ }
+
+
+/* END */
--- a/src/pshinter/pshalgo.h
+++ b/src/pshinter/pshalgo.h
@@ -2,13 +2,13 @@
/* */
/* pshalgo.h */
/* */
-/* This header file defines the used hinting algorithm. */
+/* PostScript hinting algorithm (specification). */
/* */
-/* Copyright 2001 by */
+/* Copyright 2001, 2002, 2003 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 */
+/* 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. */
@@ -19,33 +19,235 @@
#ifndef __PSHALGO_H__
#define __PSHALGO_H__
+
+#include "pshrec.h"
+#include "pshglob.h"
+#include FT_TRIGONOMETRY_H
+
+
FT_BEGIN_HEADER
-/* define to choose hinting algorithm */
-#define PSH_ALGORITHM_3
-#if defined(PSH_ALGORITHM_1)
+ /* handle to Hint structure */
+ typedef struct PSH_HintRec_* PSH_Hint;
-# include "pshalgo1.h"
-# define PS_HINTS_APPLY_FUNC ps1_hints_apply
+ /* hint bit-flags */
+ typedef enum
+ {
+ PSH_HINT_GHOST = PS_HINT_FLAG_GHOST,
+ PSH_HINT_BOTTOM = PS_HINT_FLAG_BOTTOM,
+ PSH_HINT_ACTIVE = 4,
+ PSH_HINT_FITTED = 8
-#elif defined(PSH_ALGORITHM_2)
+ } PSH_Hint_Flags;
-# include "pshalgo2.h"
-# define PS_HINTS_APPLY_FUNC ps2_hints_apply
-#elif defined(PSH_ALGORITHM_3)
+#define psh_hint_is_active( x ) ( ( (x)->flags & PSH_HINT_ACTIVE ) != 0 )
+#define psh_hint_is_ghost( x ) ( ( (x)->flags & PSH_HINT_GHOST ) != 0 )
+#define psh_hint_is_fitted( x ) ( ( (x)->flags & PSH_HINT_FITTED ) != 0 )
-# include "pshalgo3.h"
-# define PS_HINTS_APPLY_FUNC ps3_hints_apply
+#define psh_hint_activate( x ) (x)->flags |= PSH_HINT_ACTIVE
+#define psh_hint_deactivate( x ) (x)->flags &= ~PSH_HINT_ACTIVE
+#define psh_hint_set_fitted( x ) (x)->flags |= PSH_HINT_FITTED
-#else
+ /* hint structure */
+ 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;
-# error "invalid Postscript Hinter algorithm selection"
+ } 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_ZoneRec* zones;
+ PSH_Zone zone;
+ PS_Mask_Table hint_masks;
+ PS_Mask_Table counter_masks;
+
+ } PSH_Hint_TableRec, *PSH_Hint_Table;
+
+
+ typedef struct PSH_PointRec_* PSH_Point;
+ typedef struct PSH_ContourRec_* PSH_Contour;
+
+ enum
+ {
+ PSH_DIR_NONE = 4,
+ PSH_DIR_UP = -1,
+ PSH_DIR_DOWN = 1,
+ PSH_DIR_LEFT = -2,
+ PSH_DIR_RIGHT = 2
+ };
+
+#define PSH_DIR_HORIZONTAL 2
+#define PSH_DIR_VERTICAL 1
+
+#define PSH_DIR_COMPARE( d1, d2 ) ( (d1) == (d2) || (d1) == -(d2) )
+#define PSH_DIR_IS_HORIZONTAL( d ) PSH_DIR_COMPARE( d, PSH_DIR_HORIZONTAL )
+#define PSH_DIR_IS_VERTICAL( d ) PSH_DIR_COMPARE( d, PSH_DIR_VERTICAL )
+
+
+ /* the following bit-flags are computed once by the glyph */
+ /* analyzer, for both dimensions */
+ enum
+ {
+ PSH_POINT_OFF = 1, /* point is off the curve */
+ PSH_POINT_SMOOTH = 2, /* point is smooth */
+ PSH_POINT_INFLEX = 4 /* point is inflection */
+ };
+
+#define psh_point_is_smooth( p ) ( (p)->flags & PSH_POINT_SMOOTH )
+#define psh_point_is_off( p ) ( (p)->flags & PSH_POINT_OFF )
+#define psh_point_is_inflex( p ) ( (p)->flags & PSH_POINT_INFLEX )
+
+#define psh_point_set_smooth( p ) (p)->flags |= PSH_POINT_SMOOTH
+#define psh_point_set_off( p ) (p)->flags |= PSH_POINT_OFF
+#define psh_point_set_inflex( p ) (p)->flags |= PSH_POINT_INFLEX
+
+ /* the following bit-flags are re-computed for each dimension */
+ enum
+ {
+ PSH_POINT_STRONG = 16, /* point is strong */
+ PSH_POINT_FITTED = 32, /* point is already fitted */
+ PSH_POINT_EXTREMUM = 64, /* point is local extremum */
+ PSH_POINT_POSITIVE = 128, /* extremum has positive contour flow */
+ PSH_POINT_NEGATIVE = 256, /* extremum has negative contour flow */
+ PSH_POINT_EDGE_MIN = 512, /* point is aligned to left/bottom stem edge */
+ PSH_POINT_EDGE_MAX = 1024 /* point is aligned to top/right stem edge */
+ };
+
+#define psh_point_is_strong( p ) ( (p)->flags2 & PSH_POINT_STRONG )
+#define psh_point_is_fitted( p ) ( (p)->flags2 & PSH_POINT_FITTED )
+#define psh_point_is_extremum( p ) ( (p)->flags2 & PSH_POINT_EXTREMUM )
+#define psh_point_is_positive( p ) ( (p)->flags2 & PSH_POINT_POSITIVE )
+#define psh_point_is_negative( p ) ( (p)->flags2 & PSH_POINT_NEGATIVE )
+#define psh_point_is_edge_min( p ) ( (p)->flags2 & PSH_POINT_EDGE_MIN )
+#define psh_point_is_edge_max( p ) ( (p)->flags2 & PSH_POINT_EDGE_MAX )
+
+#define psh_point_set_strong( p ) (p)->flags2 |= PSH_POINT_STRONG
+#define psh_point_set_fitted( p ) (p)->flags2 |= PSH_POINT_FITTED
+#define psh_point_set_extremum( p ) (p)->flags2 |= PSH_POINT_EXTREMUM
+#define psh_point_set_positive( p ) (p)->flags2 |= PSH_POINT_POSITIVE
+#define psh_point_set_negative( p ) (p)->flags2 |= PSH_POINT_NEGATIVE
+#define psh_point_set_edge_min( p ) (p)->flags2 |= PSH_POINT_EDGE_MIN
+#define psh_point_set_edge_max( p ) (p)->flags2 |= PSH_POINT_EDGE_MAX
+
+
+ typedef struct PSH_PointRec_
+ {
+ PSH_Point prev;
+ PSH_Point next;
+ PSH_Contour contour;
+ FT_UInt flags;
+ FT_UInt flags2;
+ FT_Char dir_in;
+ FT_Char dir_out;
+ FT_Angle angle_in;
+ FT_Angle angle_out;
+ PSH_Hint hint;
+ FT_Pos org_u;
+ FT_Pos org_v;
+ 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
+ } PSH_PointRec;
+
+
+#define PSH_POINT_EQUAL_ORG( a, b ) ( (a)->org_u == (b)->org_u && \
+ (a)->org_v == (b)->org_v )
+
+#define PSH_POINT_ANGLE( a, b ) FT_Atan2( (b)->org_u - (a)->org_u, \
+ (b)->org_v - (a)->org_v )
+
+ typedef struct PSH_ContourRec_
+ {
+ PSH_Point start;
+ FT_UInt count;
+
+ } PSH_ContourRec;
+
+
+ typedef struct PSH_GlyphRec_
+ {
+ FT_UInt num_points;
+ FT_UInt num_contours;
+
+ PSH_Point points;
+ PSH_Contour contours;
+
+ FT_Memory memory;
+ FT_Outline* outline;
+ PSH_Globals globals;
+ PSH_Hint_TableRec hint_tables[2];
+
+ FT_Bool vertical;
+ FT_Int major_dir;
+ FT_Int minor_dir;
+
+ FT_Bool do_horz_hints;
+ FT_Bool do_vert_hints;
+ FT_Bool do_horz_snapping;
+ FT_Bool do_vert_snapping;
+ FT_Bool do_stem_adjust;
+
+ } PSH_GlyphRec, *PSH_Glyph;
+
+
+#ifdef DEBUG_HINTER
+ 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;
+
+ extern PSH_Glyph ps_debug_glyph;
+#endif
+
+
+ extern FT_Error
+ ps_hints_apply( PS_Hints ps_hints,
+ FT_Outline* outline,
+ PSH_Globals globals,
+ FT_Render_Mode hint_mode );
+
+
FT_END_HEADER
+
#endif /* __PSHALGO_H__ */
--- a/src/pshinter/pshalgo1.c
+++ /dev/null
@@ -1,785 +1,0 @@
-/***************************************************************************/
-/* */
-/* pshalgo1.c */
-/* */
-/* PostScript hinting algorithm 1 (body). */
-/* */
-/* Copyright 2001, 2002 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. */
-/* */
-/***************************************************************************/
-
-
-#include <ft2build.h>
-#include FT_INTERNAL_OBJECTS_H
-#include FT_INTERNAL_DEBUG_H
-#include "pshalgo1.h"
-
-#undef FT_COMPONENT
-#define FT_COMPONENT trace_pshalgo1
-
-#ifdef DEBUG_HINTER
- PSH1_Hint_Table ps1_debug_hint_table = 0;
- 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 )
- {
- FT_FREE( table->zones );
- table->num_zones = 0;
- table->zone = 0;
-
- FT_FREE( table->sort );
- FT_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 idx )
- {
- PSH1_Hint hint = table->hints + idx;
-
-
- if ( idx >= table->max_hints )
- {
- FT_ERROR(( "%s.activate: invalid hint index %d\n", idx ));
- 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 are 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 idx, 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 ( idx = 0; idx < limit; idx++ )
- {
- if ( mask == 0 )
- {
- val = *cursor++;
- mask = 0x80;
- }
-
- if ( val & mask )
- psh1_hint_table_record( table, idx );
-
- 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 ( FT_NEW_ARRAY( table->sort, 2 * count ) ||
- FT_NEW_ARRAY( table->hints, count ) ||
- FT_NEW_ARRAY( table->zones, 2 * count + 1 ) )
- goto Exit;
-
- table->max_hints = count;
- table->sort_global = table->sort + count;
- table->num_hints = 0;
- table->num_zones = 0;
- table->zone = 0;
-
- /* now, initialize 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 idx, limit, count;
-
-
- limit = hint_mask->num_bits;
- count = 0;
-
- psh1_hint_table_deactivate( table );
-
- for ( idx = 0; idx < limit; idx++ )
- {
- if ( mask == 0 )
- {
- val = *cursor++;
- mask = 0x80;
- }
-
- if ( val & mask )
- {
- PSH1_Hint hint = &table->hints[idx];
-
-
- 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 are 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[i2 + 1] = hint2;
- sort[i2] = hint1;
- }
- }
- }
- }
-
-
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** HINTS GRID-FITTING AND OPTIMIZATION *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
-
-#ifdef DEBUG_HINTER
- void
- ps_simple_scale( PSH1_Hint_Table table,
- FT_Fixed scale,
- FT_Fixed delta,
- FT_Int 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_Int vertical )
- {
- PSH_Dimension dim = &globals->dimension[vertical];
- FT_Fixed scale = dim->scale_mult;
- FT_Fixed delta = dim->scale_delta;
-
- FT_UNUSED( outline );
-
-
-#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 = PSH_BLUE_ALIGN_NONE;
- align.align_bot = align.align_top = 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
- psh1_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 psh1_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;
-
- psh1_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 );
-
- psh1_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 );
-
- psh1_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 );
-
- psh1_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_Int 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,
- FT_Render_Mode hint_mode )
- {
- PSH1_Hint_TableRec hints;
- FT_Error error = 0;
- FT_Int dimension;
-
-
- FT_UNUSED( hint_mode );
-
- for ( dimension = 1; dimension >= 0; dimension-- )
- {
- PS_Dimension dim = &ps_hints->dimension[dimension];
-
-
- /* initialize hints table */
- FT_MEM_ZERO( &hints, 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;
- }
-
-
-/* END */
--- a/src/pshinter/pshalgo1.h
+++ /dev/null
@@ -1,110 +1,0 @@
-/***************************************************************************/
-/* */
-/* pshalgo1.h */
-/* */
-/* PostScript hinting algorithm 1 (specification). */
-/* */
-/* 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 __PSHALGO1_H__
-#define __PSHALGO1_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,
- FT_Render_Mode hint_mode );
-
-
-#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 /* __PSHALGO1_H__ */
-
-
-/* END */
--- a/src/pshinter/pshalgo2.c
+++ /dev/null
@@ -1,1557 +1,0 @@
-/***************************************************************************/
-/* */
-/* pshalgo2.c */
-/* */
-/* PostScript hinting algorithm 2 (body). */
-/* */
-/* Copyright 2001, 2002 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. */
-/* */
-/***************************************************************************/
-
-
-#include <ft2build.h>
-#include FT_INTERNAL_OBJECTS_H
-#include FT_INTERNAL_DEBUG_H
-#include "pshalgo2.h"
-
-#undef FT_COMPONENT
-#define FT_COMPONENT trace_pshalgo2
-
-#ifdef DEBUG_HINTER
- PSH2_Hint_Table ps2_debug_hint_table = 0;
- PSH2_HintFunc ps2_debug_hint_func = 0;
- 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 )
- {
- FT_FREE( table->zones );
- table->num_zones = 0;
- table->zone = 0;
-
- FT_FREE( table->sort );
- FT_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 idx )
- {
- PSH2_Hint hint = table->hints + idx;
-
-
- if ( idx >= table->max_hints )
- {
- FT_ERROR(( "%s.activate: invalid hint index %d\n", idx ));
- 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 are 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 idx, limit;
-
-
- limit = hint_mask->num_bits;
-
- for ( idx = 0; idx < limit; idx++ )
- {
- if ( mask == 0 )
- {
- val = *cursor++;
- mask = 0x80;
- }
-
- if ( val & mask )
- psh2_hint_table_record( table, idx );
-
- 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 ( FT_NEW_ARRAY( table->sort, 2 * count ) ||
- FT_NEW_ARRAY( table->hints, count ) ||
- FT_NEW_ARRAY( table->zones, 2 * count + 1 ) )
- goto Exit;
-
- table->max_hints = count;
- table->sort_global = table->sort + count;
- table->num_hints = 0;
- table->num_zones = 0;
- table->zone = 0;
-
- /* now, initialize 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 idx, limit, count;
-
-
- limit = hint_mask->num_bits;
- count = 0;
-
- psh2_hint_table_deactivate( table );
-
- for ( idx = 0; idx < limit; idx++ )
- {
- if ( mask == 0 )
- {
- val = *cursor++;
- mask = 0x80;
- }
-
- if ( val & mask )
- {
- PSH2_Hint hint = &table->hints[idx];
-
-
- if ( !psh2_hint_is_active( hint ) )
- {
- FT_UInt count2;
-
-#if 0
- PSH2_Hint* sort = table->sort;
- PSH2_Hint hint2;
-
- 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 are 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[i2 + 1] = hint2;
- sort[i2] = hint1;
- }
- }
- }
- }
-
-
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** HINTS GRID-FITTING AND OPTIMIZATION *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
-
-#ifdef DEBUG_HINTER
- static void
- ps2_simple_scale( PSH2_Hint_Table table,
- FT_Fixed scale,
- FT_Fixed delta,
- FT_Int dimension )
- {
- 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, dimension );
- }
- }
-#endif
-
-
- static void
- psh2_hint_align( PSH2_Hint hint,
- PSH_Globals globals,
- FT_Int dimension )
- {
- PSH_Dimension dim = &globals->dimension[dimension];
- 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 = PSH_BLUE_ALIGN_NONE;
- align.align_bot = align.align_top = 0;
-
- if ( dimension == 1 )
- 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, dimension );
-
- 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, dimension );
-#endif
- }
- }
-
-
- static void
- psh2_hint_table_align_hints( PSH2_Hint_Table table,
- PSH_Globals globals,
- FT_Int dimension )
- {
- PSH2_Hint hint;
- FT_UInt count;
-
-#ifdef DEBUG_HINTER
- PSH_Dimension dim = &globals->dimension[dimension];
- FT_Fixed scale = dim->scale_mult;
- FT_Fixed delta = dim->scale_delta;
-
-
- if ( ps_debug_no_vert_hints && dimension == 0 )
- {
- ps2_simple_scale( table, scale, delta, dimension );
- return;
- }
-
- if ( ps_debug_no_horz_hints && dimension == 1 )
- {
- ps2_simple_scale( table, scale, delta, dimension );
- return;
- }
-#endif
-
- hint = table->hints;
- count = table->max_hints;
-
- for ( ; count > 0; count--, hint++ )
- psh2_hint_align( hint, globals, dimension );
- }
-
-
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** POINTS INTERPOLATION ROUTINES *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
-
-#define PSH2_ZONE_MIN -3200000
-#define PSH2_ZONE_MAX +3200000
-
-#define xxDEBUG_ZONES
-
-
-#ifdef DEBUG_ZONES
-
-#include <stdio.h>
-
- static void
- psh2_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 psh2_print_zone( x ) do { } while ( 0 )
-
-#endif
-
-#if 0
- /* 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;
-
- psh2_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 );
-
- psh2_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 );
-
- psh2_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 );
-
- psh2_print_zone( zone );
-
- zone++;
-
- table->num_zones = zone - table->zones;
- table->zone = table->zones;
- }
-#endif
-
-#if 0
- /* 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;
- }
-#endif
-
-#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_Int dimension )
-
- {
- FT_UInt count, first, last;
- PS_Mask_Table hint_masks = table->hint_masks;
- PS_Mask mask;
- PSH_Dimension dim = &globals->dimension[dimension];
- 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, dimension );
- 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 = dimension ? &vec->y : &vec->x;
- 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 ( dimension == 0 )
- {
- 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 );
-
- FT_FREE( glyph->points );
- FT_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 */
- FT_MEM_ZERO( glyph, sizeof ( *glyph ) );
-
- memory = globals->memory;
-
- /* allocate and setup points + contours arrays */
- if ( FT_NEW_ARRAY( glyph->points, outline->n_points ) ||
- FT_NEW_ARRAY( glyph->contours, outline->n_contours ) )
- 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 = (FT_Char)psh2_compute_dir( dxi, dyi );
-
- dxo = vec[n_next].x - vec[n].x;
- dyo = vec[n_next].y - vec[n].y;
-
- point->dir_out = (FT_Char)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_Int dimension )
- {
- 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 ( dimension == 0 )
- 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_Int dimension )
- {
- 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 ( dimension == 0 )
- vec[n].x = point->cur_u;
- else
- vec[n].y = point->cur_u;
-
- if ( psh2_point_is_strong( point ) )
- tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 );
-
-#ifdef DEBUG_HINTER
- if ( dimension == 0 )
- {
- 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++;
- }
- }
-
-
-#define PSH2_STRONG_THRESHOLD 10
-
-
- 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 ) < PSH2_STRONG_THRESHOLD )
- {
- Is_Strong:
- psh2_point_set_strong( point );
- point->hint = hint;
- break;
- }
-
- d -= hint->org_len;
- if ( ABS( d ) < PSH2_STRONG_THRESHOLD )
- 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_Int dimension )
- {
- /* 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[dimension];
- PS_Mask mask = table->hint_masks->masks;
- FT_UInt num_masks = table->hint_masks->num_masks;
- FT_UInt first = 0;
- FT_Int major_dir = dimension == 0 ? PSH2_DIR_UP : PSH2_DIR_RIGHT;
-
-
- /* process secondary hints to "selected" points */
- if ( num_masks > 1 && glyph->num_points > 0 )
- {
- first = mask->end_point;
- 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_Int dimension )
- {
- PSH_Dimension dim = &glyph->globals->dimension[dimension];
- FT_Fixed scale = dim->scale_mult;
-
-
- {
- 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_Int dimension )
- {
-#if 1
- PSH_Dimension dim = &glyph->globals->dimension[dimension];
- 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 are 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 are 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_Int dimension )
- {
- PSH_Dimension dim = &glyph->globals->dimension[dimension];
- 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 are less than 2 fitted points in the contour, we */
- /* 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 */
- /* 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,
- FT_Render_Mode hint_mode )
- {
- PSH2_GlyphRec glyphrec;
- PSH2_Glyph glyph = &glyphrec;
- FT_Error error;
-#ifdef DEBUG_HINTER
- FT_Memory memory;
-#endif
- FT_Int dimension;
-
- FT_UNUSED( hint_mode );
-
-#ifdef DEBUG_HINTER
- memory = globals->memory;
-
- if ( ps2_debug_glyph )
- {
- psh2_glyph_done( ps2_debug_glyph );
- FT_FREE( ps2_debug_glyph );
- }
-
- if ( FT_NEW( glyph ) )
- return error;
-
- ps2_debug_glyph = glyph;
-#endif
-
- error = psh2_glyph_init( glyph, outline, ps_hints, globals );
- if ( error )
- goto Exit;
-
- for ( dimension = 0; dimension < 2; 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;
- }
-
-
-/* END */
--- a/src/pshinter/pshalgo2.h
+++ /dev/null
@@ -1,203 +1,0 @@
-/***************************************************************************/
-/* */
-/* pshalgo2.h */
-/* */
-/* PostScript hinting algorithm 2 (specification). */
-/* */
-/* 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 __PSHALGO2_H__
-#define __PSHALGO2_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_Render_Mode hint_mode );
-
-
-FT_END_HEADER
-
-
-#endif /* __PSHALGO2_H__ */
-
-
-/* END */
--- a/src/pshinter/pshalgo3.c
+++ /dev/null
@@ -1,1997 +1,0 @@
-/***************************************************************************/
-/* */
-/* pshalgo3.c */
-/* */
-/* PostScript hinting algorithm 3 (body). */
-/* */
-/* Copyright 2001, 2002, 2003 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. */
-/* */
-/***************************************************************************/
-
-
-#include <ft2build.h>
-#include FT_INTERNAL_OBJECTS_H
-#include FT_INTERNAL_DEBUG_H
-#include "pshalgo3.h"
-
-
-#undef FT_COMPONENT
-#define FT_COMPONENT trace_pshalgo2
-
-
-#ifdef DEBUG_HINTER
- PSH3_Hint_Table ps3_debug_hint_table = 0;
- PSH3_HintFunc ps3_debug_hint_func = 0;
- PSH3_Glyph ps3_debug_glyph = 0;
-#endif
-
-
-#define COMPUTE_INFLEXS /* compute inflection points to optimize "S" and others */
-#define STRONGER /* slightly increase the contrast of smooth hinting */
-
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** BASIC HINTS RECORDINGS *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
-
- /* return true iff two stem hints overlap */
- static FT_Int
- psh3_hint_overlap( PSH3_Hint hint1,
- PSH3_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
- psh3_hint_table_done( PSH3_Hint_Table table,
- FT_Memory memory )
- {
- FT_FREE( table->zones );
- table->num_zones = 0;
- table->zone = 0;
-
- FT_FREE( table->sort );
- FT_FREE( table->hints );
- table->num_hints = 0;
- table->max_hints = 0;
- table->sort_global = 0;
- }
-
-
- /* deactivate all hints in a table */
- static void
- psh3_hint_table_deactivate( PSH3_Hint_Table table )
- {
- FT_UInt count = table->max_hints;
- PSH3_Hint hint = table->hints;
-
-
- for ( ; count > 0; count--, hint++ )
- {
- psh3_hint_deactivate( hint );
- hint->order = -1;
- }
- }
-
-
- /* internal function used to record a new hint */
- static void
- psh3_hint_table_record( PSH3_Hint_Table table,
- FT_UInt idx )
- {
- PSH3_Hint hint = table->hints + idx;
-
-
- if ( idx >= table->max_hints )
- {
- FT_ERROR(( "psh3_hint_table_record: invalid hint index %d\n", idx ));
- return;
- }
-
- /* ignore active hints */
- if ( psh3_hint_is_active( hint ) )
- return;
-
- psh3_hint_activate( hint );
-
- /* now scan the current active hint set in order to determine */
- /* if we are overlapping with another segment */
- {
- PSH3_Hint* sorted = table->sort_global;
- FT_UInt count = table->num_hints;
- PSH3_Hint hint2;
-
-
- hint->parent = 0;
- for ( ; count > 0; count--, sorted++ )
- {
- hint2 = sorted[0];
-
- if ( psh3_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(( "psh3_hint_table_record: too many sorted hints! BUG!\n" ));
- }
-
-
- static void
- psh3_hint_table_record_mask( PSH3_Hint_Table table,
- PS_Mask hint_mask )
- {
- FT_Int mask = 0, val = 0;
- FT_Byte* cursor = hint_mask->bytes;
- FT_UInt idx, limit;
-
-
- limit = hint_mask->num_bits;
-
- for ( idx = 0; idx < limit; idx++ )
- {
- if ( mask == 0 )
- {
- val = *cursor++;
- mask = 0x80;
- }
-
- if ( val & mask )
- psh3_hint_table_record( table, idx );
-
- mask >>= 1;
- }
- }
-
-
- /* create hints table */
- static FT_Error
- psh3_hint_table_init( PSH3_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 ( FT_NEW_ARRAY( table->sort, 2 * count ) ||
- FT_NEW_ARRAY( table->hints, count ) ||
- FT_NEW_ARRAY( table->zones, 2 * count + 1 ) )
- goto Exit;
-
- table->max_hints = count;
- table->sort_global = table->sort + count;
- table->num_hints = 0;
- table->num_zones = 0;
- table->zone = 0;
-
- /* now, initialize the "hints" array */
- {
- PSH3_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++ )
- psh3_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(( "psh3_hint_table_init: missing/incorrect hint masks!\n" ));
- Count = table->max_hints;
- for ( Index = 0; Index < Count; Index++ )
- psh3_hint_table_record( table, Index );
- }
-
- Exit:
- return error;
- }
-
-
- static void
- psh3_hint_table_activate_mask( PSH3_Hint_Table table,
- PS_Mask hint_mask )
- {
- FT_Int mask = 0, val = 0;
- FT_Byte* cursor = hint_mask->bytes;
- FT_UInt idx, limit, count;
-
-
- limit = hint_mask->num_bits;
- count = 0;
-
- psh3_hint_table_deactivate( table );
-
- for ( idx = 0; idx < limit; idx++ )
- {
- if ( mask == 0 )
- {
- val = *cursor++;
- mask = 0x80;
- }
-
- if ( val & mask )
- {
- PSH3_Hint hint = &table->hints[idx];
-
-
- if ( !psh3_hint_is_active( hint ) )
- {
- FT_UInt count2;
-
-#if 0
- PSH3_Hint* sort = table->sort;
- PSH3_Hint hint2;
-
-
- for ( count2 = count; count2 > 0; count2--, sort++ )
- {
- hint2 = sort[0];
- if ( psh3_hint_overlap( hint, hint2 ) )
- FT_ERROR(( "psh3_hint_table_activate_mask:"
- " found overlapping hints\n" ))
- }
-#else
- count2 = 0;
-#endif
-
- if ( count2 == 0 )
- {
- psh3_hint_activate( hint );
- if ( count < table->max_hints )
- table->sort[count++] = hint;
- else
- FT_ERROR(( "psh3_hint_tableactivate_mask:"
- " too many active hints\n" ));
- }
- }
- }
-
- mask >>= 1;
- }
- table->num_hints = count;
-
- /* now, sort the hints; they are guaranteed to not overlap */
- /* so we can compare their "org_pos" field directly */
- {
- FT_Int i1, i2;
- PSH3_Hint hint1, hint2;
- PSH3_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[i2 + 1] = hint2;
- sort[i2] = hint1;
- }
- }
- }
- }
-
-
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** HINTS GRID-FITTING AND OPTIMIZATION *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
-
-#if 1
- static FT_Pos
- psh3_dimension_quantize_len( PSH_Dimension dim,
- FT_Pos len,
- FT_Bool do_snapping )
- {
- if ( len <= 64 )
- len = 64;
- else
- {
- FT_Pos delta = len - dim->stdw.widths[0].cur;
-
-
- if ( delta < 0 )
- delta = -delta;
-
- if ( delta < 40 )
- {
- len = dim->stdw.widths[0].cur;
- if ( len < 48 )
- len = 48;
- }
-
- if ( len < 3 * 64 )
- {
- delta = ( len & 63 );
- len &= -64;
-
- if ( delta < 10 )
- len += delta;
-
- else if ( delta < 32 )
- len += 10;
-
- else if ( delta < 54 )
- len += 54;
-
- else
- len += delta;
- }
- else
- len = ( len + 32 ) & -64;
- }
-
- if ( do_snapping )
- len = ( len + 32 ) & -64;
-
- return len;
- }
-#endif /* 0 */
-
-
-#ifdef DEBUG_HINTER
-
- static void
- ps3_simple_scale( PSH3_Hint_Table table,
- FT_Fixed scale,
- FT_Fixed delta,
- FT_Int dimension )
- {
- PSH3_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 ( ps3_debug_hint_func )
- ps3_debug_hint_func( hint, dimension );
- }
- }
-
-#endif /* DEBUG_HINTER */
-
-
- static FT_Fixed
- psh3_hint_snap_stem_side_delta( FT_Fixed pos,
- FT_Fixed len )
- {
- FT_Fixed delta1 = ( ( pos + 32 ) & -64 ) - pos;
- FT_Fixed delta2 = ( ( pos + len + 32 ) & -64 ) - pos - len;
-
-
- if ( ABS( delta1 ) <= ABS( delta2 ) )
- return delta1;
- else
- return delta2;
- }
-
-
- static void
- psh3_hint_align( PSH3_Hint hint,
- PSH_Globals globals,
- FT_Int dimension,
- PSH3_Glyph glyph )
- {
- PSH_Dimension dim = &globals->dimension[dimension];
- FT_Fixed scale = dim->scale_mult;
- FT_Fixed delta = dim->scale_delta;
-
-
- if ( !psh3_hint_is_fitted( hint ) )
- {
- FT_Pos pos = FT_MulFix( hint->org_pos, scale ) + delta;
- FT_Pos len = FT_MulFix( hint->org_len, scale );
-
- FT_Int do_snapping;
- FT_Pos fit_len;
- PSH_AlignmentRec align;
-
-
- /* ignore stem alignments when requested through the hint flags */
- if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
- ( dimension == 1 && !glyph->do_vert_hints ) )
- {
- hint->cur_pos = pos;
- hint->cur_len = len;
-
- psh3_hint_set_fitted( hint );
- return;
- }
-
- /* perform stem snapping when requested - this is necessary
- * for monochrome and LCD hinting modes only
- */
- do_snapping = ( dimension == 0 && glyph->do_horz_snapping ) ||
- ( dimension == 1 && glyph->do_vert_snapping );
-
- hint->cur_len = fit_len = len;
-
- /* check blue zones for horizontal stems */
- align.align = PSH_BLUE_ALIGN_NONE;
- align.align_bot = align.align_top = 0;
-
- if ( dimension == 1 )
- 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:
- {
- PSH3_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 ( !psh3_hint_is_fitted( parent ) )
- psh3_hint_align( parent, globals, dimension, glyph );
-
- par_org_center = parent->org_pos + ( parent->org_len >> 1 );
- par_cur_center = parent->cur_pos + ( parent->cur_len >> 1 );
- cur_org_center = hint->org_pos + ( hint->org_len >> 1 );
-
- cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
- pos = par_cur_center + cur_delta - ( len >> 1 );
- }
-
- hint->cur_pos = pos;
- hint->cur_len = fit_len;
-
- /* Stem adjustment tries to snap stem widths to standard
- * ones. This is important to prevent unpleasant rounding
- * artefacts.
- */
- if ( glyph->do_stem_adjust )
- {
- if ( len <= 64 )
- {
- /* the stem is less than one pixel; we will center it
- * around the nearest pixel center
- */
-#if 1
- pos = ( pos + ( len >> 1 ) ) & -64;
-#else
- /* this seems to be a bug! */
- pos = ( pos + ( ( len >> 1 ) & -64 ) );
-#endif
- len = 64;
- }
- else
- {
- len = psh3_dimension_quantize_len( dim, len, 0 );
- }
- }
-
- /* now that we have a good hinted stem width, try to position */
- /* the stem along a pixel grid integer coordinate */
- hint->cur_pos = pos + psh3_hint_snap_stem_side_delta( pos, len );
- hint->cur_len = len;
- }
- }
-
- if ( do_snapping )
- {
- pos = hint->cur_pos;
- len = hint->cur_len;
-
- if ( len < 64 )
- len = 64;
- else
- len = ( len + 32 ) & -64;
-
- switch ( align.align )
- {
- case PSH_BLUE_ALIGN_TOP:
- hint->cur_pos = align.align_top - len;
- hint->cur_len = len;
- break;
-
- case PSH_BLUE_ALIGN_BOT:
- hint->cur_len = len;
- break;
-
- case PSH_BLUE_ALIGN_BOT | PSH_BLUE_ALIGN_TOP:
- /* don't touch */
- break;
-
-
- default:
- hint->cur_len = len;
- if ( len & 64 )
- pos = ( ( pos + ( len >> 1 ) ) & -64 ) + 32;
- else
- pos = ( pos + ( len >> 1 ) + 32 ) & -64;
-
- hint->cur_pos = pos - ( len >> 1 );
- hint->cur_len = len;
- }
- }
-
- psh3_hint_set_fitted( hint );
-
-#ifdef DEBUG_HINTER
- if ( ps3_debug_hint_func )
- ps3_debug_hint_func( hint, dimension );
-#endif
- }
- }
-
-
-#if 0 /* not used for now, experimental */
-
- /*
- * A variant to perform "light" hinting (i.e. FT_RENDER_MODE_LIGHT)
- * of stems
- */
- static void
- psh3_hint_align_light( PSH3_Hint hint,
- PSH_Globals globals,
- FT_Int dimension,
- PSH3_Glyph glyph )
- {
- PSH_Dimension dim = &globals->dimension[dimension];
- FT_Fixed scale = dim->scale_mult;
- FT_Fixed delta = dim->scale_delta;
-
-
- if ( !psh3_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_len;
-
- PSH_AlignmentRec align;
-
-
- /* ignore stem alignments when requested through the hint flags */
- if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
- ( dimension == 1 && !glyph->do_vert_hints ) )
- {
- hint->cur_pos = pos;
- hint->cur_len = len;
-
- psh3_hint_set_fitted( hint );
- return;
- }
-
- fit_len = len;
-
- hint->cur_len = fit_len;
-
- /* check blue zones for horizontal stems */
- align.align = PSH_BLUE_ALIGN_NONE;
- align.align_bot = align.align_top = 0;
-
- if ( dimension == 1 )
- 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:
- {
- PSH3_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 ( !psh3_hint_is_fitted( parent ) )
- psh3_hint_align_light( parent, globals, dimension, glyph );
-
- 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 );
- pos = par_cur_center + cur_delta - ( len >> 1 );
- }
-
- /* Stems less than one pixel wide are easy -- we want to
- * make them as dark as possible, so they must fall within
- * one pixel. If the stem is split between two pixels
- * then snap the edge that is nearer to the pixel boundary
- * to the pixel boundary.
- */
- if ( len <= 64 )
- {
- if ( ( pos + len + 63 ) / 64 != pos / 64 + 1 )
- pos += psh3_hint_snap_stem_side_delta ( pos, len );
- }
-
- /* Position stems other to minimize the amount of mid-grays.
- * There are, in general, two positions that do this,
- * illustrated as A) and B) below.
- *
- * + + + +
- *
- * A) |--------------------------------|
- * B) |--------------------------------|
- * C) |--------------------------------|
- *
- * Position A) (split the excess stem equally) should be better
- * for stems of width N + f where f < 0.5.
- *
- * Position B) (split the deficiency equally) should be better
- * for stems of width N + f where f > 0.5.
- *
- * It turns out though that minimizing the total number of lit
- * pixels is also important, so position C), with one edge
- * aligned with a pixel boundary is actually preferable
- * to A). There are also more possibile positions for C) than
- * for A) or B), so it involves less distortion of the overall
- * character shape.
- */
- else /* len > 64 */
- {
- FT_Fixed frac_len = len & 63;
- FT_Fixed center = pos + ( len >> 1 );
- FT_Fixed delta_a, delta_b;
-
-
- if ( ( len / 64 ) & 1 )
- {
- delta_a = ( center & -64 ) + 32 - center;
- delta_b = ( ( center + 32 ) & - 64 ) - center;
- }
- else
- {
- delta_a = ( ( center + 32 ) & - 64 ) - center;
- delta_b = ( center & -64 ) + 32 - center;
- }
-
- /* We choose between B) and C) above based on the amount
- * of fractinal stem width; for small amounts, choose
- * C) always, for large amounts, B) always, and inbetween,
- * pick whichever one involves less stem movement.
- */
- if ( frac_len < 32 )
- {
- pos += psh3_hint_snap_stem_side_delta ( pos, len );
- }
- else if ( frac_len < 48 )
- {
- FT_Fixed side_delta = psh3_hint_snap_stem_side_delta ( pos,
- len );
-
-
- if ( ABS( side_delta ) < ABS( delta_b ) )
- pos += side_delta;
- else
- pos += delta_b;
- }
- else
- {
- pos += delta_b;
- }
- }
-
- hint->cur_pos = pos;
- }
- } /* switch */
-
- psh3_hint_set_fitted( hint );
-
-#ifdef DEBUG_HINTER
- if ( ps3_debug_hint_func )
- ps3_debug_hint_func( hint, dimension );
-#endif
- }
- }
-
-#endif /* 0 */
-
-
- static void
- psh3_hint_table_align_hints( PSH3_Hint_Table table,
- PSH_Globals globals,
- FT_Int dimension,
- PSH3_Glyph glyph )
- {
- PSH3_Hint hint;
- FT_UInt count;
-
-#ifdef DEBUG_HINTER
-
- PSH_Dimension dim = &globals->dimension[dimension];
- FT_Fixed scale = dim->scale_mult;
- FT_Fixed delta = dim->scale_delta;
-
-
- if ( ps_debug_no_vert_hints && dimension == 0 )
- {
- ps3_simple_scale( table, scale, delta, dimension );
- return;
- }
-
- if ( ps_debug_no_horz_hints && dimension == 1 )
- {
- ps3_simple_scale( table, scale, delta, dimension );
- return;
- }
-
-#endif /* DEBUG_HINTER*/
-
- hint = table->hints;
- count = table->max_hints;
-
- for ( ; count > 0; count--, hint++ )
- psh3_hint_align( hint, globals, dimension, glyph );
- }
-
-
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** POINTS INTERPOLATION ROUTINES *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
-
-#define PSH3_ZONE_MIN -3200000L
-#define PSH3_ZONE_MAX +3200000L
-
-#define xxDEBUG_ZONES
-
-
-#ifdef DEBUG_ZONES
-
-#include <stdio.h>
-
- static void
- psh3_print_zone( PSH3_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 psh3_print_zone( x ) do { } while ( 0 )
-
-#endif /* DEBUG_ZONES */
-
-
- /*************************************************************************/
- /*************************************************************************/
- /***** *****/
- /***** HINTER GLYPH MANAGEMENT *****/
- /***** *****/
- /*************************************************************************/
- /*************************************************************************/
-
-#ifdef COMPUTE_INFLEXS
-
- /* compute all inflex points in a given glyph */
- static void
- psh3_glyph_compute_inflections( PSH3_Glyph glyph )
- {
- FT_UInt n;
-
-
- for ( n = 0; n < glyph->num_contours; n++ )
- {
- PSH3_Point first, start, end, before, after;
- FT_Angle angle_in, angle_seg, angle_out;
- FT_Angle diff_in, diff_out;
- FT_Int finished = 0;
-
-
- /* we need at least 4 points to create an inflection point */
- if ( glyph->contours[n].count < 4 )
- continue;
-
- /* compute first segment in contour */
- first = glyph->contours[n].start;
-
- start = end = first;
- do
- {
- end = end->next;
- if ( end == first )
- goto Skip;
-
- } while ( PSH3_POINT_EQUAL_ORG( end, first ) );
-
- angle_seg = PSH3_POINT_ANGLE( start, end );
-
- /* extend the segment start whenever possible */
- before = start;
- do
- {
- do
- {
- start = before;
- before = before->prev;
- if ( before == first )
- goto Skip;
-
- } while ( PSH3_POINT_EQUAL_ORG( before, start ) );
-
- angle_in = PSH3_POINT_ANGLE( before, start );
-
- } while ( angle_in == angle_seg );
-
- first = start;
- diff_in = FT_Angle_Diff( angle_in, angle_seg );
-
- /* now, process all segments in the contour */
- do
- {
- /* first, extend current segment's end whenever possible */
- after = end;
- do
- {
- do
- {
- end = after;
- after = after->next;
- if ( after == first )
- finished = 1;
-
- } while ( PSH3_POINT_EQUAL_ORG( end, after ) );
-
- angle_out = PSH3_POINT_ANGLE( end, after );
-
- } while ( angle_out == angle_seg );
-
- diff_out = FT_Angle_Diff( angle_seg, angle_out );
-
- if ( ( diff_in ^ diff_out ) < 0 )
- {
- /* diff_in and diff_out have different signs, we have */
- /* inflection points here... */
-
- do
- {
- psh3_point_set_inflex( start );
- start = start->next;
- }
- while ( start != end );
-
- psh3_point_set_inflex( start );
- }
-
- start = end;
- end = after;
- angle_seg = angle_out;
- diff_in = diff_out;
-
- } while ( !finished );
-
- Skip:
- ;
- }
- }
-
-#endif /* COMPUTE_INFLEXS */
-
-
- static void
- psh3_glyph_done( PSH3_Glyph glyph )
- {
- FT_Memory memory = glyph->memory;
-
-
- psh3_hint_table_done( &glyph->hint_tables[1], memory );
- psh3_hint_table_done( &glyph->hint_tables[0], memory );
-
- FT_FREE( glyph->points );
- FT_FREE( glyph->contours );
-
- glyph->num_points = 0;
- glyph->num_contours = 0;
-
- glyph->memory = 0;
- }
-
-
- static int
- psh3_compute_dir( FT_Pos dx,
- FT_Pos dy )
- {
- FT_Pos ax, ay;
- int result = PSH3_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 ) ? PSH3_DIR_RIGHT : PSH3_DIR_LEFT;
- }
- else if ( ax * 12 < ay )
- {
- /* |dx| <<< |dy| means a near-vertical segment */
- result = ( dy >= 0 ) ? PSH3_DIR_UP : PSH3_DIR_DOWN;
- }
-
- return result;
- }
-
-
- /* load outline point coordinates into hinter glyph */
- static void
- psh3_glyph_load_points( PSH3_Glyph glyph,
- FT_Int dimension )
- {
- FT_Vector* vec = glyph->outline->points;
- PSH3_Point point = glyph->points;
- FT_UInt count = glyph->num_points;
-
-
- for ( ; count > 0; count--, point++, vec++ )
- {
- point->flags2 = 0;
- point->hint = NULL;
- if ( dimension == 0 )
- {
- point->org_u = vec->x;
- point->org_v = vec->y;
- }
- else
- {
- point->org_u = vec->y;
- point->org_v = vec->x;
- }
-
-#ifdef DEBUG_HINTER
- point->org_x = vec->x;
- point->org_y = vec->y;
-#endif
-
- }
- }
-
-
- /* save hinted point coordinates back to outline */
- static void
- psh3_glyph_save_points( PSH3_Glyph glyph,
- FT_Int dimension )
- {
- FT_UInt n;
- PSH3_Point point = glyph->points;
- FT_Vector* vec = glyph->outline->points;
- char* tags = glyph->outline->tags;
-
-
- for ( n = 0; n < glyph->num_points; n++ )
- {
- if ( dimension == 0 )
- vec[n].x = point->cur_u;
- else
- vec[n].y = point->cur_u;
-
- if ( psh3_point_is_strong( point ) )
- tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 );
-
-#ifdef DEBUG_HINTER
-
- if ( dimension == 0 )
- {
- point->cur_x = point->cur_u;
- point->flags_x = point->flags2 | point->flags;
- }
- else
- {
- point->cur_y = point->cur_u;
- point->flags_y = point->flags2 | point->flags;
- }
-
-#endif
-
- point++;
- }
- }
-
-
- static FT_Error
- psh3_glyph_init( PSH3_Glyph glyph,
- FT_Outline* outline,
- PS_Hints ps_hints,
- PSH_Globals globals )
- {
- FT_Error error;
- FT_Memory memory;
-
-
- /* clear all fields */
- FT_MEM_ZERO( glyph, sizeof ( *glyph ) );
-
- memory = globals->memory;
-
- /* allocate and setup points + contours arrays */
- if ( FT_NEW_ARRAY( glyph->points, outline->n_points ) ||
- FT_NEW_ARRAY( glyph->contours, outline->n_contours ) )
- goto Exit;
-
- glyph->num_points = outline->n_points;
- glyph->num_contours = outline->n_contours;
-
- {
- FT_UInt first = 0, next, n;
- PSH3_Point points = glyph->points;
- PSH3_Contour contour = glyph->contours;
-
-
- for ( n = 0; n < glyph->num_contours; n++ )
- {
- FT_Int count;
- PSH3_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;
- }
- }
-
- {
- PSH3_Point points = glyph->points;
- PSH3_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 = PSH3_POINT_OFF;
-
- dxi = vec[n].x - vec[n_prev].x;
- dyi = vec[n].y - vec[n_prev].y;
-
- point->dir_in = (FT_Char)psh3_compute_dir( dxi, dyi );
-
- dxo = vec[n_next].x - vec[n].x;
- dyo = vec[n_next].y - vec[n].y;
-
- point->dir_out = (FT_Char)psh3_compute_dir( dxo, dyo );
-
- /* detect smooth points */
- if ( point->flags & PSH3_POINT_OFF )
- point->flags |= PSH3_POINT_SMOOTH;
- else if ( point->dir_in != PSH3_DIR_NONE ||
- point->dir_out != PSH3_DIR_NONE )
- {
- if ( point->dir_in == point->dir_out )
- point->flags |= PSH3_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 |= PSH3_POINT_SMOOTH;
- }
- }
- }
-
- glyph->memory = memory;
- glyph->outline = outline;
- glyph->globals = globals;
-
-#ifdef COMPUTE_INFLEXS
- psh3_glyph_load_points( glyph, 0 );
- psh3_glyph_compute_inflections( glyph );
-#endif /* COMPUTE_INFLEXS */
-
- /* now deal with hints tables */
- error = psh3_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 = psh3_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;
- }
-
-
- /* compute all extrema in a glyph for a given dimension */
- static void
- psh3_glyph_compute_extrema( PSH3_Glyph glyph )
- {
- FT_UInt n;
-
-
- /* first of all, compute all local extrema */
- for ( n = 0; n < glyph->num_contours; n++ )
- {
- PSH3_Point first = glyph->contours[n].start;
- PSH3_Point point, before, after;
-
-
- if ( glyph->contours[n].count == 0 )
- continue;
-
- point = first;
- before = point;
- after = point;
-
- do
- {
- before = before->prev;
- if ( before == first )
- goto Skip;
-
- } while ( before->org_u == point->org_u );
-
- first = point = before->next;
-
- for (;;)
- {
- after = point;
- do
- {
- after = after->next;
- if ( after == first )
- goto Next;
-
- } while ( after->org_u == point->org_u );
-
- if ( before->org_u < point->org_u )
- {
- if ( after->org_u < point->org_u )
- {
- /* local maximum */
- goto Extremum;
- }
- }
- else /* before->org_u > point->org_u */
- {
- if ( after->org_u > point->org_u )
- {
- /* local minimum */
- Extremum:
- do
- {
- psh3_point_set_extremum( point );
- point = point->next;
-
- } while ( point != after );
- }
- }
-
- before = after->prev;
- point = after;
-
- } /* for */
-
- Next:
- ;
- }
-
- /* for each extrema, determine its direction along the */
- /* orthogonal axis */
- for ( n = 0; n < glyph->num_points; n++ )
- {
- PSH3_Point point, before, after;
-
-
- point = &glyph->points[n];
- before = point;
- after = point;
-
- if ( psh3_point_is_extremum( point ) )
- {
- do
- {
- before = before->prev;
- if ( before == point )
- goto Skip;
-
- } while ( before->org_v == point->org_v );
-
- do
- {
- after = after->next;
- if ( after == point )
- goto Skip;
-
- } while ( after->org_v == point->org_v );
- }
-
- if ( before->org_v < point->org_v &&
- after->org_v > point->org_v )
- {
- psh3_point_set_positive( point );
- }
- else if ( before->org_v > point->org_v &&
- after->org_v < point->org_v )
- {
- psh3_point_set_negative( point );
- }
-
- Skip:
- ;
- }
- }
-
-
-#define PSH3_STRONG_THRESHOLD 30
-
-
- /* major_dir is the direction for points on the bottom/left of the stem; */
- /* Points on the top/right of the stem will have a direction of */
- /* -major_dir. */
-
- static void
- psh3_hint_table_find_strong_point( PSH3_Hint_Table table,
- PSH3_Point point,
- FT_Int major_dir )
- {
- PSH3_Hint* sort = table->sort;
- FT_UInt num_hints = table->num_hints;
- FT_Int point_dir = 0;
-
-
- if ( PSH3_DIR_COMPARE( point->dir_in, major_dir ) )
- point_dir = point->dir_in;
-
- else if ( PSH3_DIR_COMPARE( point->dir_out, major_dir ) )
- point_dir = point->dir_out;
-
- if ( point_dir )
- {
- FT_UInt flag;
-
-
- for ( ; num_hints > 0; num_hints--, sort++ )
- {
- PSH3_Hint hint = sort[0];
- FT_Pos d;
-
-
- if ( point_dir == major_dir )
- {
- flag = PSH3_POINT_EDGE_MIN;
- d = point->org_u - hint->org_pos;
-
- if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
- {
- Is_Strong:
- psh3_point_set_strong( point );
- point->flags2 |= flag;
- point->hint = hint;
- break;
- }
- }
- else if ( point_dir == -major_dir )
- {
- flag = PSH3_POINT_EDGE_MAX;
- d = point->org_u - hint->org_pos - hint->org_len;
-
- if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
- goto Is_Strong;
- }
- }
- }
-
-#if 1
- else if ( psh3_point_is_extremum( point ) )
- {
- /* treat extrema as special cases for stem edge alignment */
- FT_UInt min_flag, max_flag;
-
-
- if ( major_dir == PSH3_DIR_HORIZONTAL )
- {
- min_flag = PSH3_POINT_POSITIVE;
- max_flag = PSH3_POINT_NEGATIVE;
- }
- else
- {
- min_flag = PSH3_POINT_NEGATIVE;
- max_flag = PSH3_POINT_POSITIVE;
- }
-
- for ( ; num_hints > 0; num_hints--, sort++ )
- {
- PSH3_Hint hint = sort[0];
- FT_Pos d, flag;
-
-
- if ( point->flags2 & min_flag )
- {
- flag = PSH3_POINT_EDGE_MIN;
- d = point->org_u - hint->org_pos;
-
- if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
- {
- Is_Strong2:
- point->flags2 |= flag;
- point->hint = hint;
- psh3_point_set_strong( point );
- break;
- }
- }
- else if ( point->flags2 & max_flag )
- {
- flag = PSH3_POINT_EDGE_MAX;
- d = point->org_u - hint->org_pos - hint->org_len;
-
- if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
- goto Is_Strong2;
- }
-
- if ( point->org_u >= hint->org_pos &&
- point->org_u <= hint->org_pos + hint->org_len )
- {
- point->hint = hint;
- }
- }
- }
-
-#endif /* 1 */
- }
-
-
- /* find strong points in a glyph */
- static void
- psh3_glyph_find_strong_points( PSH3_Glyph glyph,
- FT_Int dimension )
- {
- /* a point is strong if it is located on a stem */
- /* edge and has an "in" or "out" tangent to the hint's direction */
- {
- PSH3_Hint_Table table = &glyph->hint_tables[dimension];
- PS_Mask mask = table->hint_masks->masks;
- FT_UInt num_masks = table->hint_masks->num_masks;
- FT_UInt first = 0;
- FT_Int major_dir = dimension == 0 ? PSH3_DIR_VERTICAL
- : PSH3_DIR_HORIZONTAL;
-
-
- /* process secondary hints to "selected" points */
- if ( num_masks > 1 && glyph->num_points > 0 )
- {
- first = mask->end_point;
- mask++;
- for ( ; num_masks > 1; num_masks--, mask++ )
- {
- FT_UInt next;
- FT_Int count;
-
-
- next = mask->end_point;
- count = next - first;
- if ( count > 0 )
- {
- PSH3_Point point = glyph->points + first;
-
-
- psh3_hint_table_activate_mask( table, mask );
-
- for ( ; count > 0; count--, point++ )
- psh3_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;
- PSH3_Point point = glyph->points;
-
-
- psh3_hint_table_activate_mask( table, table->hint_masks->masks );
- for ( ; count > 0; count--, point++ )
- {
- if ( !psh3_point_is_strong( point ) )
- psh3_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;
- PSH3_Point point = glyph->points;
-
-
- for ( ; count > 0; count--, point++ )
- if ( point->hint && !psh3_point_is_strong( point ) )
- psh3_point_set_strong( point );
- }
- }
- }
-
-
- /* interpolate strong points with the help of hinted coordinates */
- static void
- psh3_glyph_interpolate_strong_points( PSH3_Glyph glyph,
- FT_Int dimension )
- {
- PSH_Dimension dim = &glyph->globals->dimension[dimension];
- FT_Fixed scale = dim->scale_mult;
-
-
- {
- FT_UInt count = glyph->num_points;
- PSH3_Point point = glyph->points;
-
-
- for ( ; count > 0; count--, point++ )
- {
- PSH3_Hint hint = point->hint;
-
-
- if ( hint )
- {
- FT_Pos delta;
-
-
- if ( psh3_point_is_edge_min( point ) )
- {
- point->cur_u = hint->cur_pos;
- }
- else if ( psh3_point_is_edge_max( point ) )
- {
- point->cur_u = hint->cur_pos + hint->cur_len;
- }
- else
- {
- 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;
- }
- psh3_point_set_fitted( point );
- }
- }
- }
- }
-
-
- static void
- psh3_glyph_interpolate_normal_points( PSH3_Glyph glyph,
- FT_Int dimension )
- {
-
-#if 1
-
- PSH_Dimension dim = &glyph->globals->dimension[dimension];
- FT_Fixed scale = dim->scale_mult;
-
-
- /* first technique: a point is strong if it is a local extrema */
- {
- FT_UInt count = glyph->num_points;
- PSH3_Point point = glyph->points;
-
-
- for ( ; count > 0; count--, point++ )
- {
- if ( psh3_point_is_strong( point ) )
- continue;
-
- /* sometimes, some local extremas are smooth points */
- if ( psh3_point_is_smooth( point ) )
- {
- if ( point->dir_in == PSH3_DIR_NONE ||
- point->dir_in != point->dir_out )
- continue;
-
- if ( !psh3_point_is_extremum( point ) &&
- !psh3_point_is_inflex( point ) )
- continue;
-
- point->flags &= ~PSH3_POINT_SMOOTH;
- }
-
- /* find best enclosing point coordinates */
- {
- PSH3_Point before = 0;
- PSH3_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;
- PSH3_Point cur = glyph->points;
-
-
- for ( ; count2 > 0; count2--, cur++ )
- {
- if ( psh3_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 are 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 are 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 );
- }
-
- psh3_point_set_fitted( point );
- }
- }
- }
-
-#endif /* 1 */
-
- }
-
-
- /* interpolate other points */
- static void
- psh3_glyph_interpolate_other_points( PSH3_Glyph glyph,
- FT_Int dimension )
- {
- PSH_Dimension dim = &glyph->globals->dimension[dimension];
- FT_Fixed scale = dim->scale_mult;
- FT_Fixed delta = dim->scale_delta;
- PSH3_Contour contour = glyph->contours;
- FT_UInt num_contours = glyph->num_contours;
-
-
- for ( ; num_contours > 0; num_contours--, contour++ )
- {
- PSH3_Point start = contour->start;
- PSH3_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 ( psh3_point_is_fitted( point ) )
- {
- if ( !first )
- first = point;
-
- fit_count++;
- }
-
- /* if there are less than 2 fitted points in the contour, we */
- /* 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 */
- /* 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 ( !psh3_point_is_fitted( next ) )
- break;
-
- first = next;
- }
-
- /* find next fitted point after unfitted one */
- for (;;)
- {
- next = next->next;
- if ( psh3_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
- ps3_hints_apply( PS_Hints ps_hints,
- FT_Outline* outline,
- PSH_Globals globals,
- FT_Render_Mode hint_mode )
- {
- PSH3_GlyphRec glyphrec;
- PSH3_Glyph glyph = &glyphrec;
- FT_Error error;
-#ifdef DEBUG_HINTER
- FT_Memory memory;
-#endif
- FT_Int dimension;
-
-
- /* something to do? */
- if ( outline->n_points == 0 || outline->n_contours == 0 )
- return FT_Err_Ok;
-
-#ifdef DEBUG_HINTER
-
- memory = globals->memory;
-
- if ( ps3_debug_glyph )
- {
- psh3_glyph_done( ps3_debug_glyph );
- FT_FREE( ps3_debug_glyph );
- }
-
- if ( FT_NEW( glyph ) )
- return error;
-
- ps3_debug_glyph = glyph;
-
-#endif /* DEBUG_HINTER */
-
- error = psh3_glyph_init( glyph, outline, ps_hints, globals );
- if ( error )
- goto Exit;
-
- /* try to optimize the y_scale so that the top of non-capital letters
- * is aligned on a pixel boundary whenever possible
- */
- {
- PSH_Dimension dim_x = &glyph->globals->dimension[0];
- PSH_Dimension dim_y = &glyph->globals->dimension[1];
-
- FT_Fixed x_scale = dim_x->scale_mult;
- FT_Fixed y_scale = dim_y->scale_mult;
-
- FT_Fixed scaled;
- FT_Fixed fitted;
-
-
- scaled = FT_MulFix( globals->blues.normal_top.zones->org_ref, y_scale );
- fitted = ( scaled + 32 ) & -64;
-
- if (scaled != fitted ) {
- y_scale = FT_MulDiv( y_scale, fitted, scaled );
-
- if ( fitted < scaled )
- x_scale -= x_scale / 50;
-
- psh_globals_set_scale( glyph->globals, x_scale, y_scale, 0, 0 );
- }
- }
-
- glyph->do_horz_hints = 1;
- glyph->do_vert_hints = 1;
-
- glyph->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
- hint_mode == FT_RENDER_MODE_LCD );
-
- glyph->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
- hint_mode == FT_RENDER_MODE_LCD_V );
-
- glyph->do_stem_adjust = FT_BOOL( hint_mode != FT_RENDER_MODE_LIGHT );
-
- for ( dimension = 0; dimension < 2; dimension++ )
- {
- /* load outline coordinates into glyph */
- psh3_glyph_load_points( glyph, dimension );
-
- /* compute local extrema */
- psh3_glyph_compute_extrema( glyph );
-
- /* compute aligned stem/hints positions */
- psh3_hint_table_align_hints( &glyph->hint_tables[dimension],
- glyph->globals,
- dimension,
- glyph );
-
- /* find strong points, align them, then interpolate others */
- psh3_glyph_find_strong_points( glyph, dimension );
- psh3_glyph_interpolate_strong_points( glyph, dimension );
- psh3_glyph_interpolate_normal_points( glyph, dimension );
- psh3_glyph_interpolate_other_points( glyph, dimension );
-
- /* save hinted coordinates back to outline */
- psh3_glyph_save_points( glyph, dimension );
- }
-
- Exit:
-
-#ifndef DEBUG_HINTER
- psh3_glyph_done( glyph );
-#endif
-
- return error;
- }
-
-
-/* END */
--- a/src/pshinter/pshalgo3.h
+++ /dev/null
@@ -1,255 +1,0 @@
-/***************************************************************************/
-/* */
-/* pshalgo3.h */
-/* */
-/* PostScript hinting algorithm 3 (specification). */
-/* */
-/* Copyright 2001, 2002 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 __PSHALGO3_H__
-#define __PSHALGO3_H__
-
-
-#include "pshrec.h"
-#include "pshglob.h"
-#include FT_TRIGONOMETRY_H
-
-
-FT_BEGIN_HEADER
-
-
- /* handle to Hint structure */
- typedef struct PSH3_HintRec_* PSH3_Hint;
-
- /* hint bit-flags */
- typedef enum
- {
- PSH3_HINT_GHOST = PS_HINT_FLAG_GHOST,
- PSH3_HINT_BOTTOM = PS_HINT_FLAG_BOTTOM,
- PSH3_HINT_ACTIVE = 4,
- PSH3_HINT_FITTED = 8
-
- } PSH3_Hint_Flags;
-
-
-#define psh3_hint_is_active( x ) ( ( (x)->flags & PSH3_HINT_ACTIVE ) != 0 )
-#define psh3_hint_is_ghost( x ) ( ( (x)->flags & PSH3_HINT_GHOST ) != 0 )
-#define psh3_hint_is_fitted( x ) ( ( (x)->flags & PSH3_HINT_FITTED ) != 0 )
-
-#define psh3_hint_activate( x ) (x)->flags |= PSH3_HINT_ACTIVE
-#define psh3_hint_deactivate( x ) (x)->flags &= ~PSH3_HINT_ACTIVE
-#define psh3_hint_set_fitted( x ) (x)->flags |= PSH3_HINT_FITTED
-
- /* hint structure */
- typedef struct PSH3_HintRec_
- {
- FT_Int org_pos;
- FT_Int org_len;
- FT_Pos cur_pos;
- FT_Pos cur_len;
- FT_UInt flags;
- PSH3_Hint parent;
- FT_Int order;
-
- } PSH3_HintRec;
-
-
- /* this is an interpolation zone used for strong points; */
- /* weak points are interpolated according to their strong */
- /* neighbours */
- typedef struct PSH3_ZoneRec_
- {
- FT_Fixed scale;
- FT_Fixed delta;
- FT_Pos min;
- FT_Pos max;
-
- } PSH3_ZoneRec, *PSH3_Zone;
-
-
- typedef struct PSH3_Hint_TableRec_
- {
- FT_UInt max_hints;
- FT_UInt num_hints;
- PSH3_Hint hints;
- PSH3_Hint* sort;
- PSH3_Hint* sort_global;
- FT_UInt num_zones;
- PSH3_ZoneRec* zones;
- PSH3_Zone zone;
- PS_Mask_Table hint_masks;
- PS_Mask_Table counter_masks;
-
- } PSH3_Hint_TableRec, *PSH3_Hint_Table;
-
-
- typedef struct PSH3_PointRec_* PSH3_Point;
- typedef struct PSH3_ContourRec_* PSH3_Contour;
-
- enum
- {
- PSH3_DIR_NONE = 4,
- PSH3_DIR_UP = -1,
- PSH3_DIR_DOWN = 1,
- PSH3_DIR_LEFT = -2,
- PSH3_DIR_RIGHT = 2
- };
-
-#define PSH3_DIR_HORIZONTAL 2
-#define PSH3_DIR_VERTICAL 1
-
-#define PSH3_DIR_COMPARE( d1, d2 ) ( (d1) == (d2) || (d1) == -(d2) )
-#define PSH3_DIR_IS_HORIZONTAL( d ) PSH3_DIR_COMPARE( d, PSH3_DIR_HORIZONTAL )
-#define PSH3_DIR_IS_VERTICAL( d ) PSH3_DIR_COMPARE( d, PSH3_DIR_VERTICAL )
-
-
- /* the following bit-flags are computed once by the glyph */
- /* analyzer, for both dimensions */
- enum
- {
- PSH3_POINT_OFF = 1, /* point is off the curve */
- PSH3_POINT_SMOOTH = 2, /* point is smooth */
- PSH3_POINT_INFLEX = 4 /* point is inflection */
- };
-
-#define psh3_point_is_smooth( p ) ( (p)->flags & PSH3_POINT_SMOOTH )
-#define psh3_point_is_off( p ) ( (p)->flags & PSH3_POINT_OFF )
-#define psh3_point_is_inflex( p ) ( (p)->flags & PSH3_POINT_INFLEX )
-
-#define psh3_point_set_smooth( p ) (p)->flags |= PSH3_POINT_SMOOTH
-#define psh3_point_set_off( p ) (p)->flags |= PSH3_POINT_OFF
-#define psh3_point_set_inflex( p ) (p)->flags |= PSH3_POINT_INFLEX
-
- /* the following bit-flags are re-computed for each dimension */
- enum
- {
- PSH3_POINT_STRONG = 16, /* point is strong */
- PSH3_POINT_FITTED = 32, /* point is already fitted */
- PSH3_POINT_EXTREMUM = 64, /* point is local extremum */
- PSH3_POINT_POSITIVE = 128, /* extremum has positive contour flow */
- PSH3_POINT_NEGATIVE = 256, /* extremum has negative contour flow */
- PSH3_POINT_EDGE_MIN = 512, /* point is aligned to left/bottom stem edge */
- PSH3_POINT_EDGE_MAX = 1024 /* point is aligned to top/right stem edge */
- };
-
-#define psh3_point_is_strong( p ) ( (p)->flags2 & PSH3_POINT_STRONG )
-#define psh3_point_is_fitted( p ) ( (p)->flags2 & PSH3_POINT_FITTED )
-#define psh3_point_is_extremum( p ) ( (p)->flags2 & PSH3_POINT_EXTREMUM )
-#define psh3_point_is_positive( p ) ( (p)->flags2 & PSH3_POINT_POSITIVE )
-#define psh3_point_is_negative( p ) ( (p)->flags2 & PSH3_POINT_NEGATIVE )
-#define psh3_point_is_edge_min( p ) ( (p)->flags2 & PSH3_POINT_EDGE_MIN )
-#define psh3_point_is_edge_max( p ) ( (p)->flags2 & PSH3_POINT_EDGE_MAX )
-
-#define psh3_point_set_strong( p ) (p)->flags2 |= PSH3_POINT_STRONG
-#define psh3_point_set_fitted( p ) (p)->flags2 |= PSH3_POINT_FITTED
-#define psh3_point_set_extremum( p ) (p)->flags2 |= PSH3_POINT_EXTREMUM
-#define psh3_point_set_positive( p ) (p)->flags2 |= PSH3_POINT_POSITIVE
-#define psh3_point_set_negative( p ) (p)->flags2 |= PSH3_POINT_NEGATIVE
-#define psh3_point_set_edge_min( p ) (p)->flags2 |= PSH3_POINT_EDGE_MIN
-#define psh3_point_set_edge_max( p ) (p)->flags2 |= PSH3_POINT_EDGE_MAX
-
-
- typedef struct PSH3_PointRec_
- {
- PSH3_Point prev;
- PSH3_Point next;
- PSH3_Contour contour;
- FT_UInt flags;
- FT_UInt flags2;
- FT_Char dir_in;
- FT_Char dir_out;
- FT_Angle angle_in;
- FT_Angle angle_out;
- PSH3_Hint hint;
- FT_Pos org_u;
- FT_Pos org_v;
- 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
-
- } PSH3_PointRec;
-
-
-#define PSH3_POINT_EQUAL_ORG( a, b ) ( (a)->org_u == (b)->org_u && \
- (a)->org_v == (b)->org_v )
-
-#define PSH3_POINT_ANGLE( a, b ) FT_Atan2( (b)->org_u - (a)->org_u, \
- (b)->org_v - (a)->org_v )
-
- typedef struct PSH3_ContourRec_
- {
- PSH3_Point start;
- FT_UInt count;
-
- } PSH3_ContourRec;
-
-
- typedef struct PSH3_GlyphRec_
- {
- FT_UInt num_points;
- FT_UInt num_contours;
-
- PSH3_Point points;
- PSH3_Contour contours;
-
- FT_Memory memory;
- FT_Outline* outline;
- PSH_Globals globals;
- PSH3_Hint_TableRec hint_tables[2];
-
- FT_Bool vertical;
- FT_Int major_dir;
- FT_Int minor_dir;
-
- FT_Bool do_horz_hints;
- FT_Bool do_vert_hints;
- FT_Bool do_horz_snapping;
- FT_Bool do_vert_snapping;
- FT_Bool do_stem_adjust;
-
- } PSH3_GlyphRec, *PSH3_Glyph;
-
-
-#ifdef DEBUG_HINTER
- extern PSH3_Hint_Table ps3_debug_hint_table;
-
- typedef void
- (*PSH3_HintFunc)( PSH3_Hint hint,
- FT_Bool vertical );
-
- extern PSH3_HintFunc ps3_debug_hint_func;
-
- extern PSH3_Glyph ps3_debug_glyph;
-#endif
-
-
- extern FT_Error
- ps3_hints_apply( PS_Hints ps_hints,
- FT_Outline* outline,
- PSH_Globals globals,
- FT_Render_Mode hint_mode );
-
-
-FT_END_HEADER
-
-
-#endif /* __PSHALGO3_H__ */
-
-
-/* END */
--- a/src/pshinter/pshglob.c
+++ b/src/pshinter/pshglob.c
@@ -5,7 +5,7 @@
/* PostScript hinter global hinting management (body). */
/* Inspired by the new auto-hinter module. */
/* */
-/* Copyright 2001, 2002 by */
+/* Copyright 2001, 2002, 2003 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used */
@@ -78,6 +78,8 @@
}
+#if 0
+
/* org_width is is font units, result in device pixels, 26.6 format */
FT_LOCAL_DEF( FT_Pos )
psh_dimension_snap_width( PSH_Dimension dimension,
@@ -121,6 +123,8 @@
return width;
}
+
+#endif /* 0 */
/*************************************************************************/
--- a/src/pshinter/pshglob.h
+++ b/src/pshinter/pshglob.h
@@ -4,7 +4,7 @@
/* */
/* PostScript hinter global hinting management. */
/* */
-/* Copyright 2001, 2002 by */
+/* Copyright 2001, 2002, 2003 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -159,11 +159,13 @@
psh_globals_funcs_init( PSH_Globals_FuncsRec* funcs );
+#if 0
/* snap a stem width to fitter coordinates. `org_width' is in font */
/* units. The result is in device pixels (26.6 format). */
FT_LOCAL( FT_Pos )
psh_dimension_snap_width( PSH_Dimension dimension,
FT_Int org_width );
+#endif
/* snap a stem to one or two blue zones */
FT_LOCAL( void )
--- a/src/pshinter/pshinter.c
+++ b/src/pshinter/pshinter.c
@@ -4,7 +4,7 @@
/* */
/* FreeType PostScript Hinting module */
/* */
-/* Copyright 2001 by */
+/* Copyright 2001, 2003 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -21,9 +21,7 @@
#include <ft2build.h>
#include "pshrec.c"
#include "pshglob.c"
-#include "pshalgo1.c"
-#include "pshalgo2.c"
-#include "pshalgo3.c"
+#include "pshalgo.c"
#include "pshmod.c"
--- a/src/pshinter/pshrec.c
+++ b/src/pshinter/pshrec.c
@@ -4,7 +4,7 @@
/* */
/* FreeType PostScript hints recorder (body). */
/* */
-/* Copyright 2001, 2002 by */
+/* Copyright 2001, 2002, 2003 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -1139,7 +1139,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_FUNC;
+ funcs->apply = (T1_Hints_ApplyFunc) ps_hints_apply;
}
@@ -1204,7 +1204,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_FUNC;
+ funcs->apply = (T2_Hints_ApplyFunc) ps_hints_apply;
}
--- a/src/pshinter/rules.mk
+++ b/src/pshinter/rules.mk
@@ -26,12 +26,10 @@
# PSHINTER driver sources (i.e., C files)
#
-PSHINTER_DRV_SRC := $(PSHINTER_DIR_)pshrec.c \
- $(PSHINTER_DIR_)pshglob.c \
- $(PSHINTER_DIR_)pshmod.c \
- $(PSHINTER_DIR_)pshalgo1.c \
- $(PSHINTER_DIR_)pshalgo2.c \
- $(PSHINTER_DIR_)pshalgo3.c
+PSHINTER_DRV_SRC := $(PSHINTER_DIR_)pshrec.c \
+ $(PSHINTER_DIR_)pshglob.c \
+ $(PSHINTER_DIR_)pshmod.c \
+ $(PSHINTER_DIR_)pshalgo.c
# PSHINTER driver headers
--- a/tests/gview.c
+++ b/tests/gview.c
@@ -7,9 +7,7 @@
/* include FreeType internals to debug hints */
#include <../src/pshinter/pshrec.h>
-#include <../src/pshinter/pshalgo1.h>
-#include <../src/pshinter/pshalgo2.h>
-#include <../src/pshinter/pshalgo3.h>
+#include <../src/pshinter/pshalgo.h>
#include <../src/autohint/ahtypes.h>
@@ -358,122 +356,20 @@
}
}
- /************************************************************************/
- /************************************************************************/
- /***** *****/
- /***** POSTSCRIPT HINTER ALGORITHM 1 ROUTINES *****/
- /***** *****/
- /************************************************************************/
- /************************************************************************/
-#include <../src/pshinter/pshalgo1.h>
-
-static int pshint_cpos = 0;
-static int pshint_vertical = -1;
-
-static void
-draw_ps1_hint( PSH1_Hint hint, FT_Bool vertical )
-{
- int x1, x2;
- NV_Vector v;
-
-
- if ( pshint_vertical != vertical )
- {
- if (vertical)
- pshint_cpos = 40;
- else
- pshint_cpos = 10;
-
- pshint_vertical = vertical;
- }
-
- if (vertical)
- {
- if ( !option_show_vert_hints )
- return;
-
- v.x = hint->cur_pos;
- v.y = 0;
- nv_vector_transform( &v, &size_transform );
- 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,
- 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 *****/
+ /***** POSTSCRIPT HINTER ALGORITHM ROUTINES *****/
/***** *****/
/************************************************************************/
/************************************************************************/
-#include <../src/pshinter/pshalgo2.h>
+#include <../src/pshinter/pshalgo.h>
static void
-draw_ps2_hint( PSH2_Hint hint, FT_Bool vertical )
+draw_ps_hint( PSH_Hint hint,
+ FT_Bool vertical )
{
int x1, x2;
NV_Vector v;
@@ -488,155 +384,6 @@
pshint_vertical = vertical;
}
- if (vertical)
- {
- if ( !option_show_vert_hints )
- return;
-
- v.x = hint->cur_pos;
- v.y = 0;
- nv_vector_transform( &v, &size_transform );
- x1 = (int)(v.x + 0.5);
-
- v.x = hint->cur_pos + hint->cur_len;
- v.y = 0;
- nv_vector_transform( &v, &size_transform );
- x2 = (int)(v.x + 0.5);
-
- nv_pixmap_fill_rect( target, x1, 0, 1, target->height,
- psh2_hint_is_ghost(hint)
- ? GHOST_HINT_COLOR : STEM_HINT_COLOR );
-
- if ( psh2_hint_is_ghost(hint) )
- {
- x1 --;
- x2 = x1 + 2;
- }
- else
- nv_pixmap_fill_rect( target, x2, 0, 1, target->height,
- psh2_hint_is_ghost(hint)
- ? GHOST_HINT_COLOR : STEM_HINT_COLOR );
-
- nv_pixmap_fill_rect( target, x1, pshint_cpos, x2+1-x1, 1,
- STEM_JOIN_COLOR );
- }
- else
- {
- if (!option_show_horz_hints)
- return;
-
- v.y = hint->cur_pos;
- v.x = 0;
- nv_vector_transform( &v, &size_transform );
- x1 = (int)(v.y + 0.5);
-
- v.y = hint->cur_pos + hint->cur_len;
- v.x = 0;
- nv_vector_transform( &v, &size_transform );
- x2 = (int)(v.y + 0.5);
-
- nv_pixmap_fill_rect( target, 0, x1, target->width, 1,
- psh2_hint_is_ghost(hint)
- ? GHOST_HINT_COLOR : STEM_HINT_COLOR );
-
- if ( psh2_hint_is_ghost(hint) )
- {
- x1 --;
- x2 = x1 + 2;
- }
- else
- nv_pixmap_fill_rect( target, 0, x2, target->width, 1,
- psh2_hint_is_ghost(hint)
- ? GHOST_HINT_COLOR : STEM_HINT_COLOR );
-
- nv_pixmap_fill_rect( target, pshint_cpos, x2, 1, x1+1-x2,
- STEM_JOIN_COLOR );
- }
-
-#if 0
- printf( "[%7.3f %7.3f] %c\n", hint->cur_pos/64.0, (hint->cur_pos+hint->cur_len)/64.0, vertical ? 'v' : 'h' );
-#endif
-
- pshint_cpos += 10;
-}
-
-
-static void
-ps2_draw_control_points( void )
-{
- if ( ps2_debug_glyph )
- {
- PSH2_Glyph glyph = ps2_debug_glyph;
- PSH2_Point point = glyph->points;
- FT_UInt count = glyph->num_points;
- NV_Transform transform, *trans = &transform;
- NV_Path vert_rect;
- NV_Path horz_rect;
- NV_Path dot, circle;
-
- 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, symbol_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, symbol_rect_h );
- }
- }
-
- 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, symbol_rect_v );
- }
- }
- }
- }
-}
-
- /************************************************************************/
- /************************************************************************/
- /***** *****/
- /***** POSTSCRIPT HINTER ALGORITHM 3 ROUTINES *****/
- /***** *****/
- /************************************************************************/
- /************************************************************************/
-
-#include <../src/pshinter/pshalgo3.h>
-
-static void
-draw_ps3_hint( PSH3_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 )
@@ -653,10 +400,10 @@
x2 = (int)(v.x + 0.5);
nv_pixmap_fill_rect( target, x1, 0, 1, target->height,
- psh3_hint_is_ghost(hint)
+ psh_hint_is_ghost( hint )
? GHOST_HINT_COLOR : STEM_HINT_COLOR );
- if ( psh3_hint_is_ghost(hint) )
+ if ( psh_hint_is_ghost( hint ) )
{
x1 --;
x2 = x1 + 2;
@@ -663,7 +410,7 @@
}
else
nv_pixmap_fill_rect( target, x2, 0, 1, target->height,
- psh3_hint_is_ghost(hint)
+ psh_hint_is_ghost( hint )
? GHOST_HINT_COLOR : STEM_HINT_COLOR );
nv_pixmap_fill_rect( target, x1, pshint_cpos, x2+1-x1, 1,
@@ -685,10 +432,10 @@
x2 = (int)(v.y + 0.5);
nv_pixmap_fill_rect( target, 0, x1, target->width, 1,
- psh3_hint_is_ghost(hint)
+ psh_hint_is_ghost( hint )
? GHOST_HINT_COLOR : STEM_HINT_COLOR );
- if ( psh3_hint_is_ghost(hint) )
+ if ( psh_hint_is_ghost(hint) )
{
x1 --;
x2 = x1 + 2;
@@ -695,7 +442,7 @@
}
else
nv_pixmap_fill_rect( target, 0, x2, target->width, 1,
- psh3_hint_is_ghost(hint)
+ psh_hint_is_ghost(hint)
? GHOST_HINT_COLOR : STEM_HINT_COLOR );
nv_pixmap_fill_rect( target, pshint_cpos, x2, 1, x1+1-x2,
@@ -711,12 +458,12 @@
static void
-ps3_draw_control_points( void )
+ps_draw_control_points( void )
{
- if ( ps3_debug_glyph )
+ if ( ps_debug_glyph )
{
- PSH3_Glyph glyph = ps3_debug_glyph;
- PSH3_Point point = glyph->points;
+ PSH_Glyph glyph = ps_debug_glyph;
+ PSH_Point point = glyph->points;
FT_UInt count = glyph->num_points;
NV_Transform transform, *trans = &transform;
NV_Path vert_rect;
@@ -733,7 +480,7 @@
nv_transform_set_translate( trans, vec.x, vec.y );
- if ( option_show_smooth && !psh3_point_is_smooth(point) )
+ if ( option_show_smooth && !psh_point_is_smooth(point) )
{
nv_painter_set_color( painter, SMOOTH_COLOR, 256 );
nv_painter_fill_path( painter, trans, 0, symbol_circle );
@@ -741,7 +488,7 @@
if (option_show_horz_hints)
{
- if ( point->flags_y & PSH3_POINT_STRONG )
+ if ( point->flags_y & PSH_POINT_STRONG )
{
nv_painter_set_color( painter, STRONG_COLOR, 256 );
nv_painter_fill_path( painter, trans, 0, symbol_rect_h );
@@ -750,7 +497,7 @@
if (option_show_vert_hints)
{
- if ( point->flags_x & PSH3_POINT_STRONG )
+ if ( point->flags_x & PSH_POINT_STRONG )
{
nv_painter_set_color( painter, STRONG_COLOR, 256 );
nv_painter_fill_path( painter, trans, 0, symbol_rect_v );
@@ -1104,9 +851,7 @@
pshint_vertical = -1;
- ps1_debug_hint_func = option_show_ps_hints ? draw_ps1_hint : 0;
- ps2_debug_hint_func = option_show_ps_hints ? draw_ps2_hint : 0;
- ps3_debug_hint_func = option_show_ps_hints ? draw_ps3_hint : 0;
+ ps_debug_hint_func = option_show_ps_hints ? draw_ps_hint : 0;
ah_debug_hinter = NULL;