< prev index next >

src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c

Print this page


   1 /***************************************************************************/
   2 /*                                                                         */
   3 /*  aflatin.c                                                              */
   4 /*                                                                         */
   5 /*    Auto-fitter hinting routines for latin writing system (body).        */
   6 /*                                                                         */
   7 /*  Copyright 2003-2018 by                                                 */
   8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
   9 /*                                                                         */
  10 /*  This file is part of the FreeType project, and may only be used,       */
  11 /*  modified, and distributed under the terms of the FreeType project      */
  12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
  13 /*  this file you indicate that you have read the license and              */
  14 /*  understand and accept it fully.                                        */
  15 /*                                                                         */
  16 /***************************************************************************/
  17 
  18 
  19 #include <ft2build.h>
  20 #include FT_ADVANCES_H
  21 #include FT_INTERNAL_DEBUG_H
  22 
  23 #include "afglobal.h"
  24 #include "afpic.h"
  25 #include "aflatin.h"
  26 #include "aferrors.h"
  27 
  28 
  29 #ifdef AF_CONFIG_OPTION_USE_WARPER
  30 #include "afwarp.h"
  31 #endif
  32 
  33 
  34   /*************************************************************************/
  35   /*                                                                       */
  36   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  37   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  38   /* messages during execution.                                            */
  39   /*                                                                       */
  40 #undef  FT_COMPONENT
  41 #define FT_COMPONENT  trace_aflatin
  42 
  43 
  44   /* needed for computation of round vs. flat segments */
  45 #define FLAT_THRESHOLD( x )  ( x / 14 )
  46 
  47 
  48   /*************************************************************************/
  49   /*************************************************************************/
  50   /*****                                                               *****/
  51   /*****            L A T I N   G L O B A L   M E T R I C S            *****/
  52   /*****                                                               *****/
  53   /*************************************************************************/
  54   /*************************************************************************/
  55 
  56 
  57   /* Find segments and links, compute all stem widths, and initialize */
  58   /* standard width and height for the glyph with given charcode.     */
  59 
  60   FT_LOCAL_DEF( void )
  61   af_latin_metrics_init_widths( AF_LatinMetrics  metrics,


  66 
  67 
  68     FT_TRACE5(( "\n"
  69                 "latin standard widths computation (style `%s')\n"
  70                 "=====================================================\n"
  71                 "\n",
  72                 af_style_names[metrics->root.style_class->style] ));
  73 
  74     af_glyph_hints_init( hints, face->memory );
  75 
  76     metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
  77     metrics->axis[AF_DIMENSION_VERT].width_count = 0;
  78 
  79     {
  80       FT_Error            error;
  81       FT_ULong            glyph_index;
  82       int                 dim;
  83       AF_LatinMetricsRec  dummy[1];
  84       AF_Scaler           scaler = &dummy->root.scaler;
  85 
  86 #ifdef FT_CONFIG_OPTION_PIC
  87       AF_FaceGlobals  globals = metrics->root.globals;
  88 #endif
  89 
  90       AF_StyleClass   style_class  = metrics->root.style_class;
  91       AF_ScriptClass  script_class = AF_SCRIPT_CLASSES_GET
  92                                        [style_class->script];
  93 



  94       void*        shaper_buf;





  95       const char*  p;
  96 
  97 #ifdef FT_DEBUG_LEVEL_TRACE
  98       FT_ULong  ch = 0;
  99 #endif
 100 

 101       p          = script_class->standard_charstring;
 102       shaper_buf = af_shaper_buf_create( face );
 103 



 104       /*
 105        * We check a list of standard characters to catch features like
 106        * `c2sc' (small caps from caps) that don't contain lowercase letters
 107        * by definition, or other features that mainly operate on numerals.
 108        * The first match wins.
 109        */
 110 
 111       glyph_index = 0;
 112       while ( *p )
 113       {
 114         unsigned int  num_idx;
 115 
 116 #ifdef FT_DEBUG_LEVEL_TRACE
 117         const char*  p_old;
 118 #endif
 119 
 120 
 121         while ( *p == ' ' )
 122           p++;
 123 


 312                                FT_Face          face )
 313   {
 314     FT_Pos        flats [AF_BLUE_STRING_MAX_LEN];
 315     FT_Pos        rounds[AF_BLUE_STRING_MAX_LEN];
 316 
 317     FT_UInt       num_flats;
 318     FT_UInt       num_rounds;
 319 
 320     AF_LatinBlue  blue;
 321     FT_Error      error;
 322     AF_LatinAxis  axis = &metrics->axis[AF_DIMENSION_VERT];
 323     FT_Outline    outline;
 324 
 325     AF_StyleClass  sc = metrics->root.style_class;
 326 
 327     AF_Blue_Stringset         bss = sc->blue_stringset;
 328     const AF_Blue_StringRec*  bs  = &af_blue_stringsets[bss];
 329 
 330     FT_Pos  flat_threshold = FLAT_THRESHOLD( metrics->units_per_em );
 331 



 332     void*  shaper_buf;




 333 
 334 
 335     /* we walk over the blue character strings as specified in the */
 336     /* style's entry in the `af_blue_stringset' array              */
 337 
 338     FT_TRACE5(( "latin blue zones computation\n"
 339                 "============================\n"
 340                 "\n" ));
 341 

 342     shaper_buf = af_shaper_buf_create( face );

 343 
 344     for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
 345     {
 346       const char*  p = &af_blue_strings[bs->string];
 347       FT_Pos*      blue_ref;
 348       FT_Pos*      blue_shoot;
 349       FT_Pos       ascender;
 350       FT_Pos       descender;
 351 
 352 
 353 #ifdef FT_DEBUG_LEVEL_TRACE
 354       {
 355         FT_Bool  have_flag = 0;
 356 
 357 
 358         FT_TRACE5(( "blue zone %d", axis->blue_count ));
 359 
 360         if ( bs->properties )
 361         {
 362           FT_TRACE5(( " (" ));


1019                       *a ));
1020         }
1021       }
1022     }
1023 
1024     FT_TRACE5(( "\n" ));
1025 
1026     return;
1027   }
1028 
1029 
1030   /* Check whether all ASCII digits have the same advance width. */
1031 
1032   FT_LOCAL_DEF( void )
1033   af_latin_metrics_check_digits( AF_LatinMetrics  metrics,
1034                                  FT_Face          face )
1035   {
1036     FT_Bool   started = 0, same_width = 1;
1037     FT_Fixed  advance = 0, old_advance = 0;
1038 



1039     void*  shaper_buf;




1040 
1041     /* in all supported charmaps, digits have character codes 0x30-0x39 */
1042     const char   digits[] = "0 1 2 3 4 5 6 7 8 9";
1043     const char*  p;
1044 
1045 
1046     p          = digits;


1047     shaper_buf = af_shaper_buf_create( face );

1048 
1049     while ( *p )
1050     {
1051       FT_ULong      glyph_index;
1052       unsigned int  num_idx;
1053 
1054 
1055       /* reject input that maps to more than a single glyph */
1056       p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
1057       if ( num_idx > 1 )
1058         continue;
1059 
1060       glyph_index = af_shaper_get_elem( &metrics->root,
1061                                         shaper_buf,
1062                                         0,
1063                                         &advance,
1064                                         NULL );
1065       if ( !glyph_index )
1066         continue;
1067 


1266 
1267     /* scale the widths */
1268     for ( nn = 0; nn < axis->width_count; nn++ )
1269     {
1270       AF_Width  width = axis->widths + nn;
1271 
1272 
1273       width->cur = FT_MulFix( width->org, scale );
1274       width->fit = width->cur;
1275 
1276       FT_TRACE5(( "  %d scaled to %.2f\n",
1277                   width->org,
1278                   width->cur / 64.0 ));
1279     }
1280 
1281     FT_TRACE5(( "\n" ));
1282 
1283     /* an extra-light axis corresponds to a standard width that is */
1284     /* smaller than 5/8 pixels                                     */
1285     axis->extra_light =
1286       (FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 );
1287 
1288 #ifdef FT_DEBUG_LEVEL_TRACE
1289     if ( axis->extra_light )
1290       FT_TRACE5(( "`%s' style is extra light (at current resolution)\n"
1291                   "\n",
1292                   af_style_names[metrics->root.style_class->style] ));
1293 #endif
1294 
1295     if ( dim == AF_DIMENSION_VERT )
1296     {
1297 #ifdef FT_DEBUG_LEVEL_TRACE
1298       if ( axis->blue_count )
1299         FT_TRACE5(( "blue zones (style `%s')\n",
1300                     af_style_names[metrics->root.style_class->style] ));
1301 #endif
1302 
1303       /* scale the blue zones */
1304       for ( nn = 0; nn < axis->blue_count; nn++ )
1305       {
1306         AF_LatinBlue  blue = &axis->blues[nn];


1954           FT_Pos  max = seg1->max_coord;
1955           FT_Pos  len;
1956 
1957 
1958           if ( min < seg2->min_coord )
1959             min = seg2->min_coord;
1960 
1961           if ( max > seg2->max_coord )
1962             max = seg2->max_coord;
1963 
1964           /* compute maximum coordinate difference of the two segments */
1965           /* (this is, how much they overlap)                          */
1966           len = max - min;
1967           if ( len >= len_threshold )
1968           {
1969             /*
1970              *  The score is the sum of two demerits indicating the
1971              *  `badness' of a fit, measured along the segments' main axis
1972              *  and orthogonal to it, respectively.
1973              *
1974              *  o The less overlapping along the main axis, the worse it
1975              *    is, causing a larger demerit.
1976              *
1977              *  o The nearer the orthogonal distance to a stem width, the
1978              *    better it is, causing a smaller demerit.  For simplicity,
1979              *    however, we only increase the demerit for values that
1980              *    exceed the largest stem width.
1981              */
1982 
1983             FT_Pos  dist = pos2 - pos1;
1984 
1985             FT_Pos  dist_demerit, score;
1986 
1987 
1988             if ( max_width )
1989             {
1990               /* distance demerits are based on multiples of `max_width'; */
1991               /* we scale by 1024 for getting more precision              */
1992               FT_Pos  delta = ( dist << 10 ) / max_width - ( 1 << 10 );
1993 
1994 
1995               if ( delta > 10000 )
1996                 dist_demerit = 32000;
1997               else if ( delta > 0 )


2032         {
2033           seg1->link  = 0;
2034           seg1->serif = seg2->link;
2035         }
2036       }
2037     }
2038   }
2039 
2040 
2041   /* Link segments to edges, using feature analysis for selection. */
2042 
2043   FT_LOCAL_DEF( FT_Error )
2044   af_latin_hints_compute_edges( AF_GlyphHints  hints,
2045                                 AF_Dimension   dim )
2046   {
2047     AF_AxisHints  axis   = &hints->axis[dim];
2048     FT_Error      error  = FT_Err_Ok;
2049     FT_Memory     memory = hints->memory;
2050     AF_LatinAxis  laxis  = &((AF_LatinMetrics)hints->metrics)->axis[dim];
2051 
2052 #ifdef FT_CONFIG_OPTION_PIC
2053     AF_FaceGlobals  globals = hints->metrics->globals;
2054 #endif
2055 
2056     AF_StyleClass   style_class  = hints->metrics->style_class;
2057     AF_ScriptClass  script_class = AF_SCRIPT_CLASSES_GET
2058                                      [style_class->script];
2059 
2060     FT_Bool  top_to_bottom_hinting = 0;
2061 
2062     AF_Segment    segments      = axis->segments;
2063     AF_Segment    segment_limit = segments + axis->num_segments;
2064     AF_Segment    seg;
2065 
2066 #if 0
2067     AF_Direction  up_dir;
2068 #endif
2069     FT_Fixed      scale;
2070     FT_Pos        edge_distance_threshold;
2071     FT_Pos        segment_length_threshold;
2072     FT_Pos        segment_width_threshold;
2073 
2074 
2075     axis->num_edges = 0;
2076 
2077     scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
2078                                          : hints->y_scale;


2084 
2085     if ( dim == AF_DIMENSION_VERT )
2086       top_to_bottom_hinting = script_class->top_to_bottom_hinting;
2087 
2088     /*
2089      *  We ignore all segments that are less than 1 pixel in length
2090      *  to avoid many problems with serif fonts.  We compute the
2091      *  corresponding threshold in font units.
2092      */
2093     if ( dim == AF_DIMENSION_HORZ )
2094       segment_length_threshold = FT_DivFix( 64, hints->y_scale );
2095     else
2096       segment_length_threshold = 0;
2097 
2098     /*
2099      *  Similarly, we ignore segments that have a width delta
2100      *  larger than 0.5px (i.e., a width larger than 1px).
2101      */
2102     segment_width_threshold = FT_DivFix( 32, scale );
2103 
2104     /*********************************************************************/
2105     /*                                                                   */
2106     /* We begin by generating a sorted table of edges for the current    */
2107     /* direction.  To do so, we simply scan each segment and try to find */
2108     /* an edge in our table that corresponds to its position.            */
2109     /*                                                                   */
2110     /* If no edge is found, we create and insert a new edge in the       */
2111     /* sorted table.  Otherwise, we simply add the segment to the edge's */
2112     /* list which gets processed in the second step to compute the       */
2113     /* edge's properties.                                                */
2114     /*                                                                   */
2115     /* Note that the table of edges is sorted along the segment/edge     */
2116     /* position.                                                         */
2117     /*                                                                   */
2118     /*********************************************************************/
2119 
2120     /* assure that edge distance threshold is at most 0.25px */
2121     edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
2122                                          scale );
2123     if ( edge_distance_threshold > 64 / 4 )
2124       edge_distance_threshold = 64 / 4;
2125 
2126     edge_distance_threshold = FT_DivFix( edge_distance_threshold,
2127                                          scale );
2128 
2129     for ( seg = segments; seg < segment_limit; seg++ )
2130     {
2131       AF_Edge  found = NULL;
2132       FT_Int   ee;
2133 
2134 
2135       /* ignore too short segments, too wide ones, and, in this loop, */
2136       /* one-point segments without a direction                       */
2137       if ( seg->height < segment_length_threshold ||
2138            seg->delta > segment_width_threshold   ||


2220         if ( dist < 0 )
2221           dist = -dist;
2222 
2223         if ( dist < edge_distance_threshold )
2224         {
2225           found = edge;
2226           break;
2227         }
2228       }
2229 
2230       /* one-point segments without a match are ignored */
2231       if ( found )
2232       {
2233         seg->edge_next         = found->first;
2234         found->last->edge_next = seg;
2235         found->last            = seg;
2236       }
2237     }
2238 
2239 
2240     /******************************************************************/
2241     /*                                                                */
2242     /* Good, we now compute each edge's properties according to the   */
2243     /* segments found on its position.  Basically, these are          */
2244     /*                                                                */
2245     /*  - the edge's main direction                                   */
2246     /*  - stem edge, serif edge or both (which defaults to stem then) */
2247     /*  - rounded edge, straight or both (which defaults to straight) */
2248     /*  - link for edge                                               */
2249     /*                                                                */
2250     /******************************************************************/
2251 
2252     /* first of all, set the `edge' field in each segment -- this is */
2253     /* required in order to compute edge links                       */
2254 
2255     /*
2256      * Note that removing this loop and setting the `edge' field of each
2257      * segment directly in the code above slows down execution speed for
2258      * some reasons on platforms like the Sun.
2259      */
2260     {
2261       AF_Edge  edges      = axis->edges;
2262       AF_Edge  edge_limit = edges + axis->num_edges;
2263       AF_Edge  edge;
2264 
2265 
2266       for ( edge = edges; edge < edge_limit; edge++ )
2267       {
2268         seg = edge->first;
2269         if ( seg )
2270           do


2292         {
2293           FT_Bool  is_serif;
2294 
2295 
2296           /* check for roundness of segment */
2297           if ( seg->flags & AF_EDGE_ROUND )
2298             is_round++;
2299           else
2300             is_straight++;
2301 
2302 #if 0
2303           /* check for segment direction */
2304           if ( seg->dir == up_dir )
2305             ups   += seg->max_coord - seg->min_coord;
2306           else
2307             downs += seg->max_coord - seg->min_coord;
2308 #endif
2309 
2310           /* check for links -- if seg->serif is set, then seg->link must */
2311           /* be ignored                                                   */
2312           is_serif = (FT_Bool)( seg->serif               &&
2313                                 seg->serif->edge         &&
2314                                 seg->serif->edge != edge );
2315 
2316           if ( ( seg->link && seg->link->edge ) || is_serif )
2317           {
2318             AF_Edge     edge2;
2319             AF_Segment  seg2;
2320 
2321 
2322             edge2 = edge->link;
2323             seg2  = seg->link;
2324 
2325             if ( is_serif )
2326             {
2327               seg2  = seg->serif;
2328               edge2 = edge->serif;
2329             }
2330 
2331             if ( edge2 )
2332             {


2919   /****                                                                 ****/
2920   /*************************************************************************/
2921   /*************************************************************************/
2922   /*************************************************************************/
2923 
2924 
2925   /* The main grid-fitting routine. */
2926 
2927   static void
2928   af_latin_hint_edges( AF_GlyphHints  hints,
2929                        AF_Dimension   dim )
2930   {
2931     AF_AxisHints  axis       = &hints->axis[dim];
2932     AF_Edge       edges      = axis->edges;
2933     AF_Edge       edge_limit = edges + axis->num_edges;
2934     FT_PtrDist    n_edges;
2935     AF_Edge       edge;
2936     AF_Edge       anchor     = NULL;
2937     FT_Int        has_serifs = 0;
2938 
2939 #ifdef FT_CONFIG_OPTION_PIC
2940     AF_FaceGlobals  globals = hints->metrics->globals;
2941 #endif
2942 
2943     AF_StyleClass   style_class  = hints->metrics->style_class;
2944     AF_ScriptClass  script_class = AF_SCRIPT_CLASSES_GET
2945                                      [style_class->script];
2946 
2947     FT_Bool  top_to_bottom_hinting = 0;
2948 
2949 #ifdef FT_DEBUG_LEVEL_TRACE
2950     FT_UInt  num_actions = 0;
2951 #endif
2952 
2953 
2954     FT_TRACE5(( "latin %s edge hinting (style `%s')\n",
2955                 dim == AF_DIMENSION_VERT ? "horizontal" : "vertical",
2956                 af_style_names[hints->metrics->style_class->style] ));
2957 
2958     if ( dim == AF_DIMENSION_VERT )
2959       top_to_bottom_hinting = script_class->top_to_bottom_hinting;
2960 
2961     /* we begin by aligning all stems relative to the blue zone */
2962     /* if needed -- that's only for horizontal edges            */
2963 
2964     if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) )
2965     {


   1 /****************************************************************************
   2  *
   3  * aflatin.c
   4  *
   5  *   Auto-fitter hinting routines for latin writing system (body).
   6  *
   7  * Copyright (C) 2003-2019 by
   8  * David Turner, Robert Wilhelm, and Werner Lemberg.
   9  *
  10  * This file is part of the FreeType project, and may only be used,
  11  * modified, and distributed under the terms of the FreeType project
  12  * license, LICENSE.TXT.  By continuing to use, modify, or distribute
  13  * this file you indicate that you have read the license and
  14  * understand and accept it fully.
  15  *
  16  */
  17 
  18 
  19 #include <ft2build.h>
  20 #include FT_ADVANCES_H
  21 #include FT_INTERNAL_DEBUG_H
  22 
  23 #include "afglobal.h"

  24 #include "aflatin.h"
  25 #include "aferrors.h"
  26 
  27 
  28 #ifdef AF_CONFIG_OPTION_USE_WARPER
  29 #include "afwarp.h"
  30 #endif
  31 
  32 
  33   /**************************************************************************
  34    *
  35    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
  36    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
  37    * messages during execution.
  38    */
  39 #undef  FT_COMPONENT
  40 #define FT_COMPONENT  aflatin
  41 
  42 
  43   /* needed for computation of round vs. flat segments */
  44 #define FLAT_THRESHOLD( x )  ( x / 14 )
  45 
  46 
  47   /*************************************************************************/
  48   /*************************************************************************/
  49   /*****                                                               *****/
  50   /*****            L A T I N   G L O B A L   M E T R I C S            *****/
  51   /*****                                                               *****/
  52   /*************************************************************************/
  53   /*************************************************************************/
  54 
  55 
  56   /* Find segments and links, compute all stem widths, and initialize */
  57   /* standard width and height for the glyph with given charcode.     */
  58 
  59   FT_LOCAL_DEF( void )
  60   af_latin_metrics_init_widths( AF_LatinMetrics  metrics,


  65 
  66 
  67     FT_TRACE5(( "\n"
  68                 "latin standard widths computation (style `%s')\n"
  69                 "=====================================================\n"
  70                 "\n",
  71                 af_style_names[metrics->root.style_class->style] ));
  72 
  73     af_glyph_hints_init( hints, face->memory );
  74 
  75     metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
  76     metrics->axis[AF_DIMENSION_VERT].width_count = 0;
  77 
  78     {
  79       FT_Error            error;
  80       FT_ULong            glyph_index;
  81       int                 dim;
  82       AF_LatinMetricsRec  dummy[1];
  83       AF_Scaler           scaler = &dummy->root.scaler;
  84 




  85       AF_StyleClass   style_class  = metrics->root.style_class;
  86       AF_ScriptClass  script_class = af_script_classes[style_class->script];

  87 
  88       /* If HarfBuzz is not available, we need a pointer to a single */
  89       /* unsigned long value.                                        */
  90 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
  91       void*     shaper_buf;
  92 #else
  93       FT_ULong  shaper_buf_;
  94       void*     shaper_buf = &shaper_buf_;
  95 #endif
  96 
  97       const char*  p;
  98 
  99 #ifdef FT_DEBUG_LEVEL_TRACE
 100       FT_ULong  ch = 0;
 101 #endif
 102 
 103 
 104       p = script_class->standard_charstring;

 105 
 106 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
 107       shaper_buf = af_shaper_buf_create( face );
 108 #endif
 109       /*
 110        * We check a list of standard characters to catch features like
 111        * `c2sc' (small caps from caps) that don't contain lowercase letters
 112        * by definition, or other features that mainly operate on numerals.
 113        * The first match wins.
 114        */
 115 
 116       glyph_index = 0;
 117       while ( *p )
 118       {
 119         unsigned int  num_idx;
 120 
 121 #ifdef FT_DEBUG_LEVEL_TRACE
 122         const char*  p_old;
 123 #endif
 124 
 125 
 126         while ( *p == ' ' )
 127           p++;
 128 


 317                                FT_Face          face )
 318   {
 319     FT_Pos        flats [AF_BLUE_STRING_MAX_LEN];
 320     FT_Pos        rounds[AF_BLUE_STRING_MAX_LEN];
 321 
 322     FT_UInt       num_flats;
 323     FT_UInt       num_rounds;
 324 
 325     AF_LatinBlue  blue;
 326     FT_Error      error;
 327     AF_LatinAxis  axis = &metrics->axis[AF_DIMENSION_VERT];
 328     FT_Outline    outline;
 329 
 330     AF_StyleClass  sc = metrics->root.style_class;
 331 
 332     AF_Blue_Stringset         bss = sc->blue_stringset;
 333     const AF_Blue_StringRec*  bs  = &af_blue_stringsets[bss];
 334 
 335     FT_Pos  flat_threshold = FLAT_THRESHOLD( metrics->units_per_em );
 336 
 337     /* If HarfBuzz is not available, we need a pointer to a single */
 338     /* unsigned long value.                                        */
 339 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
 340     void*     shaper_buf;
 341 #else
 342     FT_ULong  shaper_buf_;
 343     void*     shaper_buf = &shaper_buf_;
 344 #endif
 345 
 346 
 347     /* we walk over the blue character strings as specified in the */
 348     /* style's entry in the `af_blue_stringset' array              */
 349 
 350     FT_TRACE5(( "latin blue zones computation\n"
 351                 "============================\n"
 352                 "\n" ));
 353 
 354 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
 355     shaper_buf = af_shaper_buf_create( face );
 356 #endif
 357 
 358     for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
 359     {
 360       const char*  p = &af_blue_strings[bs->string];
 361       FT_Pos*      blue_ref;
 362       FT_Pos*      blue_shoot;
 363       FT_Pos       ascender;
 364       FT_Pos       descender;
 365 
 366 
 367 #ifdef FT_DEBUG_LEVEL_TRACE
 368       {
 369         FT_Bool  have_flag = 0;
 370 
 371 
 372         FT_TRACE5(( "blue zone %d", axis->blue_count ));
 373 
 374         if ( bs->properties )
 375         {
 376           FT_TRACE5(( " (" ));


1033                       *a ));
1034         }
1035       }
1036     }
1037 
1038     FT_TRACE5(( "\n" ));
1039 
1040     return;
1041   }
1042 
1043 
1044   /* Check whether all ASCII digits have the same advance width. */
1045 
1046   FT_LOCAL_DEF( void )
1047   af_latin_metrics_check_digits( AF_LatinMetrics  metrics,
1048                                  FT_Face          face )
1049   {
1050     FT_Bool   started = 0, same_width = 1;
1051     FT_Fixed  advance = 0, old_advance = 0;
1052 
1053     /* If HarfBuzz is not available, we need a pointer to a single */
1054     /* unsigned long value.                                        */
1055 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
1056     void*     shaper_buf;
1057 #else
1058     FT_ULong  shaper_buf_;
1059     void*     shaper_buf = &shaper_buf_;
1060 #endif
1061 
1062     /* in all supported charmaps, digits have character codes 0x30-0x39 */
1063     const char   digits[] = "0 1 2 3 4 5 6 7 8 9";
1064     const char*  p;
1065 
1066 
1067     p = digits;
1068 
1069 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
1070     shaper_buf = af_shaper_buf_create( face );
1071 #endif
1072 
1073     while ( *p )
1074     {
1075       FT_ULong      glyph_index;
1076       unsigned int  num_idx;
1077 
1078 
1079       /* reject input that maps to more than a single glyph */
1080       p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
1081       if ( num_idx > 1 )
1082         continue;
1083 
1084       glyph_index = af_shaper_get_elem( &metrics->root,
1085                                         shaper_buf,
1086                                         0,
1087                                         &advance,
1088                                         NULL );
1089       if ( !glyph_index )
1090         continue;
1091 


1290 
1291     /* scale the widths */
1292     for ( nn = 0; nn < axis->width_count; nn++ )
1293     {
1294       AF_Width  width = axis->widths + nn;
1295 
1296 
1297       width->cur = FT_MulFix( width->org, scale );
1298       width->fit = width->cur;
1299 
1300       FT_TRACE5(( "  %d scaled to %.2f\n",
1301                   width->org,
1302                   width->cur / 64.0 ));
1303     }
1304 
1305     FT_TRACE5(( "\n" ));
1306 
1307     /* an extra-light axis corresponds to a standard width that is */
1308     /* smaller than 5/8 pixels                                     */
1309     axis->extra_light =
1310       FT_BOOL( FT_MulFix( axis->standard_width, scale ) < 32 + 8 );
1311 
1312 #ifdef FT_DEBUG_LEVEL_TRACE
1313     if ( axis->extra_light )
1314       FT_TRACE5(( "`%s' style is extra light (at current resolution)\n"
1315                   "\n",
1316                   af_style_names[metrics->root.style_class->style] ));
1317 #endif
1318 
1319     if ( dim == AF_DIMENSION_VERT )
1320     {
1321 #ifdef FT_DEBUG_LEVEL_TRACE
1322       if ( axis->blue_count )
1323         FT_TRACE5(( "blue zones (style `%s')\n",
1324                     af_style_names[metrics->root.style_class->style] ));
1325 #endif
1326 
1327       /* scale the blue zones */
1328       for ( nn = 0; nn < axis->blue_count; nn++ )
1329       {
1330         AF_LatinBlue  blue = &axis->blues[nn];


1978           FT_Pos  max = seg1->max_coord;
1979           FT_Pos  len;
1980 
1981 
1982           if ( min < seg2->min_coord )
1983             min = seg2->min_coord;
1984 
1985           if ( max > seg2->max_coord )
1986             max = seg2->max_coord;
1987 
1988           /* compute maximum coordinate difference of the two segments */
1989           /* (this is, how much they overlap)                          */
1990           len = max - min;
1991           if ( len >= len_threshold )
1992           {
1993             /*
1994              * The score is the sum of two demerits indicating the
1995              * `badness' of a fit, measured along the segments' main axis
1996              * and orthogonal to it, respectively.
1997              *
1998              * - The less overlapping along the main axis, the worse it
1999              *   is, causing a larger demerit.
2000              *
2001              * - The nearer the orthogonal distance to a stem width, the
2002              *   better it is, causing a smaller demerit.  For simplicity,
2003              *   however, we only increase the demerit for values that
2004              *   exceed the largest stem width.
2005              */
2006 
2007             FT_Pos  dist = pos2 - pos1;
2008 
2009             FT_Pos  dist_demerit, score;
2010 
2011 
2012             if ( max_width )
2013             {
2014               /* distance demerits are based on multiples of `max_width'; */
2015               /* we scale by 1024 for getting more precision              */
2016               FT_Pos  delta = ( dist << 10 ) / max_width - ( 1 << 10 );
2017 
2018 
2019               if ( delta > 10000 )
2020                 dist_demerit = 32000;
2021               else if ( delta > 0 )


2056         {
2057           seg1->link  = 0;
2058           seg1->serif = seg2->link;
2059         }
2060       }
2061     }
2062   }
2063 
2064 
2065   /* Link segments to edges, using feature analysis for selection. */
2066 
2067   FT_LOCAL_DEF( FT_Error )
2068   af_latin_hints_compute_edges( AF_GlyphHints  hints,
2069                                 AF_Dimension   dim )
2070   {
2071     AF_AxisHints  axis   = &hints->axis[dim];
2072     FT_Error      error  = FT_Err_Ok;
2073     FT_Memory     memory = hints->memory;
2074     AF_LatinAxis  laxis  = &((AF_LatinMetrics)hints->metrics)->axis[dim];
2075 




2076     AF_StyleClass   style_class  = hints->metrics->style_class;
2077     AF_ScriptClass  script_class = af_script_classes[style_class->script];

2078 
2079     FT_Bool  top_to_bottom_hinting = 0;
2080 
2081     AF_Segment    segments      = axis->segments;
2082     AF_Segment    segment_limit = segments + axis->num_segments;
2083     AF_Segment    seg;
2084 
2085 #if 0
2086     AF_Direction  up_dir;
2087 #endif
2088     FT_Fixed      scale;
2089     FT_Pos        edge_distance_threshold;
2090     FT_Pos        segment_length_threshold;
2091     FT_Pos        segment_width_threshold;
2092 
2093 
2094     axis->num_edges = 0;
2095 
2096     scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
2097                                          : hints->y_scale;


2103 
2104     if ( dim == AF_DIMENSION_VERT )
2105       top_to_bottom_hinting = script_class->top_to_bottom_hinting;
2106 
2107     /*
2108      * We ignore all segments that are less than 1 pixel in length
2109      * to avoid many problems with serif fonts.  We compute the
2110      * corresponding threshold in font units.
2111      */
2112     if ( dim == AF_DIMENSION_HORZ )
2113       segment_length_threshold = FT_DivFix( 64, hints->y_scale );
2114     else
2115       segment_length_threshold = 0;
2116 
2117     /*
2118      * Similarly, we ignore segments that have a width delta
2119      * larger than 0.5px (i.e., a width larger than 1px).
2120      */
2121     segment_width_threshold = FT_DivFix( 32, scale );
2122 
2123     /**********************************************************************
2124      *
2125      * We begin by generating a sorted table of edges for the current
2126      * direction.  To do so, we simply scan each segment and try to find
2127      * an edge in our table that corresponds to its position.
2128      *
2129      * If no edge is found, we create and insert a new edge in the
2130      * sorted table.  Otherwise, we simply add the segment to the edge's
2131      * list which gets processed in the second step to compute the
2132      * edge's properties.
2133      *
2134      * Note that the table of edges is sorted along the segment/edge
2135      * position.
2136      *
2137      */
2138 
2139     /* assure that edge distance threshold is at most 0.25px */
2140     edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
2141                                          scale );
2142     if ( edge_distance_threshold > 64 / 4 )
2143       edge_distance_threshold = 64 / 4;
2144 
2145     edge_distance_threshold = FT_DivFix( edge_distance_threshold,
2146                                          scale );
2147 
2148     for ( seg = segments; seg < segment_limit; seg++ )
2149     {
2150       AF_Edge  found = NULL;
2151       FT_Int   ee;
2152 
2153 
2154       /* ignore too short segments, too wide ones, and, in this loop, */
2155       /* one-point segments without a direction                       */
2156       if ( seg->height < segment_length_threshold ||
2157            seg->delta > segment_width_threshold   ||


2239         if ( dist < 0 )
2240           dist = -dist;
2241 
2242         if ( dist < edge_distance_threshold )
2243         {
2244           found = edge;
2245           break;
2246         }
2247       }
2248 
2249       /* one-point segments without a match are ignored */
2250       if ( found )
2251       {
2252         seg->edge_next         = found->first;
2253         found->last->edge_next = seg;
2254         found->last            = seg;
2255       }
2256     }
2257 
2258 
2259     /*******************************************************************
2260      *
2261      * Good, we now compute each edge's properties according to the
2262      * segments found on its position.  Basically, these are
2263      *
2264      * - the edge's main direction
2265      * - stem edge, serif edge or both (which defaults to stem then)
2266      * - rounded edge, straight or both (which defaults to straight)
2267      * - link for edge
2268      *
2269      */
2270 
2271     /* first of all, set the `edge' field in each segment -- this is */
2272     /* required in order to compute edge links                       */
2273 
2274     /*
2275      * Note that removing this loop and setting the `edge' field of each
2276      * segment directly in the code above slows down execution speed for
2277      * some reasons on platforms like the Sun.
2278      */
2279     {
2280       AF_Edge  edges      = axis->edges;
2281       AF_Edge  edge_limit = edges + axis->num_edges;
2282       AF_Edge  edge;
2283 
2284 
2285       for ( edge = edges; edge < edge_limit; edge++ )
2286       {
2287         seg = edge->first;
2288         if ( seg )
2289           do


2311         {
2312           FT_Bool  is_serif;
2313 
2314 
2315           /* check for roundness of segment */
2316           if ( seg->flags & AF_EDGE_ROUND )
2317             is_round++;
2318           else
2319             is_straight++;
2320 
2321 #if 0
2322           /* check for segment direction */
2323           if ( seg->dir == up_dir )
2324             ups   += seg->max_coord - seg->min_coord;
2325           else
2326             downs += seg->max_coord - seg->min_coord;
2327 #endif
2328 
2329           /* check for links -- if seg->serif is set, then seg->link must */
2330           /* be ignored                                                   */
2331           is_serif = FT_BOOL( seg->serif               &&
2332                               seg->serif->edge         &&
2333                               seg->serif->edge != edge );
2334 
2335           if ( ( seg->link && seg->link->edge ) || is_serif )
2336           {
2337             AF_Edge     edge2;
2338             AF_Segment  seg2;
2339 
2340 
2341             edge2 = edge->link;
2342             seg2  = seg->link;
2343 
2344             if ( is_serif )
2345             {
2346               seg2  = seg->serif;
2347               edge2 = edge->serif;
2348             }
2349 
2350             if ( edge2 )
2351             {


2938   /****                                                                 ****/
2939   /*************************************************************************/
2940   /*************************************************************************/
2941   /*************************************************************************/
2942 
2943 
2944   /* The main grid-fitting routine. */
2945 
2946   static void
2947   af_latin_hint_edges( AF_GlyphHints  hints,
2948                        AF_Dimension   dim )
2949   {
2950     AF_AxisHints  axis       = &hints->axis[dim];
2951     AF_Edge       edges      = axis->edges;
2952     AF_Edge       edge_limit = edges + axis->num_edges;
2953     FT_PtrDist    n_edges;
2954     AF_Edge       edge;
2955     AF_Edge       anchor     = NULL;
2956     FT_Int        has_serifs = 0;
2957 




2958     AF_StyleClass   style_class  = hints->metrics->style_class;
2959     AF_ScriptClass  script_class = af_script_classes[style_class->script];

2960 
2961     FT_Bool  top_to_bottom_hinting = 0;
2962 
2963 #ifdef FT_DEBUG_LEVEL_TRACE
2964     FT_UInt  num_actions = 0;
2965 #endif
2966 
2967 
2968     FT_TRACE5(( "latin %s edge hinting (style `%s')\n",
2969                 dim == AF_DIMENSION_VERT ? "horizontal" : "vertical",
2970                 af_style_names[hints->metrics->style_class->style] ));
2971 
2972     if ( dim == AF_DIMENSION_VERT )
2973       top_to_bottom_hinting = script_class->top_to_bottom_hinting;
2974 
2975     /* we begin by aligning all stems relative to the blue zone */
2976     /* if needed -- that's only for horizontal edges            */
2977 
2978     if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) )
2979     {


< prev index next >