?? ahhint.c
字號:
/***************************************************************************//* *//* 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 /*************************************************************************/ /*************************************************************************/ /**** ****/ /**** 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; 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; } } if ( width >= reference ) { width -= 0x21; if ( width < reference ) width = reference; } else { width += 0x21; if ( width > reference ) width = reference; } return width; } /* 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; AH_Globals* globals = &hinter->globals->scaled; FT_Pos sign = 1; if ( dist < 0 ) { dist = -dist; sign = -1; } 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 + 42 ) & -64; else /* XXX: round otherwise, prevent color fringes in LCD mode */ dist = ( dist + 32 ) & -64; } } stem_edge->pos = base_edge->pos + sign * 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 strengthen serifs */ 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; } 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 ( ah_debug_disable_vert && !dimension ) goto Next_Dimension; if ( ah_debug_disable_horz && 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_Edge *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_Edge *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 ) {#if 0 printf( "strange blue alignement, edge %d to %d\n", edge - edges, edge2 - edges );#endif ah_align_linked_edge( hinter, edge2, edge, dimension ); edge->flags |= ah_edge_done; continue; } { FT_Bool min = 0; FT_Pos delta; 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; min = 1; } ah_align_linked_edge( hinter, edge, edge2, dimension ); delta = 0; if ( edge2 + 1 < edge_limit && edge2[1].flags & ah_edge_done ) delta = edge2[1].pos - edge2->pos; if ( delta < 0 ) { edge2->pos += delta; if ( !min ) edge->pos += delta; } edge2->flags |= ah_edge_done; } } 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, FT_Bool no_horz_edges, FT_Bool no_vert_edges ) {#if 0 ah_debug_disable_horz = no_horz_edges; ah_debug_disable_vert = no_vert_edges;#else FT_UNUSED( no_horz_edges ); FT_UNUSED( no_vert_edges );#endif /* 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 );#if 0 /* outline optimizer removed temporarily */ if ( hinter->flags & ah_hinter_optimize ) { AH_Optimizer opt; if ( !AH_Optimizer_Init( &opt, hinter->glyph, hinter->memory ) ) { AH_Optimizer_Compute( &opt ); AH_Optimizer_Done( &opt ); } }#endif } } /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ /**** ****/ /**** 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 ) { point->y = edge->pos; point->flags |= ah_flag_touch_y; } else { point->x = edge->pos; point->flags |= ah_flag_touch_x; } if ( point == seg->last ) break; point = point->next; } seg = seg->edge_next;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -