< prev index next >

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

Print this page


   1 /***************************************************************************/
   2 /*                                                                         */
   3 /*  afcjk.c                                                                */
   4 /*                                                                         */
   5 /*    Auto-fitter hinting routines for CJK writing system (body).          */
   6 /*                                                                         */
   7 /*  Copyright 2006-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    *  The algorithm is based on akito's autohint patch, archived at
  20    *
  21    *  https://web.archive.org/web/20051219160454/http://www.kde.gr.jp:80/~akito/patch/freetype2/2.1.7/
  22    *
  23    */
  24 
  25 #include <ft2build.h>
  26 #include FT_ADVANCES_H
  27 #include FT_INTERNAL_DEBUG_H
  28 
  29 #include "afglobal.h"
  30 #include "afpic.h"
  31 #include "aflatin.h"
  32 #include "afcjk.h"
  33 
  34 
  35 #ifdef AF_CONFIG_OPTION_CJK
  36 
  37 #undef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT
  38 
  39 #include "aferrors.h"
  40 
  41 
  42 #ifdef AF_CONFIG_OPTION_USE_WARPER
  43 #include "afwarp.h"
  44 #endif
  45 
  46 
  47   /*************************************************************************/
  48   /*                                                                       */
  49   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  50   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  51   /* messages during execution.                                            */
  52   /*                                                                       */
  53 #undef  FT_COMPONENT
  54 #define FT_COMPONENT  trace_afcjk
  55 
  56 
  57   /*************************************************************************/
  58   /*************************************************************************/
  59   /*****                                                               *****/
  60   /*****              C J K   G L O B A L   M E T R I C S              *****/
  61   /*****                                                               *****/
  62   /*************************************************************************/
  63   /*************************************************************************/
  64 
  65 
  66   /* Basically the Latin version with AF_CJKMetrics */
  67   /* to replace AF_LatinMetrics.                    */
  68 
  69   FT_LOCAL_DEF( void )
  70   af_cjk_metrics_init_widths( AF_CJKMetrics  metrics,
  71                               FT_Face        face )
  72   {
  73     /* scan the array of segments in each direction */
  74     AF_GlyphHintsRec  hints[1];
  75 
  76 
  77     FT_TRACE5(( "\n"
  78                 "cjk standard widths computation (style `%s')\n"
  79                 "===================================================\n"
  80                 "\n",
  81                 af_style_names[metrics->root.style_class->style] ));
  82 
  83     af_glyph_hints_init( hints, face->memory );
  84 
  85     metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
  86     metrics->axis[AF_DIMENSION_VERT].width_count = 0;
  87 
  88     {
  89       FT_Error          error;
  90       FT_ULong          glyph_index;
  91       int               dim;
  92       AF_CJKMetricsRec  dummy[1];
  93       AF_Scaler         scaler = &dummy->root.scaler;
  94 
  95 #ifdef FT_CONFIG_OPTION_PIC
  96       AF_FaceGlobals  globals = metrics->root.globals;
  97 #endif
  98 
  99       AF_StyleClass   style_class  = metrics->root.style_class;
 100       AF_ScriptClass  script_class = AF_SCRIPT_CLASSES_GET
 101                                        [style_class->script];
 102 



 103       void*        shaper_buf;





 104       const char*  p;
 105 
 106 #ifdef FT_DEBUG_LEVEL_TRACE
 107       FT_ULong  ch = 0;
 108 #endif
 109 
 110       p          = script_class->standard_charstring;


 111       shaper_buf = af_shaper_buf_create( face );

 112 
 113       /* We check a list of standard characters.  The first match wins. */
 114 
 115       glyph_index = 0;
 116       while ( *p )
 117       {
 118         unsigned int  num_idx;
 119 
 120 #ifdef FT_DEBUG_LEVEL_TRACE
 121         const char*  p_old;
 122 #endif
 123 
 124 
 125         while ( *p == ' ' )
 126           p++;
 127 
 128 #ifdef FT_DEBUG_LEVEL_TRACE
 129         p_old = p;
 130         GET_UTF8_CHAR( ch, p_old );
 131 #endif


 279                              FT_Face        face )
 280   {
 281     FT_Pos      fills[AF_BLUE_STRING_MAX_LEN];
 282     FT_Pos      flats[AF_BLUE_STRING_MAX_LEN];
 283 
 284     FT_UInt     num_fills;
 285     FT_UInt     num_flats;
 286 
 287     FT_Bool     fill;
 288 
 289     AF_CJKBlue  blue;
 290     FT_Error    error;
 291     AF_CJKAxis  axis;
 292     FT_Outline  outline;
 293 
 294     AF_StyleClass  sc = metrics->root.style_class;
 295 
 296     AF_Blue_Stringset         bss = sc->blue_stringset;
 297     const AF_Blue_StringRec*  bs  = &af_blue_stringsets[bss];
 298 



 299     void*  shaper_buf;




 300 
 301 
 302     /* we walk over the blue character strings as specified in the   */
 303     /* style's entry in the `af_blue_stringset' array, computing its */
 304     /* extremum points (depending on the string properties)          */
 305 
 306     FT_TRACE5(( "cjk blue zones computation\n"
 307                 "==========================\n"
 308                 "\n" ));
 309 

 310     shaper_buf = af_shaper_buf_create( face );

 311 
 312     for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
 313     {
 314       const char*  p = &af_blue_strings[bs->string];
 315       FT_Pos*      blue_ref;
 316       FT_Pos*      blue_shoot;
 317 
 318 
 319       if ( AF_CJK_IS_HORIZ_BLUE( bs ) )
 320         axis = &metrics->axis[AF_DIMENSION_HORZ];
 321       else
 322         axis = &metrics->axis[AF_DIMENSION_VERT];
 323 
 324 #ifdef FT_DEBUG_LEVEL_TRACE
 325       {
 326         FT_String*  cjk_blue_name[4] =
 327         {
 328           (FT_String*)"bottom",    /* --   , --  */
 329           (FT_String*)"top",       /* --   , TOP */
 330           (FT_String*)"left",      /* HORIZ, --  */


 548 
 549     } /* end for loop */
 550 
 551     af_shaper_buf_destroy( face, shaper_buf );
 552 
 553     FT_TRACE5(( "\n" ));
 554 
 555     return;
 556   }
 557 
 558 
 559   /* Basically the Latin version with type AF_CJKMetrics for metrics. */
 560 
 561   FT_LOCAL_DEF( void )
 562   af_cjk_metrics_check_digits( AF_CJKMetrics  metrics,
 563                                FT_Face        face )
 564   {
 565     FT_Bool   started = 0, same_width = 1;
 566     FT_Fixed  advance = 0, old_advance = 0;
 567 



 568     void*  shaper_buf;




 569 
 570     /* in all supported charmaps, digits have character codes 0x30-0x39 */
 571     const char   digits[] = "0 1 2 3 4 5 6 7 8 9";
 572     const char*  p;
 573 
 574 
 575     p          = digits;


 576     shaper_buf = af_shaper_buf_create( face );

 577 
 578     while ( *p )
 579     {
 580       FT_ULong      glyph_index;
 581       unsigned int  num_idx;
 582 
 583 
 584       /* reject input that maps to more than a single glyph */
 585       p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
 586       if ( num_idx > 1 )
 587         continue;
 588 
 589       glyph_index = af_shaper_get_elem( &metrics->root,
 590                                         shaper_buf,
 591                                         0,
 592                                         &advance,
 593                                         NULL );
 594       if ( !glyph_index )
 595         continue;
 596 


 983                               AF_Dimension   dim )
 984   {
 985     AF_AxisHints  axis   = &hints->axis[dim];
 986     FT_Error      error  = FT_Err_Ok;
 987     FT_Memory     memory = hints->memory;
 988     AF_CJKAxis    laxis  = &((AF_CJKMetrics)hints->metrics)->axis[dim];
 989 
 990     AF_Segment    segments      = axis->segments;
 991     AF_Segment    segment_limit = segments + axis->num_segments;
 992     AF_Segment    seg;
 993 
 994     FT_Fixed      scale;
 995     FT_Pos        edge_distance_threshold;
 996 
 997 
 998     axis->num_edges = 0;
 999 
1000     scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
1001                                          : hints->y_scale;
1002 
1003     /*********************************************************************/
1004     /*                                                                   */
1005     /* We begin by generating a sorted table of edges for the current    */
1006     /* direction.  To do so, we simply scan each segment and try to find */
1007     /* an edge in our table that corresponds to its position.            */
1008     /*                                                                   */
1009     /* If no edge is found, we create and insert a new edge in the       */
1010     /* sorted table.  Otherwise, we simply add the segment to the edge's */
1011     /* list which is then processed in the second step to compute the    */
1012     /* edge's properties.                                                */
1013     /*                                                                   */
1014     /* Note that the edges table is sorted along the segment/edge        */
1015     /* position.                                                         */
1016     /*                                                                   */
1017     /*********************************************************************/
1018 
1019     edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
1020                                          scale );
1021     if ( edge_distance_threshold > 64 / 4 )
1022       edge_distance_threshold = FT_DivFix( 64 / 4, scale );
1023     else
1024       edge_distance_threshold = laxis->edge_distance_threshold;
1025 
1026     for ( seg = segments; seg < segment_limit; seg++ )
1027     {
1028       AF_Edge  found = NULL;
1029       FT_Pos   best  = 0xFFFFU;
1030       FT_Int   ee;
1031 
1032 
1033       /* look for an edge corresponding to the segment */
1034       for ( ee = 0; ee < axis->num_edges; ee++ )
1035       {
1036         AF_Edge  edge = axis->edges + ee;
1037         FT_Pos   dist;


1097         FT_ZERO( edge );
1098 
1099         edge->first    = seg;
1100         edge->last     = seg;
1101         edge->dir      = seg->dir;
1102         edge->fpos     = seg->pos;
1103         edge->opos     = FT_MulFix( seg->pos, scale );
1104         edge->pos      = edge->opos;
1105         seg->edge_next = seg;
1106       }
1107       else
1108       {
1109         /* if an edge was found, simply add the segment to the edge's */
1110         /* list                                                       */
1111         seg->edge_next         = found->first;
1112         found->last->edge_next = seg;
1113         found->last            = seg;
1114       }
1115     }
1116 
1117     /******************************************************************/
1118     /*                                                                */
1119     /* Good, we now compute each edge's properties according to the   */
1120     /* segments found on its position.  Basically, these are          */
1121     /*                                                                */
1122     /*  - the edge's main direction                                   */
1123     /*  - stem edge, serif edge or both (which defaults to stem then) */
1124     /*  - rounded edge, straight or both (which defaults to straight) */
1125     /*  - link for edge                                               */
1126     /*                                                                */
1127     /******************************************************************/
1128 
1129     /* first of all, set the `edge' field in each segment -- this is */
1130     /* required in order to compute edge links                       */
1131 
1132     /*
1133      * Note that removing this loop and setting the `edge' field of each
1134      * segment directly in the code above slows down execution speed for
1135      * some reasons on platforms like the Sun.
1136      */
1137     {
1138       AF_Edge  edges      = axis->edges;
1139       AF_Edge  edge_limit = edges + axis->num_edges;
1140       AF_Edge  edge;
1141 
1142 
1143       for ( edge = edges; edge < edge_limit; edge++ )
1144       {
1145         seg = edge->first;
1146         if ( seg )
1147           do


1157       {
1158         FT_Int  is_round    = 0;  /* does it contain round segments?    */
1159         FT_Int  is_straight = 0;  /* does it contain straight segments? */
1160 
1161 
1162         seg = edge->first;
1163 
1164         do
1165         {
1166           FT_Bool  is_serif;
1167 
1168 
1169           /* check for roundness of segment */
1170           if ( seg->flags & AF_EDGE_ROUND )
1171             is_round++;
1172           else
1173             is_straight++;
1174 
1175           /* check for links -- if seg->serif is set, then seg->link must */
1176           /* be ignored                                                   */
1177           is_serif = (FT_Bool)( seg->serif && seg->serif->edge != edge );
1178 
1179           if ( seg->link || is_serif )
1180           {
1181             AF_Edge     edge2;
1182             AF_Segment  seg2;
1183 
1184 
1185             edge2 = edge->link;
1186             seg2  = seg->link;
1187 
1188             if ( is_serif )
1189             {
1190               seg2  = seg->serif;
1191               edge2 = edge->serif;
1192             }
1193 
1194             if ( edge2 )
1195             {
1196               FT_Pos  edge_delta;
1197               FT_Pos  seg_delta;


   1 /****************************************************************************
   2  *
   3  * afcjk.c
   4  *
   5  *   Auto-fitter hinting routines for CJK writing system (body).
   6  *
   7  * Copyright (C) 2006-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    * The algorithm is based on akito's autohint patch, archived at
  20    *
  21    * https://web.archive.org/web/20051219160454/http://www.kde.gr.jp:80/~akito/patch/freetype2/2.1.7/
  22    *
  23    */
  24 
  25 #include <ft2build.h>
  26 #include FT_ADVANCES_H
  27 #include FT_INTERNAL_DEBUG_H
  28 
  29 #include "afglobal.h"

  30 #include "aflatin.h"
  31 #include "afcjk.h"
  32 
  33 
  34 #ifdef AF_CONFIG_OPTION_CJK
  35 
  36 #undef AF_CONFIG_OPTION_CJK_BLUE_HANI_VERT
  37 
  38 #include "aferrors.h"
  39 
  40 
  41 #ifdef AF_CONFIG_OPTION_USE_WARPER
  42 #include "afwarp.h"
  43 #endif
  44 
  45 
  46   /**************************************************************************
  47    *
  48    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
  49    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
  50    * messages during execution.
  51    */
  52 #undef  FT_COMPONENT
  53 #define FT_COMPONENT  afcjk
  54 
  55 
  56   /*************************************************************************/
  57   /*************************************************************************/
  58   /*****                                                               *****/
  59   /*****              C J K   G L O B A L   M E T R I C S              *****/
  60   /*****                                                               *****/
  61   /*************************************************************************/
  62   /*************************************************************************/
  63 
  64 
  65   /* Basically the Latin version with AF_CJKMetrics */
  66   /* to replace AF_LatinMetrics.                    */
  67 
  68   FT_LOCAL_DEF( void )
  69   af_cjk_metrics_init_widths( AF_CJKMetrics  metrics,
  70                               FT_Face        face )
  71   {
  72     /* scan the array of segments in each direction */
  73     AF_GlyphHintsRec  hints[1];
  74 
  75 
  76     FT_TRACE5(( "\n"
  77                 "cjk standard widths computation (style `%s')\n"
  78                 "===================================================\n"
  79                 "\n",
  80                 af_style_names[metrics->root.style_class->style] ));
  81 
  82     af_glyph_hints_init( hints, face->memory );
  83 
  84     metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
  85     metrics->axis[AF_DIMENSION_VERT].width_count = 0;
  86 
  87     {
  88       FT_Error          error;
  89       FT_ULong          glyph_index;
  90       int               dim;
  91       AF_CJKMetricsRec  dummy[1];
  92       AF_Scaler         scaler = &dummy->root.scaler;
  93 




  94       AF_StyleClass   style_class  = metrics->root.style_class;
  95       AF_ScriptClass  script_class = af_script_classes[style_class->script];

  96 
  97       /* If HarfBuzz is not available, we need a pointer to a single */
  98       /* unsigned long value.                                        */
  99 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
 100       void*     shaper_buf;
 101 #else
 102       FT_ULong  shaper_buf_;
 103       void*     shaper_buf = &shaper_buf_;
 104 #endif
 105 
 106       const char*  p;
 107 
 108 #ifdef FT_DEBUG_LEVEL_TRACE
 109       FT_ULong  ch = 0;
 110 #endif
 111 
 112       p = script_class->standard_charstring;
 113 
 114 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
 115       shaper_buf = af_shaper_buf_create( face );
 116 #endif
 117 
 118       /* We check a list of standard characters.  The first match wins. */
 119 
 120       glyph_index = 0;
 121       while ( *p )
 122       {
 123         unsigned int  num_idx;
 124 
 125 #ifdef FT_DEBUG_LEVEL_TRACE
 126         const char*  p_old;
 127 #endif
 128 
 129 
 130         while ( *p == ' ' )
 131           p++;
 132 
 133 #ifdef FT_DEBUG_LEVEL_TRACE
 134         p_old = p;
 135         GET_UTF8_CHAR( ch, p_old );
 136 #endif


 284                              FT_Face        face )
 285   {
 286     FT_Pos      fills[AF_BLUE_STRING_MAX_LEN];
 287     FT_Pos      flats[AF_BLUE_STRING_MAX_LEN];
 288 
 289     FT_UInt     num_fills;
 290     FT_UInt     num_flats;
 291 
 292     FT_Bool     fill;
 293 
 294     AF_CJKBlue  blue;
 295     FT_Error    error;
 296     AF_CJKAxis  axis;
 297     FT_Outline  outline;
 298 
 299     AF_StyleClass  sc = metrics->root.style_class;
 300 
 301     AF_Blue_Stringset         bss = sc->blue_stringset;
 302     const AF_Blue_StringRec*  bs  = &af_blue_stringsets[bss];
 303 
 304     /* If HarfBuzz is not available, we need a pointer to a single */
 305     /* unsigned long value.                                        */
 306 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
 307     void*     shaper_buf;
 308 #else
 309     FT_ULong  shaper_buf_;
 310     void*     shaper_buf = &shaper_buf_;
 311 #endif
 312 
 313 
 314     /* we walk over the blue character strings as specified in the   */
 315     /* style's entry in the `af_blue_stringset' array, computing its */
 316     /* extremum points (depending on the string properties)          */
 317 
 318     FT_TRACE5(( "cjk blue zones computation\n"
 319                 "==========================\n"
 320                 "\n" ));
 321 
 322 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
 323     shaper_buf = af_shaper_buf_create( face );
 324 #endif
 325 
 326     for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
 327     {
 328       const char*  p = &af_blue_strings[bs->string];
 329       FT_Pos*      blue_ref;
 330       FT_Pos*      blue_shoot;
 331 
 332 
 333       if ( AF_CJK_IS_HORIZ_BLUE( bs ) )
 334         axis = &metrics->axis[AF_DIMENSION_HORZ];
 335       else
 336         axis = &metrics->axis[AF_DIMENSION_VERT];
 337 
 338 #ifdef FT_DEBUG_LEVEL_TRACE
 339       {
 340         FT_String*  cjk_blue_name[4] =
 341         {
 342           (FT_String*)"bottom",    /* --   , --  */
 343           (FT_String*)"top",       /* --   , TOP */
 344           (FT_String*)"left",      /* HORIZ, --  */


 562 
 563     } /* end for loop */
 564 
 565     af_shaper_buf_destroy( face, shaper_buf );
 566 
 567     FT_TRACE5(( "\n" ));
 568 
 569     return;
 570   }
 571 
 572 
 573   /* Basically the Latin version with type AF_CJKMetrics for metrics. */
 574 
 575   FT_LOCAL_DEF( void )
 576   af_cjk_metrics_check_digits( AF_CJKMetrics  metrics,
 577                                FT_Face        face )
 578   {
 579     FT_Bool   started = 0, same_width = 1;
 580     FT_Fixed  advance = 0, old_advance = 0;
 581 
 582     /* If HarfBuzz is not available, we need a pointer to a single */
 583     /* unsigned long value.                                        */
 584 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
 585     void*     shaper_buf;
 586 #else
 587     FT_ULong  shaper_buf_;
 588     void*     shaper_buf = &shaper_buf_;
 589 #endif
 590 
 591     /* in all supported charmaps, digits have character codes 0x30-0x39 */
 592     const char   digits[] = "0 1 2 3 4 5 6 7 8 9";
 593     const char*  p;
 594 
 595 
 596     p = digits;
 597 
 598 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
 599     shaper_buf = af_shaper_buf_create( face );
 600 #endif
 601 
 602     while ( *p )
 603     {
 604       FT_ULong      glyph_index;
 605       unsigned int  num_idx;
 606 
 607 
 608       /* reject input that maps to more than a single glyph */
 609       p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
 610       if ( num_idx > 1 )
 611         continue;
 612 
 613       glyph_index = af_shaper_get_elem( &metrics->root,
 614                                         shaper_buf,
 615                                         0,
 616                                         &advance,
 617                                         NULL );
 618       if ( !glyph_index )
 619         continue;
 620 


1007                               AF_Dimension   dim )
1008   {
1009     AF_AxisHints  axis   = &hints->axis[dim];
1010     FT_Error      error  = FT_Err_Ok;
1011     FT_Memory     memory = hints->memory;
1012     AF_CJKAxis    laxis  = &((AF_CJKMetrics)hints->metrics)->axis[dim];
1013 
1014     AF_Segment    segments      = axis->segments;
1015     AF_Segment    segment_limit = segments + axis->num_segments;
1016     AF_Segment    seg;
1017 
1018     FT_Fixed      scale;
1019     FT_Pos        edge_distance_threshold;
1020 
1021 
1022     axis->num_edges = 0;
1023 
1024     scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
1025                                          : hints->y_scale;
1026 
1027     /**********************************************************************
1028      *
1029      * We begin by generating a sorted table of edges for the current
1030      * direction.  To do so, we simply scan each segment and try to find
1031      * an edge in our table that corresponds to its position.
1032      *
1033      * If no edge is found, we create and insert a new edge in the
1034      * sorted table.  Otherwise, we simply add the segment to the edge's
1035      * list which is then processed in the second step to compute the
1036      * edge's properties.
1037      *
1038      * Note that the edges table is sorted along the segment/edge
1039      * position.
1040      *
1041      */
1042 
1043     edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
1044                                          scale );
1045     if ( edge_distance_threshold > 64 / 4 )
1046       edge_distance_threshold = FT_DivFix( 64 / 4, scale );
1047     else
1048       edge_distance_threshold = laxis->edge_distance_threshold;
1049 
1050     for ( seg = segments; seg < segment_limit; seg++ )
1051     {
1052       AF_Edge  found = NULL;
1053       FT_Pos   best  = 0xFFFFU;
1054       FT_Int   ee;
1055 
1056 
1057       /* look for an edge corresponding to the segment */
1058       for ( ee = 0; ee < axis->num_edges; ee++ )
1059       {
1060         AF_Edge  edge = axis->edges + ee;
1061         FT_Pos   dist;


1121         FT_ZERO( edge );
1122 
1123         edge->first    = seg;
1124         edge->last     = seg;
1125         edge->dir      = seg->dir;
1126         edge->fpos     = seg->pos;
1127         edge->opos     = FT_MulFix( seg->pos, scale );
1128         edge->pos      = edge->opos;
1129         seg->edge_next = seg;
1130       }
1131       else
1132       {
1133         /* if an edge was found, simply add the segment to the edge's */
1134         /* list                                                       */
1135         seg->edge_next         = found->first;
1136         found->last->edge_next = seg;
1137         found->last            = seg;
1138       }
1139     }
1140 
1141     /*******************************************************************
1142      *
1143      * Good, we now compute each edge's properties according to the
1144      * segments found on its position.  Basically, these are
1145      *
1146      * - the edge's main direction
1147      * - stem edge, serif edge or both (which defaults to stem then)
1148      * - rounded edge, straight or both (which defaults to straight)
1149      * - link for edge
1150      *
1151      */
1152 
1153     /* first of all, set the `edge' field in each segment -- this is */
1154     /* required in order to compute edge links                       */
1155 
1156     /*
1157      * Note that removing this loop and setting the `edge' field of each
1158      * segment directly in the code above slows down execution speed for
1159      * some reasons on platforms like the Sun.
1160      */
1161     {
1162       AF_Edge  edges      = axis->edges;
1163       AF_Edge  edge_limit = edges + axis->num_edges;
1164       AF_Edge  edge;
1165 
1166 
1167       for ( edge = edges; edge < edge_limit; edge++ )
1168       {
1169         seg = edge->first;
1170         if ( seg )
1171           do


1181       {
1182         FT_Int  is_round    = 0;  /* does it contain round segments?    */
1183         FT_Int  is_straight = 0;  /* does it contain straight segments? */
1184 
1185 
1186         seg = edge->first;
1187 
1188         do
1189         {
1190           FT_Bool  is_serif;
1191 
1192 
1193           /* check for roundness of segment */
1194           if ( seg->flags & AF_EDGE_ROUND )
1195             is_round++;
1196           else
1197             is_straight++;
1198 
1199           /* check for links -- if seg->serif is set, then seg->link must */
1200           /* be ignored                                                   */
1201           is_serif = FT_BOOL( seg->serif && seg->serif->edge != edge );
1202 
1203           if ( seg->link || is_serif )
1204           {
1205             AF_Edge     edge2;
1206             AF_Segment  seg2;
1207 
1208 
1209             edge2 = edge->link;
1210             seg2  = seg->link;
1211 
1212             if ( is_serif )
1213             {
1214               seg2  = seg->serif;
1215               edge2 = edge->serif;
1216             }
1217 
1218             if ( edge2 )
1219             {
1220               FT_Pos  edge_delta;
1221               FT_Pos  seg_delta;


< prev index next >