📄 ahhint.c
字号:
/***************************************************************************//* *//* ahhint.c *//* *//* Glyph hinter (body). *//* *//* Copyright 2000-2001, 2002, 2003 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 */#ifdef FT_CONFIG_CHESTER_SERIF static FT_Pos ah_compute_stem_width( AH_Hinter hinter, int vertical, FT_Pos width, AH_Edge_Flags base_flags, AH_Edge_Flags stem_flags ) { AH_Globals globals = &hinter->globals->scaled; FT_Pos dist = width; FT_Int sign = 0; if ( dist < 0 ) { dist = -width; sign = 1; } if ( !hinter->do_stem_adjust ) { /* leave stem widths unchanged */ } else if ( ( vertical && !hinter->do_vert_snapping ) || ( !vertical && !hinter->do_horz_snapping ) ) { /* smooth hinting process: very lightly quantize the stem width */ /* */ /* leave the widths of serifs alone */ if ( ( stem_flags & AH_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) ) goto Done_Width; else if ( ( base_flags & AH_EDGE_ROUND ) ) { if ( dist < 80 ) dist = 64; } else if ( dist < 56 ) dist = 56; { FT_Pos delta = dist - globals->stds[vertical]; if ( delta < 0 ) delta = -delta; if ( delta < 40 ) { dist = globals->stds[vertical]; if ( dist < 48 ) dist = 48; goto Done_Width; } 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 to prevent color fringes in LCD mode */ dist = ( dist + 32 ) & -64; } } } Done_Width: if ( sign ) dist = -dist; return dist; }#else /* !FT_CONFIG_CHESTER_SERIF */ 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 ( !hinter->do_stem_adjust ) { /* leave stem widths unchanged */ } else 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 to prevent color fringes in LCD mode */ dist = ( dist + 32 ) & -64; } } } if ( sign ) dist = -dist; return dist; }#endif /* !FT_CONFIG_CHESTER_SERIF */ /* 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;#ifdef FT_CONFIG_CHESTER_SERIF FT_Pos fitted_width = ah_compute_stem_width( hinter, vertical, dist, base_edge->flags, stem_edge->flags ); stem_edge->pos = base_edge->pos + fitted_width;#else stem_edge->pos = base_edge->pos + ah_compute_stem_width( hinter, vertical, dist );#endif } 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 ); FT_UNUSED( vertical ); dist = serif->opos - base->opos; if ( dist < 0 ) { dist = -dist; sign = -1; }#if 0 /* do not touch serifs widths! */ 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 ****/ /**** ****/ /*************************************************************************/ /*************************************************************************/ /*************************************************************************/ FT_LOCAL_DEF( void ) ah_hinter_hint_edges( AH_Hinter hinter ) { AH_Edge edges; AH_Edge edge_limit; AH_Outline outline = hinter->glyph; FT_Int dimension; FT_Int n_edges; 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -