/***************************************************************************//* *//* ahhint.c *//* *//* Glyph hinter (body). *//* *//* Copyright 2000-2001, 2002 Catharon Productions Inc. *//* Author: David Turner *//* *//* This file is part of the Catharon Typography Project and shall only *//* be used, modified, and distributed under the terms of the Catharon *//* Open Source License that should come with this file under the name *//* `CatharonLicense.txt'. By continuing to use, modify, or distribute *//* this file you indicate that you have read the license and *//* understand and accept it fully. *//* *//* Note that this license is compatible with the FreeType license. *//* *//***************************************************************************/ #include <ft2build.h>#include "ahhint.h"#include "ahglyph.h"#include "ahangles.h"#include "aherrors.h"#include FT_OUTLINE_H #define FACE_GLOBALS( face ) ((AH_Face_Globals)(face)->autohint.data) #define AH_USE_IUP#define OPTIM_STEM_SNAP /*************************************************************************/ /*************************************************************************/ /**** ****/ /**** Hinting routines ****/ /**** ****/ /*************************************************************************/ /*************************************************************************/ /* snap a given width in scaled coordinates to one of the */ /* current standard widths */ static FT_Pos ah_snap_width( FT_Pos* widths, FT_Int count, FT_Pos width ) { int n; FT_Pos best = 64 + 32 + 2; FT_Pos reference = width; FT_Pos scaled; for ( n = 0; n < count; n++ ) { FT_Pos w; FT_Pos dist; w = widths[n]; dist = width - w; if ( dist < 0 ) dist = -dist; if ( dist < best ) { best = dist; reference = w; } } scaled = (reference+32) & -64; if ( width >= reference ) { if ( width < scaled + 48 ) width = reference; } else { if ( width > scaled - 48 ) width = reference; } return width; } /* compute the snapped width of a given stem */ static FT_Pos ah_compute_stem_width( AH_Hinter hinter, int vertical, FT_Pos width ) { AH_Globals globals = &hinter->globals->scaled; FT_Pos dist = width; FT_Int sign = 0; if ( dist < 0 ) { dist = -width; sign = 1; } if ( ( vertical && !hinter->do_vert_snapping ) || ( !vertical && !hinter->do_horz_snapping ) ) { /* smooth hinting process, very lightly quantize the stem width */ /* */ if ( dist < 64 ) dist = 64; { FT_Pos delta = dist - globals->stds[vertical]; if ( delta < 0 ) delta = -delta; if ( delta < 40 ) { dist = globals->stds[vertical]; if ( dist < 48 ) dist = 48; } if ( dist < 3 * 64 ) { delta = ( dist & 63 ); dist &= -64; if ( delta < 10 ) dist += delta; else if ( delta < 32 ) dist += 10; else if ( delta < 54 ) dist += 54; else dist += delta; } else dist = ( dist + 32 ) & -64; } } else { /* strong hinting process, snap the stem width to integer pixels */ /* */ if ( vertical ) { dist = ah_snap_width( globals->heights, globals->num_heights, dist ); /* in the case of vertical hinting, always round */ /* the stem heights to integer pixels */ if ( dist >= 64 ) dist = ( dist + 16 ) & -64; else dist = 64; } else { dist = ah_snap_width( globals->widths, globals->num_widths, dist ); if ( hinter->flags & AH_HINTER_MONOCHROME ) { /* monochrome horizontal hinting: snap widths to integer pixels */ /* with a different threshold */ if ( dist < 64 ) dist = 64; else dist = ( dist + 32 ) & -64; } else { /* for horizontal anti-aliased hinting, we adopt a more subtle */ /* approach: we strengthen small stems, round stems whose size */ /* is between 1 and 2 pixels to an integer, otherwise nothing */ if ( dist < 48 ) dist = ( dist + 64 ) >> 1; else if ( dist < 128 ) dist = ( dist + 22 ) & -64; else /* XXX: round otherwise, prevent color fringes in LCD mode */ dist = ( dist + 32 ) & -64; } } } if ( sign ) dist = -dist; return dist; } /* align one stem edge relative to the previous stem edge */ static void ah_align_linked_edge( AH_Hinter hinter, AH_Edge base_edge, AH_Edge stem_edge, int vertical ) { FT_Pos dist = stem_edge->opos - base_edge->opos; stem_edge->pos = base_edge->pos + ah_compute_stem_width( hinter, vertical, dist ); } static void ah_align_serif_edge( AH_Hinter hinter, AH_Edge base, AH_Edge serif, int vertical ) { FT_Pos dist; FT_Pos sign = 1; FT_UNUSED( hinter ); dist = serif->opos - base->opos; if ( dist < 0 ) { dist = -dist; sign = -1; } /* do not touch serifs widths !! */#if 0 if ( base->flags & AH_EDGE_DONE ) { if ( dist >= 64 ) dist = (dist+8) & -64; else if ( dist <= 32 && !vertical ) dist = ( dist + 33 ) >> 1; else dist = 0; }#endif serif->pos = base->pos + sign * dist; } /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ /**** ****/ /**** E D G E H I N T I N G ****/ /**** ****/ /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ /* Another alternative edge hinting algorithm */ static void ah_hint_edges_3( AH_Hinter hinter ) { AH_Edge edges; AH_Edge edge_limit; AH_Outline outline = hinter->glyph; FT_Int dimension; edges = outline->horz_edges; edge_limit = edges + outline->num_hedges; for ( dimension = 1; dimension >= 0; dimension-- ) { AH_Edge edge; AH_Edge anchor = 0; int has_serifs = 0; if ( !hinter->do_horz_hints && !dimension ) goto Next_Dimension; if ( !hinter->do_vert_hints && dimension ) goto Next_Dimension; /* we begin by aligning all stems relative to the blue zone */ /* if needed -- that's only for horizontal edges */ if ( dimension ) { for ( edge = edges; edge < edge_limit; edge++ ) { FT_Pos* blue; AH_EdgeRec *edge1, *edge2; if ( edge->flags & AH_EDGE_DONE ) continue; blue = edge->blue_edge; edge1 = 0; edge2 = edge->link; if ( blue ) { edge1 = edge; } else if (edge2 && edge2->blue_edge) { blue = edge2->blue_edge; edge1 = edge2; edge2 = edge; } if ( !edge1 ) continue; edge1->pos = blue[0]; edge1->flags |= AH_EDGE_DONE; if ( edge2 && !edge2->blue_edge ) { ah_align_linked_edge( hinter, edge1, edge2, dimension ); edge2->flags |= AH_EDGE_DONE; } if ( !anchor ) anchor = edge; } } /* now, we will align all stem edges, trying to maintain the */ /* relative order of stems in the glyph.. */ for ( edge = edges; edge < edge_limit; edge++ ) { AH_EdgeRec* edge2; if ( edge->flags & AH_EDGE_DONE ) continue; /* skip all non-stem edges */ edge2 = edge->link; if ( !edge2 ) { has_serifs++; continue; } /* now, align the stem */ /* this should not happen, but it's better to be safe. */ if ( edge2->blue_edge || edge2 < edge ) { ah_align_linked_edge( hinter, edge2, edge, dimension ); edge->flags |= AH_EDGE_DONE; continue; } if ( !anchor ) { edge->pos = ( edge->opos + 32 ) & -64; anchor = edge; edge->flags |= AH_EDGE_DONE; ah_align_linked_edge( hinter, edge, edge2, dimension ); } else { FT_Pos org_pos, org_len, org_center, cur_len; FT_Pos cur_pos1, cur_pos2, delta1, delta2; org_pos = anchor->pos + (edge->opos - anchor->opos); org_len = edge2->opos - edge->opos; org_center = org_pos + ( org_len >> 1 ); cur_len = ah_compute_stem_width( hinter, dimension, org_len ); cur_pos1 = ( org_pos + 32 ) & -64; delta1 = ( cur_pos1 + ( cur_len >> 1 ) - org_center ); if ( delta1 < 0 ) delta1 = -delta1; cur_pos2 = ( ( org_pos + org_len + 32 ) & -64 ) - cur_len; delta2 = ( cur_pos2 + ( cur_len >> 1 ) - org_center ); if ( delta2 < 0 ) delta2 = -delta2; edge->pos = ( delta1 <= delta2 ) ? cur_pos1 : cur_pos2; edge2->pos = edge->pos + cur_len; edge->flags |= AH_EDGE_DONE; edge2->flags |= AH_EDGE_DONE; if ( edge > edges && edge->pos < edge[-1].pos ) edge->pos = edge[-1].pos; } } if ( !has_serifs ) goto Next_Dimension; /* now, hint the remaining edges (serifs and single) in order */ /* to complete our processing */ for ( edge = edges; edge < edge_limit; edge++ ) { if ( edge->flags & AH_EDGE_DONE ) continue; if ( edge->serif ) ah_align_serif_edge( hinter, edge->serif, edge, dimension ); else if ( !anchor ) { edge->pos = ( edge->opos + 32 ) & -64; anchor = edge; } else edge->pos = anchor->pos + ( ( edge->opos-anchor->opos + 32 ) & -64 ); edge->flags |= AH_EDGE_DONE; if ( edge > edges && edge->pos < edge[-1].pos ) edge->pos = edge[-1].pos; if ( edge + 1 < edge_limit && edge[1].flags & AH_EDGE_DONE && edge->pos > edge[1].pos ) edge->pos = edge[1].pos; } Next_Dimension: edges = outline->vert_edges; edge_limit = edges + outline->num_vedges; } } FT_LOCAL_DEF( void ) ah_hinter_hint_edges( AH_Hinter hinter ) { /* AH_Interpolate_Blue_Edges( hinter ); -- doesn't seem to help */ /* reduce the problem of the disappearing eye in the `e' of Times... */ /* also, creates some artifacts near the blue zones? */ { ah_hint_edges_3( hinter ); } } /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ /**** ****/ /**** P O I N T H I N T I N G ****/ /**** ****/ /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ static void ah_hinter_align_edge_points( AH_Hinter hinter ) { AH_Outline outline = hinter->glyph; AH_Edge edges; AH_Edge edge_limit; FT_Int dimension; edges = outline->horz_edges; edge_limit = edges + outline->num_hedges; for ( dimension = 1; dimension >= 0; dimension-- ) { AH_Edge edge; edge = edges; for ( ; edge < edge_limit; edge++ ) { /* move the points of each segment */ /* in each edge to the edge's position */ AH_Segment seg = edge->first; do { AH_Point point = seg->first; for (;;) { if ( dimension )Lines 1–500 of 1493. Load more
/***************************************************************************/ /* */ /* ahhint.c */ /* */ /* Glyph hinter (body). */ /* */ /* Copyright 2000-2001, 2002 Catharon Productions Inc. */ /* Author: David Turner */ /* */ /* This file is part of the Catharon Typography Project and shall only */ /* be used, modified, and distributed under the terms of the Catharon */ /* Open Source License that should come with this file under the name */ /* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ /* this file you indicate that you have read the license and */ /* understand and accept it fully. */ /* */ /* Note that this license is compatible with the FreeType license. */ /* */ /***************************************************************************/ #include <ft2build.h> #include "ahhint.h" #include "ahglyph.h" #include "ahangles.h" #include "aherrors.h" #include FT_OUTLINE_H #define FACE_GLOBALS( face ) ((AH_Face_Globals)(face)->autohint.data) #define AH_USE_IUP #define OPTIM_STEM_SNAP /*************************************************************************/ /*************************************************************************/ /**** ****/ /**** Hinting routines ****/ /**** ****/ /*************************************************************************/ /*************************************************************************/ /* snap a given width in scaled coordinates to one of the */ /* current standard widths */ static FT_Pos ah_snap_width( FT_Pos* widths, FT_Int count, FT_Pos width ) { int n; FT_Pos best = 64 + 32 + 2; FT_Pos reference = width; FT_Pos scaled; for ( n = 0; n < count; n++ ) { FT_Pos w; FT_Pos dist; w = widths[n]; dist = width - w; if ( dist < 0 ) dist = -dist; if ( dist < best ) { best = dist; reference = w; } } scaled = (reference+32) & -64; if ( width >= reference ) { if ( width < scaled + 48 ) width = reference; } else { if ( width > scaled - 48 ) width = reference; } return width; } /* compute the snapped width of a given stem */ static FT_Pos ah_compute_stem_width( AH_Hinter hinter, int vertical, FT_Pos width ) { AH_Globals globals = &hinter->globals->scaled; FT_Pos dist = width; FT_Int sign = 0; if ( dist < 0 ) { dist = -width; sign = 1; } if ( ( vertical && !hinter->do_vert_snapping ) || ( !vertical && !hinter->do_horz_snapping ) ) { /* smooth hinting process, very lightly quantize the stem width */ /* */ if ( dist < 64 ) dist = 64; { FT_Pos delta = dist - globals->stds[vertical]; if ( delta < 0 ) delta = -delta; if ( delta < 40 ) { dist = globals->stds[vertical]; if ( dist < 48 ) dist = 48; } if ( dist < 3 * 64 ) { delta = ( dist & 63 ); dist &= -64; if ( delta < 10 ) dist += delta; else if ( delta < 32 ) dist += 10; else if ( delta < 54 ) dist += 54; else dist += delta; } else dist = ( dist + 32 ) & -64; } } else { /* strong hinting process, snap the stem width to integer pixels */ /* */ if ( vertical ) { dist = ah_snap_width( globals->heights, globals->num_heights, dist ); /* in the case of vertical hinting, always round */ /* the stem heights to integer pixels */ if ( dist >= 64 ) dist = ( dist + 16 ) & -64; else dist = 64; } else { dist = ah_snap_width( globals->widths, globals->num_widths, dist ); if ( hinter->flags & AH_HINTER_MONOCHROME ) { /* monochrome horizontal hinting: snap widths to integer pixels */ /* with a different threshold */ if ( dist < 64 ) dist = 64; else dist = ( dist + 32 ) & -64; } else { /* for horizontal anti-aliased hinting, we adopt a more subtle */ /* approach: we strengthen small stems, round stems whose size */ /* is between 1 and 2 pixels to an integer, otherwise nothing */ if ( dist < 48 ) dist = ( dist + 64 ) >> 1; else if ( dist < 128 ) dist = ( dist + 22 ) & -64; else /* XXX: round otherwise, prevent color fringes in LCD mode */ dist = ( dist + 32 ) & -64; } } } if ( sign ) dist = -dist; return dist; } /* align one stem edge relative to the previous stem edge */ static void ah_align_linked_edge( AH_Hinter hinter, AH_Edge base_edge, AH_Edge stem_edge, int vertical ) { FT_Pos dist = stem_edge->opos - base_edge->opos; stem_edge->pos = base_edge->pos + ah_compute_stem_width( hinter, vertical, dist ); } static void ah_align_serif_edge( AH_Hinter hinter, AH_Edge base, AH_Edge serif, int vertical ) { FT_Pos dist; FT_Pos sign = 1; FT_UNUSED( hinter ); dist = serif->opos - base->opos; if ( dist < 0 ) { dist = -dist; sign = -1; } /* do not touch serifs widths !! */ #if 0 if ( base->flags & AH_EDGE_DONE ) { if ( dist >= 64 ) dist = (dist+8) & -64; else if ( dist <= 32 && !vertical ) dist = ( dist + 33 ) >> 1; else dist = 0; } #endif serif->pos = base->pos + sign * dist; } /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ /**** ****/ /**** E D G E H I N T I N G ****/ /**** ****/ /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ /* Another alternative edge hinting algorithm */ static void ah_hint_edges_3( AH_Hinter hinter ) { AH_Edge edges; AH_Edge edge_limit; AH_Outline outline = hinter->glyph; FT_Int dimension; edges = outline->horz_edges; edge_limit = edges + outline->num_hedges; for ( dimension = 1; dimension >= 0; dimension-- ) { AH_Edge edge; AH_Edge anchor = 0; int has_serifs = 0; if ( !hinter->do_horz_hints && !dimension ) goto Next_Dimension; if ( !hinter->do_vert_hints && dimension ) goto Next_Dimension; /* we begin by aligning all stems relative to the blue zone */ /* if needed -- that's only for horizontal edges */ if ( dimension ) { for ( edge = edges; edge < edge_limit; edge++ ) { FT_Pos* blue; AH_EdgeRec *edge1, *edge2; if ( edge->flags & AH_EDGE_DONE ) continue; blue = edge->blue_edge; edge1 = 0; edge2 = edge->link; if ( blue ) { edge1 = edge; } else if (edge2 && edge2->blue_edge) { blue = edge2->blue_edge; edge1 = edge2; edge2 = edge; } if ( !edge1 ) continue; edge1->pos = blue[0]; edge1->flags |= AH_EDGE_DONE; if ( edge2 && !edge2->blue_edge ) { ah_align_linked_edge( hinter, edge1, edge2, dimension ); edge2->flags |= AH_EDGE_DONE; } if ( !anchor ) anchor = edge; } } /* now, we will align all stem edges, trying to maintain the */ /* relative order of stems in the glyph.. */ for ( edge = edges; edge < edge_limit; edge++ ) { AH_EdgeRec* edge2; if ( edge->flags & AH_EDGE_DONE ) continue; /* skip all non-stem edges */ edge2 = edge->link; if ( !edge2 ) { has_serifs++; continue; } /* now, align the stem */ /* this should not happen, but it's better to be safe. */ if ( edge2->blue_edge || edge2 < edge ) { ah_align_linked_edge( hinter, edge2, edge, dimension ); edge->flags |= AH_EDGE_DONE; continue; } if ( !anchor ) { edge->pos = ( edge->opos + 32 ) & -64; anchor = edge; edge->flags |= AH_EDGE_DONE; ah_align_linked_edge( hinter, edge, edge2, dimension ); } else { FT_Pos org_pos, org_len, org_center, cur_len; FT_Pos cur_pos1, cur_pos2, delta1, delta2; org_pos = anchor->pos + (edge->opos - anchor->opos); org_len = edge2->opos - edge->opos; org_center = org_pos + ( org_len >> 1 ); cur_len = ah_compute_stem_width( hinter, dimension, org_len ); cur_pos1 = ( org_pos + 32 ) & -64; delta1 = ( cur_pos1 + ( cur_len >> 1 ) - org_center ); if ( delta1 < 0 ) delta1 = -delta1; cur_pos2 = ( ( org_pos + org_len + 32 ) & -64 ) - cur_len; delta2 = ( cur_pos2 + ( cur_len >> 1 ) - org_center ); if ( delta2 < 0 ) delta2 = -delta2; edge->pos = ( delta1 <= delta2 ) ? cur_pos1 : cur_pos2; edge2->pos = edge->pos + cur_len; edge->flags |= AH_EDGE_DONE; edge2->flags |= AH_EDGE_DONE; if ( edge > edges && edge->pos < edge[-1].pos ) edge->pos = edge[-1].pos; } } if ( !has_serifs ) goto Next_Dimension; /* now, hint the remaining edges (serifs and single) in order */ /* to complete our processing */ for ( edge = edges; edge < edge_limit; edge++ ) { if ( edge->flags & AH_EDGE_DONE ) continue; if ( edge->serif ) ah_align_serif_edge( hinter, edge->serif, edge, dimension ); else if ( !anchor ) { edge->pos = ( edge->opos + 32 ) & -64; anchor = edge; } else edge->pos = anchor->pos + ( ( edge->opos-anchor->opos + 32 ) & -64 ); edge->flags |= AH_EDGE_DONE; if ( edge > edges && edge->pos < edge[-1].pos ) edge->pos = edge[-1].pos; if ( edge + 1 < edge_limit && edge[1].flags & AH_EDGE_DONE && edge->pos > edge[1].pos ) edge->pos = edge[1].pos; } Next_Dimension: edges = outline->vert_edges; edge_limit = edges + outline->num_vedges; } } FT_LOCAL_DEF( void ) ah_hinter_hint_edges( AH_Hinter hinter ) { /* AH_Interpolate_Blue_Edges( hinter ); -- doesn't seem to help */ /* reduce the problem of the disappearing eye in the `e' of Times... */ /* also, creates some artifacts near the blue zones? */ { ah_hint_edges_3( hinter ); } } /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ /**** ****/ /**** P O I N T H I N T I N G ****/ /**** ****/ /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ static void ah_hinter_align_edge_points( AH_Hinter hinter ) { AH_Outline outline = hinter->glyph; AH_Edge edges; AH_Edge edge_limit; FT_Int dimension; edges = outline->horz_edges; edge_limit = edges + outline->num_hedges; for ( dimension = 1; dimension >= 0; dimension-- ) { AH_Edge edge; edge = edges; for ( ; edge < edge_limit; edge++ ) { /* move the points of each segment */ /* in each edge to the edge's position */ AH_Segment seg = edge->first; do { AH_Point point = seg->first; for (;;) { if ( dimension )