1 /***************************************************************************/ |
1 /**************************************************************************** |
2 /* */ |
2 * |
3 /* aflatin.c */ |
3 * aflatin.c |
4 /* */ |
4 * |
5 /* Auto-fitter hinting routines for latin writing system (body). */ |
5 * Auto-fitter hinting routines for latin writing system (body). |
6 /* */ |
6 * |
7 /* Copyright 2003-2018 by */ |
7 * Copyright (C) 2003-2019 by |
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
8 * David Turner, Robert Wilhelm, and Werner Lemberg. |
9 /* */ |
9 * |
10 /* This file is part of the FreeType project, and may only be used, */ |
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 */ |
11 * modified, and distributed under the terms of the FreeType project |
12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ |
12 * license, LICENSE.TXT. By continuing to use, modify, or distribute |
13 /* this file you indicate that you have read the license and */ |
13 * this file you indicate that you have read the license and |
14 /* understand and accept it fully. */ |
14 * understand and accept it fully. |
15 /* */ |
15 * |
16 /***************************************************************************/ |
16 */ |
17 |
17 |
18 |
18 |
19 #include <ft2build.h> |
19 #include <ft2build.h> |
20 #include FT_ADVANCES_H |
20 #include FT_ADVANCES_H |
21 #include FT_INTERNAL_DEBUG_H |
21 #include FT_INTERNAL_DEBUG_H |
22 |
22 |
23 #include "afglobal.h" |
23 #include "afglobal.h" |
24 #include "afpic.h" |
|
25 #include "aflatin.h" |
24 #include "aflatin.h" |
26 #include "aferrors.h" |
25 #include "aferrors.h" |
27 |
26 |
28 |
27 |
29 #ifdef AF_CONFIG_OPTION_USE_WARPER |
28 #ifdef AF_CONFIG_OPTION_USE_WARPER |
30 #include "afwarp.h" |
29 #include "afwarp.h" |
31 #endif |
30 #endif |
32 |
31 |
33 |
32 |
34 /*************************************************************************/ |
33 /************************************************************************** |
35 /* */ |
34 * |
36 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ |
35 * 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 */ |
36 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log |
38 /* messages during execution. */ |
37 * messages during execution. |
39 /* */ |
38 */ |
40 #undef FT_COMPONENT |
39 #undef FT_COMPONENT |
41 #define FT_COMPONENT trace_aflatin |
40 #define FT_COMPONENT aflatin |
42 |
41 |
43 |
42 |
44 /* needed for computation of round vs. flat segments */ |
43 /* needed for computation of round vs. flat segments */ |
45 #define FLAT_THRESHOLD( x ) ( x / 14 ) |
44 #define FLAT_THRESHOLD( x ) ( x / 14 ) |
46 |
45 |
81 FT_ULong glyph_index; |
80 FT_ULong glyph_index; |
82 int dim; |
81 int dim; |
83 AF_LatinMetricsRec dummy[1]; |
82 AF_LatinMetricsRec dummy[1]; |
84 AF_Scaler scaler = &dummy->root.scaler; |
83 AF_Scaler scaler = &dummy->root.scaler; |
85 |
84 |
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; |
85 AF_StyleClass style_class = metrics->root.style_class; |
91 AF_ScriptClass script_class = AF_SCRIPT_CLASSES_GET |
86 AF_ScriptClass script_class = af_script_classes[style_class->script]; |
92 [style_class->script]; |
87 |
93 |
88 /* If HarfBuzz is not available, we need a pointer to a single */ |
94 void* shaper_buf; |
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 |
95 const char* p; |
97 const char* p; |
96 |
98 |
97 #ifdef FT_DEBUG_LEVEL_TRACE |
99 #ifdef FT_DEBUG_LEVEL_TRACE |
98 FT_ULong ch = 0; |
100 FT_ULong ch = 0; |
99 #endif |
101 #endif |
100 |
102 |
101 p = script_class->standard_charstring; |
103 |
|
104 p = script_class->standard_charstring; |
|
105 |
|
106 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ |
102 shaper_buf = af_shaper_buf_create( face ); |
107 shaper_buf = af_shaper_buf_create( face ); |
103 |
108 #endif |
104 /* |
109 /* |
105 * We check a list of standard characters to catch features like |
110 * We check a list of standard characters to catch features like |
106 * `c2sc' (small caps from caps) that don't contain lowercase letters |
111 * `c2sc' (small caps from caps) that don't contain lowercase letters |
107 * by definition, or other features that mainly operate on numerals. |
112 * by definition, or other features that mainly operate on numerals. |
108 * The first match wins. |
113 * The first match wins. |
327 AF_Blue_Stringset bss = sc->blue_stringset; |
332 AF_Blue_Stringset bss = sc->blue_stringset; |
328 const AF_Blue_StringRec* bs = &af_blue_stringsets[bss]; |
333 const AF_Blue_StringRec* bs = &af_blue_stringsets[bss]; |
329 |
334 |
330 FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em ); |
335 FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em ); |
331 |
336 |
332 void* shaper_buf; |
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 |
333 |
345 |
334 |
346 |
335 /* we walk over the blue character strings as specified in the */ |
347 /* we walk over the blue character strings as specified in the */ |
336 /* style's entry in the `af_blue_stringset' array */ |
348 /* style's entry in the `af_blue_stringset' array */ |
337 |
349 |
338 FT_TRACE5(( "latin blue zones computation\n" |
350 FT_TRACE5(( "latin blue zones computation\n" |
339 "============================\n" |
351 "============================\n" |
340 "\n" )); |
352 "\n" )); |
341 |
353 |
|
354 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ |
342 shaper_buf = af_shaper_buf_create( face ); |
355 shaper_buf = af_shaper_buf_create( face ); |
|
356 #endif |
343 |
357 |
344 for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) |
358 for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ ) |
345 { |
359 { |
346 const char* p = &af_blue_strings[bs->string]; |
360 const char* p = &af_blue_strings[bs->string]; |
347 FT_Pos* blue_ref; |
361 FT_Pos* blue_ref; |
1034 FT_Face face ) |
1048 FT_Face face ) |
1035 { |
1049 { |
1036 FT_Bool started = 0, same_width = 1; |
1050 FT_Bool started = 0, same_width = 1; |
1037 FT_Fixed advance = 0, old_advance = 0; |
1051 FT_Fixed advance = 0, old_advance = 0; |
1038 |
1052 |
1039 void* shaper_buf; |
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 |
1040 |
1061 |
1041 /* in all supported charmaps, digits have character codes 0x30-0x39 */ |
1062 /* in all supported charmaps, digits have character codes 0x30-0x39 */ |
1042 const char digits[] = "0 1 2 3 4 5 6 7 8 9"; |
1063 const char digits[] = "0 1 2 3 4 5 6 7 8 9"; |
1043 const char* p; |
1064 const char* p; |
1044 |
1065 |
1045 |
1066 |
1046 p = digits; |
1067 p = digits; |
|
1068 |
|
1069 #ifdef FT_CONFIG_OPTION_USE_HARFBUZZ |
1047 shaper_buf = af_shaper_buf_create( face ); |
1070 shaper_buf = af_shaper_buf_create( face ); |
|
1071 #endif |
1048 |
1072 |
1049 while ( *p ) |
1073 while ( *p ) |
1050 { |
1074 { |
1051 FT_ULong glyph_index; |
1075 FT_ULong glyph_index; |
1052 unsigned int num_idx; |
1076 unsigned int num_idx; |
1281 FT_TRACE5(( "\n" )); |
1305 FT_TRACE5(( "\n" )); |
1282 |
1306 |
1283 /* an extra-light axis corresponds to a standard width that is */ |
1307 /* an extra-light axis corresponds to a standard width that is */ |
1284 /* smaller than 5/8 pixels */ |
1308 /* smaller than 5/8 pixels */ |
1285 axis->extra_light = |
1309 axis->extra_light = |
1286 (FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 ); |
1310 FT_BOOL( FT_MulFix( axis->standard_width, scale ) < 32 + 8 ); |
1287 |
1311 |
1288 #ifdef FT_DEBUG_LEVEL_TRACE |
1312 #ifdef FT_DEBUG_LEVEL_TRACE |
1289 if ( axis->extra_light ) |
1313 if ( axis->extra_light ) |
1290 FT_TRACE5(( "`%s' style is extra light (at current resolution)\n" |
1314 FT_TRACE5(( "`%s' style is extra light (at current resolution)\n" |
1291 "\n", |
1315 "\n", |
1965 /* (this is, how much they overlap) */ |
1989 /* (this is, how much they overlap) */ |
1966 len = max - min; |
1990 len = max - min; |
1967 if ( len >= len_threshold ) |
1991 if ( len >= len_threshold ) |
1968 { |
1992 { |
1969 /* |
1993 /* |
1970 * The score is the sum of two demerits indicating the |
1994 * The score is the sum of two demerits indicating the |
1971 * `badness' of a fit, measured along the segments' main axis |
1995 * `badness' of a fit, measured along the segments' main axis |
1972 * and orthogonal to it, respectively. |
1996 * and orthogonal to it, respectively. |
1973 * |
1997 * |
1974 * o The less overlapping along the main axis, the worse it |
1998 * - The less overlapping along the main axis, the worse it |
1975 * is, causing a larger demerit. |
1999 * is, causing a larger demerit. |
1976 * |
2000 * |
1977 * o The nearer the orthogonal distance to a stem width, the |
2001 * - The nearer the orthogonal distance to a stem width, the |
1978 * better it is, causing a smaller demerit. For simplicity, |
2002 * better it is, causing a smaller demerit. For simplicity, |
1979 * however, we only increase the demerit for values that |
2003 * however, we only increase the demerit for values that |
1980 * exceed the largest stem width. |
2004 * exceed the largest stem width. |
1981 */ |
2005 */ |
1982 |
2006 |
1983 FT_Pos dist = pos2 - pos1; |
2007 FT_Pos dist = pos2 - pos1; |
1984 |
2008 |
1985 FT_Pos dist_demerit, score; |
2009 FT_Pos dist_demerit, score; |
2047 AF_AxisHints axis = &hints->axis[dim]; |
2071 AF_AxisHints axis = &hints->axis[dim]; |
2048 FT_Error error = FT_Err_Ok; |
2072 FT_Error error = FT_Err_Ok; |
2049 FT_Memory memory = hints->memory; |
2073 FT_Memory memory = hints->memory; |
2050 AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim]; |
2074 AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim]; |
2051 |
2075 |
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; |
2076 AF_StyleClass style_class = hints->metrics->style_class; |
2057 AF_ScriptClass script_class = AF_SCRIPT_CLASSES_GET |
2077 AF_ScriptClass script_class = af_script_classes[style_class->script]; |
2058 [style_class->script]; |
|
2059 |
2078 |
2060 FT_Bool top_to_bottom_hinting = 0; |
2079 FT_Bool top_to_bottom_hinting = 0; |
2061 |
2080 |
2062 AF_Segment segments = axis->segments; |
2081 AF_Segment segments = axis->segments; |
2063 AF_Segment segment_limit = segments + axis->num_segments; |
2082 AF_Segment segment_limit = segments + axis->num_segments; |
2084 |
2103 |
2085 if ( dim == AF_DIMENSION_VERT ) |
2104 if ( dim == AF_DIMENSION_VERT ) |
2086 top_to_bottom_hinting = script_class->top_to_bottom_hinting; |
2105 top_to_bottom_hinting = script_class->top_to_bottom_hinting; |
2087 |
2106 |
2088 /* |
2107 /* |
2089 * We ignore all segments that are less than 1 pixel in length |
2108 * We ignore all segments that are less than 1 pixel in length |
2090 * to avoid many problems with serif fonts. We compute the |
2109 * to avoid many problems with serif fonts. We compute the |
2091 * corresponding threshold in font units. |
2110 * corresponding threshold in font units. |
2092 */ |
2111 */ |
2093 if ( dim == AF_DIMENSION_HORZ ) |
2112 if ( dim == AF_DIMENSION_HORZ ) |
2094 segment_length_threshold = FT_DivFix( 64, hints->y_scale ); |
2113 segment_length_threshold = FT_DivFix( 64, hints->y_scale ); |
2095 else |
2114 else |
2096 segment_length_threshold = 0; |
2115 segment_length_threshold = 0; |
2097 |
2116 |
2098 /* |
2117 /* |
2099 * Similarly, we ignore segments that have a width delta |
2118 * Similarly, we ignore segments that have a width delta |
2100 * larger than 0.5px (i.e., a width larger than 1px). |
2119 * larger than 0.5px (i.e., a width larger than 1px). |
2101 */ |
2120 */ |
2102 segment_width_threshold = FT_DivFix( 32, scale ); |
2121 segment_width_threshold = FT_DivFix( 32, scale ); |
2103 |
2122 |
2104 /*********************************************************************/ |
2123 /********************************************************************** |
2105 /* */ |
2124 * |
2106 /* We begin by generating a sorted table of edges for the current */ |
2125 * 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 */ |
2126 * direction. To do so, we simply scan each segment and try to find |
2108 /* an edge in our table that corresponds to its position. */ |
2127 * an edge in our table that corresponds to its position. |
2109 /* */ |
2128 * |
2110 /* If no edge is found, we create and insert a new edge in the */ |
2129 * 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 */ |
2130 * sorted table. Otherwise, we simply add the segment to the edge's |
2112 /* list which gets processed in the second step to compute the */ |
2131 * list which gets processed in the second step to compute the |
2113 /* edge's properties. */ |
2132 * edge's properties. |
2114 /* */ |
2133 * |
2115 /* Note that the table of edges is sorted along the segment/edge */ |
2134 * Note that the table of edges is sorted along the segment/edge |
2116 /* position. */ |
2135 * position. |
2117 /* */ |
2136 * |
2118 /*********************************************************************/ |
2137 */ |
2119 |
2138 |
2120 /* assure that edge distance threshold is at most 0.25px */ |
2139 /* assure that edge distance threshold is at most 0.25px */ |
2121 edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold, |
2140 edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold, |
2122 scale ); |
2141 scale ); |
2123 if ( edge_distance_threshold > 64 / 4 ) |
2142 if ( edge_distance_threshold > 64 / 4 ) |
2235 found->last = seg; |
2254 found->last = seg; |
2236 } |
2255 } |
2237 } |
2256 } |
2238 |
2257 |
2239 |
2258 |
2240 /******************************************************************/ |
2259 /******************************************************************* |
2241 /* */ |
2260 * |
2242 /* Good, we now compute each edge's properties according to the */ |
2261 * Good, we now compute each edge's properties according to the |
2243 /* segments found on its position. Basically, these are */ |
2262 * segments found on its position. Basically, these are |
2244 /* */ |
2263 * |
2245 /* - the edge's main direction */ |
2264 * - the edge's main direction |
2246 /* - stem edge, serif edge or both (which defaults to stem then) */ |
2265 * - stem edge, serif edge or both (which defaults to stem then) |
2247 /* - rounded edge, straight or both (which defaults to straight) */ |
2266 * - rounded edge, straight or both (which defaults to straight) |
2248 /* - link for edge */ |
2267 * - link for edge |
2249 /* */ |
2268 * |
2250 /******************************************************************/ |
2269 */ |
2251 |
2270 |
2252 /* first of all, set the `edge' field in each segment -- this is */ |
2271 /* first of all, set the `edge' field in each segment -- this is */ |
2253 /* required in order to compute edge links */ |
2272 /* required in order to compute edge links */ |
2254 |
2273 |
2255 /* |
2274 /* |
2544 |
2563 |
2545 |
2564 |
2546 af_glyph_hints_rescale( hints, (AF_StyleMetrics)metrics ); |
2565 af_glyph_hints_rescale( hints, (AF_StyleMetrics)metrics ); |
2547 |
2566 |
2548 /* |
2567 /* |
2549 * correct x_scale and y_scale if needed, since they may have |
2568 * correct x_scale and y_scale if needed, since they may have |
2550 * been modified by `af_latin_metrics_scale_dim' above |
2569 * been modified by `af_latin_metrics_scale_dim' above |
2551 */ |
2570 */ |
2552 hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale; |
2571 hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale; |
2553 hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta; |
2572 hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta; |
2554 hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale; |
2573 hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale; |
2555 hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta; |
2574 hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta; |
2564 |
2583 |
2565 scaler_flags = hints->scaler_flags; |
2584 scaler_flags = hints->scaler_flags; |
2566 other_flags = 0; |
2585 other_flags = 0; |
2567 |
2586 |
2568 /* |
2587 /* |
2569 * We snap the width of vertical stems for the monochrome and |
2588 * We snap the width of vertical stems for the monochrome and |
2570 * horizontal LCD rendering targets only. |
2589 * horizontal LCD rendering targets only. |
2571 */ |
2590 */ |
2572 if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD ) |
2591 if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD ) |
2573 other_flags |= AF_LATIN_HINTS_HORZ_SNAP; |
2592 other_flags |= AF_LATIN_HINTS_HORZ_SNAP; |
2574 |
2593 |
2575 /* |
2594 /* |
2576 * We snap the width of horizontal stems for the monochrome and |
2595 * We snap the width of horizontal stems for the monochrome and |
2577 * vertical LCD rendering targets only. |
2596 * vertical LCD rendering targets only. |
2578 */ |
2597 */ |
2579 if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V ) |
2598 if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V ) |
2580 other_flags |= AF_LATIN_HINTS_VERT_SNAP; |
2599 other_flags |= AF_LATIN_HINTS_VERT_SNAP; |
2581 |
2600 |
2582 /* |
2601 /* |
2583 * We adjust stems to full pixels unless in `light' or `lcd' mode. |
2602 * We adjust stems to full pixels unless in `light' or `lcd' mode. |
2584 */ |
2603 */ |
2585 if ( mode != FT_RENDER_MODE_LIGHT && mode != FT_RENDER_MODE_LCD ) |
2604 if ( mode != FT_RENDER_MODE_LIGHT && mode != FT_RENDER_MODE_LCD ) |
2586 other_flags |= AF_LATIN_HINTS_STEM_ADJUST; |
2605 other_flags |= AF_LATIN_HINTS_STEM_ADJUST; |
2587 |
2606 |
2588 if ( mode == FT_RENDER_MODE_MONO ) |
2607 if ( mode == FT_RENDER_MODE_MONO ) |
2589 other_flags |= AF_LATIN_HINTS_MONO; |
2608 other_flags |= AF_LATIN_HINTS_MONO; |
2590 |
2609 |
2591 /* |
2610 /* |
2592 * In `light' or `lcd' mode we disable horizontal hinting completely. |
2611 * In `light' or `lcd' mode we disable horizontal hinting completely. |
2593 * We also do it if the face is italic. |
2612 * We also do it if the face is italic. |
2594 * |
2613 * |
2595 * However, if warping is enabled (which only works in `light' hinting |
2614 * However, if warping is enabled (which only works in `light' hinting |
2596 * mode), advance widths get adjusted, too. |
2615 * mode), advance widths get adjusted, too. |
2597 */ |
2616 */ |
2598 if ( mode == FT_RENDER_MODE_LIGHT || mode == FT_RENDER_MODE_LCD || |
2617 if ( mode == FT_RENDER_MODE_LIGHT || mode == FT_RENDER_MODE_LCD || |
2599 ( face->style_flags & FT_STYLE_FLAG_ITALIC ) != 0 ) |
2618 ( face->style_flags & FT_STYLE_FLAG_ITALIC ) != 0 ) |
2600 scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL; |
2619 scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL; |
2601 |
2620 |
2934 FT_PtrDist n_edges; |
2953 FT_PtrDist n_edges; |
2935 AF_Edge edge; |
2954 AF_Edge edge; |
2936 AF_Edge anchor = NULL; |
2955 AF_Edge anchor = NULL; |
2937 FT_Int has_serifs = 0; |
2956 FT_Int has_serifs = 0; |
2938 |
2957 |
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; |
2958 AF_StyleClass style_class = hints->metrics->style_class; |
2944 AF_ScriptClass script_class = AF_SCRIPT_CLASSES_GET |
2959 AF_ScriptClass script_class = af_script_classes[style_class->script]; |
2945 [style_class->script]; |
|
2946 |
2960 |
2947 FT_Bool top_to_bottom_hinting = 0; |
2961 FT_Bool top_to_bottom_hinting = 0; |
2948 |
2962 |
2949 #ifdef FT_DEBUG_LEVEL_TRACE |
2963 #ifdef FT_DEBUG_LEVEL_TRACE |
2950 FT_UInt num_actions = 0; |
2964 FT_UInt num_actions = 0; |
2974 |
2988 |
2975 edge1 = NULL; |
2989 edge1 = NULL; |
2976 edge2 = edge->link; |
2990 edge2 = edge->link; |
2977 |
2991 |
2978 /* |
2992 /* |
2979 * If a stem contains both a neutral and a non-neutral blue zone, |
2993 * If a stem contains both a neutral and a non-neutral blue zone, |
2980 * skip the neutral one. Otherwise, outlines with different |
2994 * skip the neutral one. Otherwise, outlines with different |
2981 * directions might be incorrectly aligned at the same vertical |
2995 * directions might be incorrectly aligned at the same vertical |
2982 * position. |
2996 * position. |
2983 * |
2997 * |
2984 * If we have two neutral blue zones, skip one of them. |
2998 * If we have two neutral blue zones, skip one of them. |
2985 * |
2999 * |
2986 */ |
3000 */ |
2987 if ( edge->blue_edge && edge2 && edge2->blue_edge ) |
3001 if ( edge->blue_edge && edge2 && edge2->blue_edge ) |
2988 { |
3002 { |
2989 FT_Byte neutral = edge->flags & AF_EDGE_NEUTRAL; |
3003 FT_Byte neutral = edge->flags & AF_EDGE_NEUTRAL; |