Charles.Forsyth20060303a828770d19 years agoHistory
1493 lines · 41.4 KB · C
RawDownload
/***************************************************************************//*                                                                         *//*  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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t