ReactOS 0.4.16-dev-2358-g0df3463
aflatin.c File Reference
#include <freetype/ftadvanc.h>
#include <freetype/internal/ftdebug.h>
#include "afglobal.h"
#include "aflatin.h"
#include "aferrors.h"
Include dependency graph for aflatin.c:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define FT_COMPONENT   aflatin
 
#define FLAT_THRESHOLD(x)   ( x / 14 )
 

Functions

 af_latin_metrics_init_widths (AF_LatinMetrics metrics, FT_Face face)
 
static void af_latin_sort_blue (FT_UInt count, AF_LatinBlue *table)
 
static int af_latin_metrics_init_blues (AF_LatinMetrics metrics, FT_Face face)
 
 af_latin_metrics_check_digits (AF_LatinMetrics metrics, FT_Face face)
 
 af_latin_metrics_init (AF_LatinMetrics metrics, FT_Face face)
 
static void af_latin_metrics_scale_dim (AF_LatinMetrics metrics, AF_Scaler scaler, AF_Dimension dim)
 
 af_latin_metrics_scale (AF_LatinMetrics metrics, AF_Scaler scaler)
 
 af_latin_get_standard_widths (AF_LatinMetrics metrics, FT_Pos *stdHW, FT_Pos *stdVW)
 
 af_latin_hints_compute_segments (AF_GlyphHints hints, AF_Dimension dim)
 
 af_latin_hints_link_segments (AF_GlyphHints hints, FT_UInt width_count, AF_WidthRec *widths, AF_Dimension dim)
 
 af_latin_hints_compute_edges (AF_GlyphHints hints, AF_Dimension dim)
 
 af_latin_hints_detect_features (AF_GlyphHints hints, FT_UInt width_count, AF_WidthRec *widths, AF_Dimension dim)
 
static void af_latin_hints_compute_blue_edges (AF_GlyphHints hints, AF_LatinMetrics metrics)
 
static FT_Error af_latin_hints_init (AF_GlyphHints hints, AF_LatinMetrics metrics)
 
static FT_Pos af_latin_snap_width (AF_Width widths, FT_UInt count, FT_Pos width)
 
static FT_Pos af_latin_compute_stem_width (AF_GlyphHints hints, AF_Dimension dim, FT_Pos width, FT_Pos base_delta, FT_UInt base_flags, FT_UInt stem_flags)
 
static void af_latin_align_linked_edge (AF_GlyphHints hints, AF_Dimension dim, AF_Edge base_edge, AF_Edge stem_edge)
 
static void af_latin_align_serif_edge (AF_GlyphHints hints, AF_Edge base, AF_Edge serif)
 
static void af_latin_hint_edges (AF_GlyphHints hints, AF_Dimension dim)
 
static FT_Error af_latin_hints_apply (FT_UInt glyph_index, AF_GlyphHints hints, FT_Outline *outline, AF_LatinMetrics metrics)
 

Macro Definition Documentation

◆ FLAT_THRESHOLD

#define FLAT_THRESHOLD (   x)    ( x / 14 )

Definition at line 43 of file aflatin.c.

◆ FT_COMPONENT

#define FT_COMPONENT   aflatin

Definition at line 39 of file aflatin.c.

Function Documentation

◆ af_latin_align_linked_edge()

static void af_latin_align_linked_edge ( AF_GlyphHints  hints,
AF_Dimension  dim,
AF_Edge  base_edge,
AF_Edge  stem_edge 
)
static

Definition at line 2945 of file aflatin.c.

2949 {
2950 FT_Pos dist, base_delta;
2951 FT_Pos fitted_width;
2952
2953
2954 dist = stem_edge->opos - base_edge->opos;
2955 base_delta = base_edge->pos - base_edge->opos;
2956
2957 fitted_width = af_latin_compute_stem_width( hints, dim,
2958 dist, base_delta,
2959 base_edge->flags,
2960 stem_edge->flags );
2961
2962
2963 stem_edge->pos = base_edge->pos + fitted_width;
2964
2965 FT_TRACE5(( " LINK: edge %ld (opos=%.2f) linked to %.2f,"
2966 " dist was %.2f, now %.2f\n",
2967 stem_edge - hints->axis[dim].edges, stem_edge->opos / 64.0,
2968 stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 ));
2969 }
static FT_Pos af_latin_compute_stem_width(AF_GlyphHints hints, AF_Dimension dim, FT_Pos width, FT_Pos base_delta, FT_UInt base_flags, FT_UInt stem_flags)
Definition: aflatin.c:2748
#define FT_TRACE5(varformat)
Definition: ftdebug.h:192
FT_BEGIN_HEADER typedef signed long FT_Pos
Definition: ftimage.h:57
namespace GUID const ADDRINFOEXW * hints
Definition: sock.c:80
FT_Pos pos
Definition: afhints.h:292
FT_Pos opos
Definition: afhints.h:291
FT_Byte flags
Definition: afhints.h:294

Referenced by af_latin_hint_edges().

◆ af_latin_align_serif_edge()

static void af_latin_align_serif_edge ( AF_GlyphHints  hints,
AF_Edge  base,
AF_Edge  serif 
)
static

Definition at line 2976 of file aflatin.c.

2979 {
2980 FT_UNUSED( hints );
2981
2982 serif->pos = base->pos + ( serif->opos - base->opos );
2983 }
#define FT_UNUSED(arg)

Referenced by af_latin_hint_edges().

◆ af_latin_compute_stem_width()

static FT_Pos af_latin_compute_stem_width ( AF_GlyphHints  hints,
AF_Dimension  dim,
FT_Pos  width,
FT_Pos  base_delta,
FT_UInt  base_flags,
FT_UInt  stem_flags 
)
static

Definition at line 2748 of file aflatin.c.

2754 {
2756 AF_LatinAxis axis = &metrics->axis[dim];
2757 FT_Pos dist = width;
2758 FT_Int sign = 0;
2759 FT_Int vertical = ( dim == AF_DIMENSION_VERT );
2760
2761
2763 axis->extra_light )
2764 return width;
2765
2766 if ( dist < 0 )
2767 {
2768 dist = -width;
2769 sign = 1;
2770 }
2771
2772 if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
2773 ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
2774 {
2775 /* smooth hinting process: very lightly quantize the stem width */
2776
2777 /* leave the widths of serifs alone */
2778 if ( ( stem_flags & AF_EDGE_SERIF ) &&
2779 vertical &&
2780 ( dist < 3 * 64 ) )
2781 goto Done_Width;
2782
2783 else if ( base_flags & AF_EDGE_ROUND )
2784 {
2785 if ( dist < 80 )
2786 dist = 64;
2787 }
2788 else if ( dist < 56 )
2789 dist = 56;
2790
2791 if ( axis->width_count > 0 )
2792 {
2793 FT_Pos delta;
2794
2795
2796 /* compare to standard width */
2797 delta = dist - axis->widths[0].cur;
2798
2799 if ( delta < 0 )
2800 delta = -delta;
2801
2802 if ( delta < 40 )
2803 {
2804 dist = axis->widths[0].cur;
2805 if ( dist < 48 )
2806 dist = 48;
2807
2808 goto Done_Width;
2809 }
2810
2811 if ( dist < 3 * 64 )
2812 {
2813 delta = dist & 63;
2814 dist &= -64;
2815
2816 if ( delta < 10 )
2817 dist += delta;
2818
2819 else if ( delta < 32 )
2820 dist += 10;
2821
2822 else if ( delta < 54 )
2823 dist += 54;
2824
2825 else
2826 dist += delta;
2827 }
2828 else
2829 {
2830 /* A stem's end position depends on two values: the start */
2831 /* position and the stem length. The former gets usually */
2832 /* rounded to the grid, while the latter gets rounded also if it */
2833 /* exceeds a certain length (see below in this function). This */
2834 /* `double rounding' can lead to a great difference to the */
2835 /* original, unhinted position; this normally doesn't matter for */
2836 /* large PPEM values, but for small sizes it can easily make */
2837 /* outlines collide. For this reason, we adjust the stem length */
2838 /* by a small amount depending on the PPEM value in case the */
2839 /* former and latter rounding both point into the same */
2840 /* direction. */
2841
2842 FT_Pos bdelta = 0;
2843
2844
2845 if ( ( ( width > 0 ) && ( base_delta > 0 ) ) ||
2846 ( ( width < 0 ) && ( base_delta < 0 ) ) )
2847 {
2848 FT_UInt ppem = metrics->root.scaler.face->size->metrics.x_ppem;
2849
2850
2851 if ( ppem < 10 )
2852 bdelta = base_delta;
2853 else if ( ppem < 30 )
2854 bdelta = ( base_delta * (FT_Pos)( 30 - ppem ) ) / 20;
2855
2856 if ( bdelta < 0 )
2857 bdelta = -bdelta;
2858 }
2859
2860 dist = ( dist - bdelta + 32 ) & ~63;
2861 }
2862 }
2863 }
2864 else
2865 {
2866 /* strong hinting process: snap the stem width to integer pixels */
2867
2868 FT_Pos org_dist = dist;
2869
2870
2871 dist = af_latin_snap_width( axis->widths, axis->width_count, dist );
2872
2873 if ( vertical )
2874 {
2875 /* in the case of vertical hinting, always round */
2876 /* the stem heights to integer pixels */
2877
2878 if ( dist >= 64 )
2879 dist = ( dist + 16 ) & ~63;
2880 else
2881 dist = 64;
2882 }
2883 else
2884 {
2886 {
2887 /* monochrome horizontal hinting: snap widths to integer pixels */
2888 /* with a different threshold */
2889
2890 if ( dist < 64 )
2891 dist = 64;
2892 else
2893 dist = ( dist + 32 ) & ~63;
2894 }
2895 else
2896 {
2897 /* for horizontal anti-aliased hinting, we adopt a more subtle */
2898 /* approach: we strengthen small stems, round stems whose size */
2899 /* is between 1 and 2 pixels to an integer, otherwise nothing */
2900
2901 if ( dist < 48 )
2902 dist = ( dist + 64 ) >> 1;
2903
2904 else if ( dist < 128 )
2905 {
2906 /* We only round to an integer width if the corresponding */
2907 /* distortion is less than 1/4 pixel. Otherwise this */
2908 /* makes everything worse since the diagonals, which are */
2909 /* not hinted, appear a lot bolder or thinner than the */
2910 /* vertical stems. */
2911
2912 FT_Pos delta;
2913
2914
2915 dist = ( dist + 22 ) & ~63;
2916 delta = dist - org_dist;
2917 if ( delta < 0 )
2918 delta = -delta;
2919
2920 if ( delta >= 16 )
2921 {
2922 dist = org_dist;
2923 if ( dist < 48 )
2924 dist = ( dist + 64 ) >> 1;
2925 }
2926 }
2927 else
2928 /* round otherwise to prevent color fringes in LCD mode */
2929 dist = ( dist + 32 ) & ~63;
2930 }
2931 }
2932 }
2933
2934 Done_Width:
2935 if ( sign )
2936 dist = -dist;
2937
2938 return dist;
2939 }
#define AF_EDGE_ROUND
Definition: afhints.h:230
@ AF_DIMENSION_VERT
Definition: afhints.h:37
#define AF_EDGE_SERIF
Definition: afhints.h:231
static FT_Pos af_latin_snap_width(AF_Width widths, FT_UInt count, FT_Pos width)
Definition: aflatin.c:2699
#define AF_LATIN_HINTS_DO_MONO(h)
Definition: aflatin.h:159
#define AF_LATIN_HINTS_DO_VERT_SNAP(h)
Definition: aflatin.h:153
struct AF_LatinMetricsRec_ * AF_LatinMetrics
#define AF_LATIN_HINTS_DO_HORZ_SNAP(h)
Definition: aflatin.h:150
#define AF_LATIN_HINTS_DO_STEM_ADJUST(h)
Definition: aflatin.h:156
unsigned int FT_UInt
Definition: fttypes.h:231
signed int FT_Int
Definition: fttypes.h:220
GLint GLint GLsizei width
Definition: gl.h:1546
GLsizei GLenum const GLvoid GLuint GLsizei GLfloat * metrics
Definition: glext.h:11745
#define sign(x)
Definition: mapdesc.cc:613

Referenced by af_latin_align_linked_edge(), and af_latin_hint_edges().

◆ af_latin_get_standard_widths()

af_latin_get_standard_widths ( AF_LatinMetrics  metrics,
FT_Pos stdHW,
FT_Pos stdVW 
)

Definition at line 1531 of file aflatin.c.

1534 {
1535 if ( stdHW )
1536 *stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
1537
1538 if ( stdVW )
1539 *stdVW = metrics->axis[AF_DIMENSION_HORZ].standard_width;
1540 }
@ AF_DIMENSION_HORZ
Definition: afhints.h:35

◆ af_latin_hint_edges()

static void af_latin_hint_edges ( AF_GlyphHints  hints,
AF_Dimension  dim 
)
static

Definition at line 3000 of file aflatin.c.

3002 {
3003 AF_AxisHints axis = &hints->axis[dim];
3004 AF_Edge edges = axis->edges;
3005 AF_Edge edge_limit = edges + axis->num_edges;
3006 FT_PtrDist n_edges;
3007 AF_Edge edge;
3008 AF_Edge anchor = NULL;
3009 FT_Int has_serifs = 0;
3010
3011 AF_StyleClass style_class = hints->metrics->style_class;
3012 AF_ScriptClass script_class = af_script_classes[style_class->script];
3013
3014 FT_Bool top_to_bottom_hinting = 0;
3015
3016#ifdef FT_DEBUG_LEVEL_TRACE
3017 FT_UInt num_actions = 0;
3018#endif
3019
3020
3021 FT_TRACE5(( "latin %s edge hinting (style `%s')\n",
3022 dim == AF_DIMENSION_VERT ? "horizontal" : "vertical",
3023 af_style_names[hints->metrics->style_class->style] ));
3024
3025 if ( dim == AF_DIMENSION_VERT )
3026 top_to_bottom_hinting = script_class->top_to_bottom_hinting;
3027
3028 /* we begin by aligning all stems relative to the blue zone */
3029 /* if needed -- that's only for horizontal edges */
3030
3031 if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) )
3032 {
3033 for ( edge = edges; edge < edge_limit; edge++ )
3034 {
3035 AF_Width blue;
3036 AF_Edge edge1, edge2; /* these edges form the stem to check */
3037
3038
3039 if ( edge->flags & AF_EDGE_DONE )
3040 continue;
3041
3042 edge1 = NULL;
3043 edge2 = edge->link;
3044
3045 /*
3046 * If a stem contains both a neutral and a non-neutral blue zone,
3047 * skip the neutral one. Otherwise, outlines with different
3048 * directions might be incorrectly aligned at the same vertical
3049 * position.
3050 *
3051 * If we have two neutral blue zones, skip one of them.
3052 *
3053 */
3054 if ( edge->blue_edge && edge2 && edge2->blue_edge )
3055 {
3056 FT_Byte neutral = edge->flags & AF_EDGE_NEUTRAL;
3057 FT_Byte neutral2 = edge2->flags & AF_EDGE_NEUTRAL;
3058
3059
3060 if ( neutral2 )
3061 {
3062 edge2->blue_edge = NULL;
3063 edge2->flags &= ~AF_EDGE_NEUTRAL;
3064 }
3065 else if ( neutral )
3066 {
3067 edge->blue_edge = NULL;
3068 edge->flags &= ~AF_EDGE_NEUTRAL;
3069 }
3070 }
3071
3072 blue = edge->blue_edge;
3073 if ( blue )
3074 edge1 = edge;
3075
3076 /* flip edges if the other edge is aligned to a blue zone */
3077 else if ( edge2 && edge2->blue_edge )
3078 {
3079 blue = edge2->blue_edge;
3080 edge1 = edge2;
3081 edge2 = edge;
3082 }
3083
3084 if ( !edge1 )
3085 continue;
3086
3087#ifdef FT_DEBUG_LEVEL_TRACE
3088 if ( !anchor )
3089 FT_TRACE5(( " BLUE_ANCHOR: edge %ld (opos=%.2f) snapped to %.2f,"
3090 " was %.2f (anchor=edge %ld)\n",
3091 edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0,
3092 edge1->pos / 64.0, edge - edges ));
3093 else
3094 FT_TRACE5(( " BLUE: edge %ld (opos=%.2f) snapped to %.2f,"
3095 " was %.2f\n",
3096 edge1 - edges, edge1->opos / 64.0, blue->fit / 64.0,
3097 edge1->pos / 64.0 ));
3098
3099 num_actions++;
3100#endif
3101
3102 edge1->pos = blue->fit;
3103 edge1->flags |= AF_EDGE_DONE;
3104
3105 if ( edge2 && !edge2->blue_edge )
3106 {
3107 af_latin_align_linked_edge( hints, dim, edge1, edge2 );
3108 edge2->flags |= AF_EDGE_DONE;
3109
3110#ifdef FT_DEBUG_LEVEL_TRACE
3111 num_actions++;
3112#endif
3113 }
3114
3115 if ( !anchor )
3116 anchor = edge;
3117 }
3118 }
3119
3120 /* now we align all other stem edges, trying to maintain the */
3121 /* relative order of stems in the glyph */
3122 for ( edge = edges; edge < edge_limit; edge++ )
3123 {
3124 AF_Edge edge2;
3125
3126
3127 if ( edge->flags & AF_EDGE_DONE )
3128 continue;
3129
3130 /* skip all non-stem edges */
3131 edge2 = edge->link;
3132 if ( !edge2 )
3133 {
3134 has_serifs++;
3135 continue;
3136 }
3137
3138 /* now align the stem */
3139
3140 /* this should not happen, but it's better to be safe */
3141 if ( edge2->blue_edge )
3142 {
3143 FT_TRACE5(( " ASSERTION FAILED for edge %ld\n", edge2 - edges ));
3144
3145 af_latin_align_linked_edge( hints, dim, edge2, edge );
3146 edge->flags |= AF_EDGE_DONE;
3147
3148#ifdef FT_DEBUG_LEVEL_TRACE
3149 num_actions++;
3150#endif
3151 continue;
3152 }
3153
3154 if ( !anchor )
3155 {
3156 /* if we reach this if clause, no stem has been aligned yet */
3157
3158 FT_Pos org_len, org_center, cur_len;
3159 FT_Pos cur_pos1, error1, error2, u_off, d_off;
3160
3161
3162 org_len = edge2->opos - edge->opos;
3163 cur_len = af_latin_compute_stem_width( hints, dim,
3164 org_len, 0,
3165 edge->flags,
3166 edge2->flags );
3167
3168 /* some voodoo to specially round edges for small stem widths; */
3169 /* the idea is to align the center of a stem, then shifting */
3170 /* the stem edges to suitable positions */
3171 if ( cur_len <= 64 )
3172 {
3173 /* width <= 1px */
3174 u_off = 32;
3175 d_off = 32;
3176 }
3177 else
3178 {
3179 /* 1px < width < 1.5px */
3180 u_off = 38;
3181 d_off = 26;
3182 }
3183
3184 if ( cur_len < 96 )
3185 {
3186 org_center = edge->opos + ( org_len >> 1 );
3187 cur_pos1 = FT_PIX_ROUND( org_center );
3188
3189 error1 = org_center - ( cur_pos1 - u_off );
3190 if ( error1 < 0 )
3191 error1 = -error1;
3192
3193 error2 = org_center - ( cur_pos1 + d_off );
3194 if ( error2 < 0 )
3195 error2 = -error2;
3196
3197 if ( error1 < error2 )
3198 cur_pos1 -= u_off;
3199 else
3200 cur_pos1 += d_off;
3201
3202 edge->pos = cur_pos1 - cur_len / 2;
3203 edge2->pos = edge->pos + cur_len;
3204 }
3205 else
3206 edge->pos = FT_PIX_ROUND( edge->opos );
3207
3208 anchor = edge;
3209 edge->flags |= AF_EDGE_DONE;
3210
3211 FT_TRACE5(( " ANCHOR: edge %ld (opos=%.2f) and %ld (opos=%.2f)"
3212 " snapped to %.2f and %.2f\n",
3213 edge - edges, edge->opos / 64.0,
3214 edge2 - edges, edge2->opos / 64.0,
3215 edge->pos / 64.0, edge2->pos / 64.0 ));
3216
3217 af_latin_align_linked_edge( hints, dim, edge, edge2 );
3218
3219#ifdef FT_DEBUG_LEVEL_TRACE
3220 num_actions += 2;
3221#endif
3222 }
3223 else
3224 {
3225 FT_Pos org_pos, org_len, org_center, cur_len;
3226 FT_Pos cur_pos1, cur_pos2, delta1, delta2;
3227
3228
3229 org_pos = anchor->pos + ( edge->opos - anchor->opos );
3230 org_len = edge2->opos - edge->opos;
3231 org_center = org_pos + ( org_len >> 1 );
3232
3233 cur_len = af_latin_compute_stem_width( hints, dim,
3234 org_len, 0,
3235 edge->flags,
3236 edge2->flags );
3237
3238 if ( edge2->flags & AF_EDGE_DONE )
3239 {
3240 FT_TRACE5(( " ADJUST: edge %ld (pos=%.2f) moved to %.2f\n",
3241 edge - edges, edge->pos / 64.0,
3242 ( edge2->pos - cur_len ) / 64.0 ));
3243
3244 edge->pos = edge2->pos - cur_len;
3245 }
3246
3247 else if ( cur_len < 96 )
3248 {
3249 FT_Pos u_off, d_off;
3250
3251
3252 cur_pos1 = FT_PIX_ROUND( org_center );
3253
3254 if ( cur_len <= 64 )
3255 {
3256 u_off = 32;
3257 d_off = 32;
3258 }
3259 else
3260 {
3261 u_off = 38;
3262 d_off = 26;
3263 }
3264
3265 delta1 = org_center - ( cur_pos1 - u_off );
3266 if ( delta1 < 0 )
3267 delta1 = -delta1;
3268
3269 delta2 = org_center - ( cur_pos1 + d_off );
3270 if ( delta2 < 0 )
3271 delta2 = -delta2;
3272
3273 if ( delta1 < delta2 )
3274 cur_pos1 -= u_off;
3275 else
3276 cur_pos1 += d_off;
3277
3278 edge->pos = cur_pos1 - cur_len / 2;
3279 edge2->pos = cur_pos1 + cur_len / 2;
3280
3281 FT_TRACE5(( " STEM: edge %ld (opos=%.2f) linked to %ld (opos=%.2f)"
3282 " snapped to %.2f and %.2f\n",
3283 edge - edges, edge->opos / 64.0,
3284 edge2 - edges, edge2->opos / 64.0,
3285 edge->pos / 64.0, edge2->pos / 64.0 ));
3286 }
3287
3288 else
3289 {
3290 org_pos = anchor->pos + ( edge->opos - anchor->opos );
3291 org_len = edge2->opos - edge->opos;
3292 org_center = org_pos + ( org_len >> 1 );
3293
3294 cur_len = af_latin_compute_stem_width( hints, dim,
3295 org_len, 0,
3296 edge->flags,
3297 edge2->flags );
3298
3299 cur_pos1 = FT_PIX_ROUND( org_pos );
3300 delta1 = cur_pos1 + ( cur_len >> 1 ) - org_center;
3301 if ( delta1 < 0 )
3302 delta1 = -delta1;
3303
3304 cur_pos2 = FT_PIX_ROUND( org_pos + org_len ) - cur_len;
3305 delta2 = cur_pos2 + ( cur_len >> 1 ) - org_center;
3306 if ( delta2 < 0 )
3307 delta2 = -delta2;
3308
3309 edge->pos = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2;
3310 edge2->pos = edge->pos + cur_len;
3311
3312 FT_TRACE5(( " STEM: edge %ld (opos=%.2f) linked to %ld (opos=%.2f)"
3313 " snapped to %.2f and %.2f\n",
3314 edge - edges, edge->opos / 64.0,
3315 edge2 - edges, edge2->opos / 64.0,
3316 edge->pos / 64.0, edge2->pos / 64.0 ));
3317 }
3318
3319#ifdef FT_DEBUG_LEVEL_TRACE
3320 num_actions++;
3321#endif
3322
3323 edge->flags |= AF_EDGE_DONE;
3324 edge2->flags |= AF_EDGE_DONE;
3325
3326 if ( edge > edges &&
3327 ( top_to_bottom_hinting ? ( edge->pos > edge[-1].pos )
3328 : ( edge->pos < edge[-1].pos ) ) )
3329 {
3330 /* don't move if stem would (almost) disappear otherwise; */
3331 /* the ad-hoc value 16 corresponds to 1/4px */
3332 if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
3333 {
3334#ifdef FT_DEBUG_LEVEL_TRACE
3335 FT_TRACE5(( " BOUND: edge %ld (pos=%.2f) moved to %.2f\n",
3336 edge - edges,
3337 edge->pos / 64.0,
3338 edge[-1].pos / 64.0 ));
3339
3340 num_actions++;
3341#endif
3342
3343 edge->pos = edge[-1].pos;
3344 }
3345 }
3346 }
3347 }
3348
3349 /* make sure that lowercase m's maintain their symmetry */
3350
3351 /* In general, lowercase m's have six vertical edges if they are sans */
3352 /* serif, or twelve if they are with serifs. This implementation is */
3353 /* based on that assumption, and seems to work very well with most */
3354 /* faces. However, if for a certain face this assumption is not */
3355 /* true, the m is just rendered like before. In addition, any stem */
3356 /* correction will only be applied to symmetrical glyphs (even if the */
3357 /* glyph is not an m), so the potential for unwanted distortion is */
3358 /* relatively low. */
3359
3360 /* We don't handle horizontal edges since we can't easily assure that */
3361 /* the third (lowest) stem aligns with the base line; it might end up */
3362 /* one pixel higher or lower. */
3363
3364 n_edges = edge_limit - edges;
3365 if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
3366 {
3367 AF_Edge edge1, edge2, edge3;
3368 FT_Pos dist1, dist2, span, delta;
3369
3370
3371 if ( n_edges == 6 )
3372 {
3373 edge1 = edges;
3374 edge2 = edges + 2;
3375 edge3 = edges + 4;
3376 }
3377 else
3378 {
3379 edge1 = edges + 1;
3380 edge2 = edges + 5;
3381 edge3 = edges + 9;
3382 }
3383
3384 dist1 = edge2->opos - edge1->opos;
3385 dist2 = edge3->opos - edge2->opos;
3386
3387 span = dist1 - dist2;
3388 if ( span < 0 )
3389 span = -span;
3390
3391 if ( span < 8 )
3392 {
3393 delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
3394 edge3->pos -= delta;
3395 if ( edge3->link )
3396 edge3->link->pos -= delta;
3397
3398 /* move the serifs along with the stem */
3399 if ( n_edges == 12 )
3400 {
3401 ( edges + 8 )->pos -= delta;
3402 ( edges + 11 )->pos -= delta;
3403 }
3404
3405 edge3->flags |= AF_EDGE_DONE;
3406 if ( edge3->link )
3407 edge3->link->flags |= AF_EDGE_DONE;
3408 }
3409 }
3410
3411 if ( has_serifs || !anchor )
3412 {
3413 /*
3414 * now hint the remaining edges (serifs and single) in order
3415 * to complete our processing
3416 */
3417 for ( edge = edges; edge < edge_limit; edge++ )
3418 {
3419 FT_Pos delta;
3420
3421
3422 if ( edge->flags & AF_EDGE_DONE )
3423 continue;
3424
3425 delta = 1000;
3426
3427 if ( edge->serif )
3428 {
3429 delta = edge->serif->opos - edge->opos;
3430 if ( delta < 0 )
3431 delta = -delta;
3432 }
3433
3434 if ( delta < 64 + 16 )
3435 {
3436 af_latin_align_serif_edge( hints, edge->serif, edge );
3437 FT_TRACE5(( " SERIF: edge %ld (opos=%.2f) serif to %ld (opos=%.2f)"
3438 " aligned to %.2f\n",
3439 edge - edges, edge->opos / 64.0,
3440 edge->serif - edges, edge->serif->opos / 64.0,
3441 edge->pos / 64.0 ));
3442 }
3443 else if ( !anchor )
3444 {
3445 edge->pos = FT_PIX_ROUND( edge->opos );
3446 anchor = edge;
3447 FT_TRACE5(( " SERIF_ANCHOR: edge %ld (opos=%.2f)"
3448 " snapped to %.2f\n",
3449 edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
3450 }
3451 else
3452 {
3454
3455
3456 for ( before = edge - 1; before >= edges; before-- )
3457 if ( before->flags & AF_EDGE_DONE )
3458 break;
3459
3460 for ( after = edge + 1; after < edge_limit; after++ )
3461 if ( after->flags & AF_EDGE_DONE )
3462 break;
3463
3464 if ( before >= edges && before < edge &&
3465 after < edge_limit && after > edge )
3466 {
3467 if ( after->opos == before->opos )
3468 edge->pos = before->pos;
3469 else
3470 edge->pos = before->pos +
3471 FT_MulDiv( edge->opos - before->opos,
3472 after->pos - before->pos,
3473 after->opos - before->opos );
3474
3475 FT_TRACE5(( " SERIF_LINK1: edge %ld (opos=%.2f) snapped to %.2f"
3476 " from %ld (opos=%.2f)\n",
3477 edge - edges, edge->opos / 64.0,
3478 edge->pos / 64.0,
3479 before - edges, before->opos / 64.0 ));
3480 }
3481 else
3482 {
3483 edge->pos = anchor->pos +
3484 ( ( edge->opos - anchor->opos + 16 ) & ~31 );
3485 FT_TRACE5(( " SERIF_LINK2: edge %ld (opos=%.2f)"
3486 " snapped to %.2f\n",
3487 edge - edges, edge->opos / 64.0, edge->pos / 64.0 ));
3488 }
3489 }
3490
3491#ifdef FT_DEBUG_LEVEL_TRACE
3492 num_actions++;
3493#endif
3494 edge->flags |= AF_EDGE_DONE;
3495
3496 if ( edge > edges &&
3497 ( top_to_bottom_hinting ? ( edge->pos > edge[-1].pos )
3498 : ( edge->pos < edge[-1].pos ) ) )
3499 {
3500 /* don't move if stem would (almost) disappear otherwise; */
3501 /* the ad-hoc value 16 corresponds to 1/4px */
3502 if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
3503 {
3504#ifdef FT_DEBUG_LEVEL_TRACE
3505 FT_TRACE5(( " BOUND: edge %ld (pos=%.2f) moved to %.2f\n",
3506 edge - edges,
3507 edge->pos / 64.0,
3508 edge[-1].pos / 64.0 ));
3509
3510 num_actions++;
3511#endif
3512 edge->pos = edge[-1].pos;
3513 }
3514 }
3515
3516 if ( edge + 1 < edge_limit &&
3517 edge[1].flags & AF_EDGE_DONE &&
3518 ( top_to_bottom_hinting ? ( edge->pos < edge[1].pos )
3519 : ( edge->pos > edge[1].pos ) ) )
3520 {
3521 /* don't move if stem would (almost) disappear otherwise; */
3522 /* the ad-hoc value 16 corresponds to 1/4px */
3523 if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
3524 {
3525#ifdef FT_DEBUG_LEVEL_TRACE
3526 FT_TRACE5(( " BOUND: edge %ld (pos=%.2f) moved to %.2f\n",
3527 edge - edges,
3528 edge->pos / 64.0,
3529 edge[1].pos / 64.0 ));
3530
3531 num_actions++;
3532#endif
3533
3534 edge->pos = edge[1].pos;
3535 }
3536 }
3537 }
3538 }
3539
3540#ifdef FT_DEBUG_LEVEL_TRACE
3541 if ( !num_actions )
3542 FT_TRACE5(( " (none)\n" ));
3543 FT_TRACE5(( "\n" ));
3544#endif
3545 }
af_script_classes[]
Definition: afglobal.c:88
#define AF_HINTS_DO_BLUES(h)
Definition: afhints.h:403
#define AF_EDGE_NEUTRAL
Definition: afhints.h:233
#define AF_EDGE_DONE
Definition: afhints.h:232
static void af_latin_align_serif_edge(AF_GlyphHints hints, AF_Edge base, AF_Edge serif)
Definition: aflatin.c:2976
static void af_latin_align_linked_edge(AF_GlyphHints hints, AF_Dimension dim, AF_Edge base_edge, AF_Edge stem_edge)
Definition: aflatin.c:2945
FT_BEGIN_HEADER struct AF_WidthRec_ * AF_Width
#define NULL
Definition: types.h:112
FT_MulDiv(FT_Long a, FT_Long b, FT_Long c)
Definition: ftcalc.c:415
#define FT_ABS(a)
Definition: ftobjs.h:73
#define FT_PIX_ROUND(x)
Definition: ftobjs.h:92
FT_BEGIN_HEADER typedef unsigned char FT_Bool
Definition: fttypes.h:108
ft_ptrdiff_t FT_PtrDist
Definition: fttypes.h:336
unsigned char FT_Byte
Definition: fttypes.h:154
GLclampf GLclampf blue
Definition: gl.h:1740
GLenum GLenum GLvoid GLvoid GLvoid * span
Definition: glext.h:5664
GLbitfield flags
Definition: glext.h:7161
#define error2(s, a, b)
Definition: debug.h:126
#define error1(s, a)
Definition: debug.h:125
FT_Int num_edges
Definition: afhints.h:320
AF_Edge edges
Definition: afhints.h:322
AF_Edge serif
Definition: afhints.h:300
AF_Width blue_edge
Definition: afhints.h:298
AF_Edge link
Definition: afhints.h:299
FT_Bool top_to_bottom_hinting
Definition: aftypes.h:347
AF_Script script
Definition: aftypes.h:451
__inline int before(__u32 seq1, __u32 seq2)
Definition: tcpcore.h:2390
__inline int after(__u32 seq1, __u32 seq2)
Definition: tcpcore.h:2395

Referenced by af_latin_hints_apply().

◆ af_latin_hints_apply()

static FT_Error af_latin_hints_apply ( FT_UInt  glyph_index,
AF_GlyphHints  hints,
FT_Outline outline,
AF_LatinMetrics  metrics 
)
static

Definition at line 3551 of file aflatin.c.

3555 {
3557 int dim;
3558
3559 AF_LatinAxis axis;
3560
3561
3563 if ( error )
3564 goto Exit;
3565
3566 /* analyze glyph outline */
3568 {
3569 axis = &metrics->axis[AF_DIMENSION_HORZ];
3571 axis->width_count,
3572 axis->widths,
3574 if ( error )
3575 goto Exit;
3576 }
3577
3578 if ( AF_HINTS_DO_VERTICAL( hints ) )
3579 {
3580 axis = &metrics->axis[AF_DIMENSION_VERT];
3582 axis->width_count,
3583 axis->widths,
3585 if ( error )
3586 goto Exit;
3587
3588 /* apply blue zones to base characters only */
3589 if ( !( metrics->root.globals->glyph_styles[glyph_index] & AF_NONBASE ) )
3591 }
3592
3593 /* grid-fit the outline */
3594 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
3595 {
3596#ifdef AF_CONFIG_OPTION_USE_WARPER
3597 if ( dim == AF_DIMENSION_HORZ &&
3598 metrics->root.scaler.render_mode == FT_RENDER_MODE_NORMAL &&
3600 {
3601 AF_WarperRec warper;
3603 FT_Pos delta;
3604
3605
3606 af_warper_compute( &warper, hints, (AF_Dimension)dim,
3607 &scale, &delta );
3608 af_glyph_hints_scale_dim( hints, (AF_Dimension)dim,
3609 scale, delta );
3610 continue;
3611 }
3612#endif /* AF_CONFIG_OPTION_USE_WARPER */
3613
3614 if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) ||
3616 {
3621 }
3622 }
3623
3625
3626 Exit:
3627 return error;
3628 }
#define AF_NONBASE
Definition: afglobal.h:84
af_glyph_hints_align_edge_points(AF_GlyphHints hints, AF_Dimension dim)
Definition: afhints.c:1219
af_glyph_hints_save(AF_GlyphHints hints, FT_Outline *outline)
Definition: afhints.c:1184
af_glyph_hints_reload(AF_GlyphHints hints, FT_Outline *outline)
Definition: afhints.c:762
af_glyph_hints_align_strong_points(AF_GlyphHints hints, AF_Dimension dim)
Definition: afhints.c:1294
af_glyph_hints_align_weak_points(AF_GlyphHints hints, AF_Dimension dim)
Definition: afhints.c:1568
#define AF_HINTS_DO_WARP(h)
Definition: afhints.h:411
#define AF_HINTS_DO_HORIZONTAL(h)
Definition: afhints.h:397
FT_BEGIN_HEADER enum AF_Dimension_ AF_Dimension
@ AF_DIMENSION_MAX
Definition: afhints.h:40
#define AF_HINTS_DO_VERTICAL(h)
Definition: afhints.h:400
static void af_latin_hints_compute_blue_edges(AF_GlyphHints hints, AF_LatinMetrics metrics)
Definition: aflatin.c:2496
static void af_latin_hint_edges(AF_GlyphHints hints, AF_Dimension dim)
Definition: aflatin.c:3000
af_latin_hints_detect_features(AF_GlyphHints hints, FT_UInt width_count, AF_WidthRec *widths, AF_Dimension dim)
Definition: aflatin.c:2473
@ FT_RENDER_MODE_NORMAL
Definition: freetype.h:3249
signed long FT_Fixed
Definition: fttypes.h:287
int FT_Error
Definition: fttypes.h:299
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:9032
#define error(str)
Definition: mkdosfs.c:1605
static void Exit(void)
Definition: sock.c:1330
AF_WidthRec widths[AF_LATIN_MAX_WIDTHS]
Definition: aflatin.h:94
FT_UInt width_count
Definition: aflatin.h:93
Definition: mesh.c:5330

◆ af_latin_hints_compute_blue_edges()

static void af_latin_hints_compute_blue_edges ( AF_GlyphHints  hints,
AF_LatinMetrics  metrics 
)
static

Definition at line 2496 of file aflatin.c.

2498 {
2499 AF_AxisHints axis = &hints->axis[AF_DIMENSION_VERT];
2500 AF_Edge edge = axis->edges;
2501 AF_Edge edge_limit = edge + axis->num_edges;
2502 AF_LatinAxis latin = &metrics->axis[AF_DIMENSION_VERT];
2503 FT_Fixed scale = latin->scale;
2504
2505
2506 /* compute which blue zones are active, i.e. have their scaled */
2507 /* size < 3/4 pixels */
2508
2509 /* for each horizontal edge search the blue zone which is closest */
2510 for ( ; edge < edge_limit; edge++ )
2511 {
2512 FT_UInt bb;
2513 AF_Width best_blue = NULL;
2514 FT_Bool best_blue_is_neutral = 0;
2515 FT_Pos best_dist; /* initial threshold */
2516
2517
2518 /* compute the initial threshold as a fraction of the EM size */
2519 /* (the value 40 is heuristic) */
2520 best_dist = FT_MulFix( metrics->units_per_em / 40, scale );
2521
2522 /* assure a minimum distance of 0.5px */
2523 if ( best_dist > 64 / 2 )
2524 best_dist = 64 / 2;
2525
2526 for ( bb = 0; bb < latin->blue_count; bb++ )
2527 {
2528 AF_LatinBlue blue = latin->blues + bb;
2529 FT_Bool is_top_blue, is_neutral_blue, is_major_dir;
2530
2531
2532 /* skip inactive blue zones (i.e., those that are too large) */
2533 if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
2534 continue;
2535
2536 /* if it is a top zone, check for right edges (against the major */
2537 /* direction); if it is a bottom zone, check for left edges (in */
2538 /* the major direction) -- this assumes the TrueType convention */
2539 /* for the orientation of contours */
2540 is_top_blue =
2541 (FT_Byte)( ( blue->flags & ( AF_LATIN_BLUE_TOP |
2542 AF_LATIN_BLUE_SUB_TOP ) ) != 0 );
2543 is_neutral_blue =
2544 (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_NEUTRAL ) != 0);
2545 is_major_dir =
2546 FT_BOOL( edge->dir == axis->major_dir );
2547
2548 /* neutral blue zones are handled for both directions */
2549 if ( is_top_blue ^ is_major_dir || is_neutral_blue )
2550 {
2551 FT_Pos dist;
2552
2553
2554 /* first of all, compare it to the reference position */
2555 dist = edge->fpos - blue->ref.org;
2556 if ( dist < 0 )
2557 dist = -dist;
2558
2559 dist = FT_MulFix( dist, scale );
2560 if ( dist < best_dist )
2561 {
2562 best_dist = dist;
2563 best_blue = &blue->ref;
2564 best_blue_is_neutral = is_neutral_blue;
2565 }
2566
2567 /* now compare it to the overshoot position and check whether */
2568 /* the edge is rounded, and whether the edge is over the */
2569 /* reference position of a top zone, or under the reference */
2570 /* position of a bottom zone (provided we don't have a */
2571 /* neutral blue zone) */
2572 if ( edge->flags & AF_EDGE_ROUND &&
2573 dist != 0 &&
2574 !is_neutral_blue )
2575 {
2576 FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org );
2577
2578
2579 if ( is_top_blue ^ is_under_ref )
2580 {
2581 dist = edge->fpos - blue->shoot.org;
2582 if ( dist < 0 )
2583 dist = -dist;
2584
2585 dist = FT_MulFix( dist, scale );
2586 if ( dist < best_dist )
2587 {
2588 best_dist = dist;
2589 best_blue = &blue->shoot;
2590 best_blue_is_neutral = is_neutral_blue;
2591 }
2592 }
2593 }
2594 }
2595 }
2596
2597 if ( best_blue )
2598 {
2599 edge->blue_edge = best_blue;
2600 if ( best_blue_is_neutral )
2601 edge->flags |= AF_EDGE_NEUTRAL;
2602 }
2603 }
2604 }
#define AF_LATIN_BLUE_SUB_TOP
Definition: aflatin.h:70
#define AF_LATIN_BLUE_TOP
Definition: aflatin.h:69
#define AF_LATIN_BLUE_ACTIVE
Definition: aflatin.h:68
#define AF_LATIN_BLUE_NEUTRAL
Definition: aflatin.h:72
FT_MulFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:508
#define FT_BOOL(x)
Definition: fttypes.h:591
AF_Direction major_dir
Definition: afhints.h:324
FT_Char dir
Definition: afhints.h:295
FT_Short fpos
Definition: afhints.h:290
AF_LatinBlueRec blues[AF_BLUE_STRINGSET_MAX]
Definition: aflatin.h:101
FT_Fixed scale
Definition: aflatin.h:90
FT_UInt blue_count
Definition: aflatin.h:100

Referenced by af_latin_hints_apply().

◆ af_latin_hints_compute_edges()

af_latin_hints_compute_edges ( AF_GlyphHints  hints,
AF_Dimension  dim 
)

Definition at line 2121 of file aflatin.c.

2123 {
2124 AF_AxisHints axis = &hints->axis[dim];
2126 FT_Memory memory = hints->memory;
2127 AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim];
2128
2129 AF_StyleClass style_class = hints->metrics->style_class;
2130 AF_ScriptClass script_class = af_script_classes[style_class->script];
2131
2132 FT_Bool top_to_bottom_hinting = 0;
2133
2134 AF_Segment segments = axis->segments;
2135 AF_Segment segment_limit = segments + axis->num_segments;
2136 AF_Segment seg;
2137
2138#if 0
2139 AF_Direction up_dir;
2140#endif
2142 FT_Pos edge_distance_threshold;
2143 FT_Pos segment_length_threshold;
2144 FT_Pos segment_width_threshold;
2145
2146
2147 axis->num_edges = 0;
2148
2149 scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
2150 : hints->y_scale;
2151
2152#if 0
2153 up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP
2154 : AF_DIR_RIGHT;
2155#endif
2156
2157 if ( dim == AF_DIMENSION_VERT )
2158 top_to_bottom_hinting = script_class->top_to_bottom_hinting;
2159
2160 /*
2161 * We ignore all segments that are less than 1 pixel in length
2162 * to avoid many problems with serif fonts. We compute the
2163 * corresponding threshold in font units.
2164 */
2165 if ( dim == AF_DIMENSION_HORZ )
2166 segment_length_threshold = FT_DivFix( 64, hints->y_scale );
2167 else
2168 segment_length_threshold = 0;
2169
2170 /*
2171 * Similarly, we ignore segments that have a width delta
2172 * larger than 0.5px (i.e., a width larger than 1px).
2173 */
2174 segment_width_threshold = FT_DivFix( 32, scale );
2175
2176 /**********************************************************************
2177 *
2178 * We begin by generating a sorted table of edges for the current
2179 * direction. To do so, we simply scan each segment and try to find
2180 * an edge in our table that corresponds to its position.
2181 *
2182 * If no edge is found, we create and insert a new edge in the
2183 * sorted table. Otherwise, we simply add the segment to the edge's
2184 * list which gets processed in the second step to compute the
2185 * edge's properties.
2186 *
2187 * Note that the table of edges is sorted along the segment/edge
2188 * position.
2189 *
2190 */
2191
2192 /* assure that edge distance threshold is at most 0.25px */
2193 edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
2194 scale );
2195 if ( edge_distance_threshold > 64 / 4 )
2196 edge_distance_threshold = 64 / 4;
2197
2198 edge_distance_threshold = FT_DivFix( edge_distance_threshold,
2199 scale );
2200
2201 for ( seg = segments; seg < segment_limit; seg++ )
2202 {
2203 AF_Edge found = NULL;
2204 FT_Int ee;
2205
2206
2207 /* ignore too short segments, too wide ones, and, in this loop, */
2208 /* one-point segments without a direction */
2209 if ( seg->height < segment_length_threshold ||
2210 seg->delta > segment_width_threshold ||
2211 seg->dir == AF_DIR_NONE )
2212 continue;
2213
2214 /* A special case for serif edges: If they are smaller than */
2215 /* 1.5 pixels we ignore them. */
2216 if ( seg->serif &&
2217 2 * seg->height < 3 * segment_length_threshold )
2218 continue;
2219
2220 /* look for an edge corresponding to the segment */
2221 for ( ee = 0; ee < axis->num_edges; ee++ )
2222 {
2223 AF_Edge edge = axis->edges + ee;
2224 FT_Pos dist;
2225
2226
2227 dist = seg->pos - edge->fpos;
2228 if ( dist < 0 )
2229 dist = -dist;
2230
2231 if ( dist < edge_distance_threshold && edge->dir == seg->dir )
2232 {
2233 found = edge;
2234 break;
2235 }
2236 }
2237
2238 if ( !found )
2239 {
2240 AF_Edge edge;
2241
2242
2243 /* insert a new edge in the list and */
2244 /* sort according to the position */
2245 error = af_axis_hints_new_edge( axis, seg->pos,
2246 (AF_Direction)seg->dir,
2247 top_to_bottom_hinting,
2248 memory, &edge );
2249 if ( error )
2250 goto Exit;
2251
2252 /* add the segment to the new edge's list */
2253 FT_ZERO( edge );
2254
2255 edge->first = seg;
2256 edge->last = seg;
2257 edge->dir = seg->dir;
2258 edge->fpos = seg->pos;
2259 edge->opos = FT_MulFix( seg->pos, scale );
2260 edge->pos = edge->opos;
2261 seg->edge_next = seg;
2262 }
2263 else
2264 {
2265 /* if an edge was found, simply add the segment to the edge's */
2266 /* list */
2267 seg->edge_next = found->first;
2268 found->last->edge_next = seg;
2269 found->last = seg;
2270 }
2271 }
2272
2273 /* we loop again over all segments to catch one-point segments */
2274 /* without a direction: if possible, link them to existing edges */
2275 for ( seg = segments; seg < segment_limit; seg++ )
2276 {
2277 AF_Edge found = NULL;
2278 FT_Int ee;
2279
2280
2281 if ( seg->dir != AF_DIR_NONE )
2282 continue;
2283
2284 /* look for an edge corresponding to the segment */
2285 for ( ee = 0; ee < axis->num_edges; ee++ )
2286 {
2287 AF_Edge edge = axis->edges + ee;
2288 FT_Pos dist;
2289
2290
2291 dist = seg->pos - edge->fpos;
2292 if ( dist < 0 )
2293 dist = -dist;
2294
2295 if ( dist < edge_distance_threshold )
2296 {
2297 found = edge;
2298 break;
2299 }
2300 }
2301
2302 /* one-point segments without a match are ignored */
2303 if ( found )
2304 {
2305 seg->edge_next = found->first;
2306 found->last->edge_next = seg;
2307 found->last = seg;
2308 }
2309 }
2310
2311
2312 /*******************************************************************
2313 *
2314 * Good, we now compute each edge's properties according to the
2315 * segments found on its position. Basically, these are
2316 *
2317 * - the edge's main direction
2318 * - stem edge, serif edge or both (which defaults to stem then)
2319 * - rounded edge, straight or both (which defaults to straight)
2320 * - link for edge
2321 *
2322 */
2323
2324 /* first of all, set the `edge' field in each segment -- this is */
2325 /* required in order to compute edge links */
2326
2327 /*
2328 * Note that removing this loop and setting the `edge' field of each
2329 * segment directly in the code above slows down execution speed for
2330 * some reasons on platforms like the Sun.
2331 */
2332 {
2333 AF_Edge edges = axis->edges;
2334 AF_Edge edge_limit = FT_OFFSET( edges, axis->num_edges );
2335 AF_Edge edge;
2336
2337
2338 for ( edge = edges; edge < edge_limit; edge++ )
2339 {
2340 seg = edge->first;
2341 if ( seg )
2342 do
2343 {
2344 seg->edge = edge;
2345 seg = seg->edge_next;
2346
2347 } while ( seg != edge->first );
2348 }
2349
2350 /* now compute each edge properties */
2351 for ( edge = edges; edge < edge_limit; edge++ )
2352 {
2353 FT_Int is_round = 0; /* does it contain round segments? */
2354 FT_Int is_straight = 0; /* does it contain straight segments? */
2355#if 0
2356 FT_Pos ups = 0; /* number of upwards segments */
2357 FT_Pos downs = 0; /* number of downwards segments */
2358#endif
2359
2360
2361 seg = edge->first;
2362
2363 do
2364 {
2365 FT_Bool is_serif;
2366
2367
2368 /* check for roundness of segment */
2369 if ( seg->flags & AF_EDGE_ROUND )
2370 is_round++;
2371 else
2372 is_straight++;
2373
2374#if 0
2375 /* check for segment direction */
2376 if ( seg->dir == up_dir )
2377 ups += seg->max_coord - seg->min_coord;
2378 else
2379 downs += seg->max_coord - seg->min_coord;
2380#endif
2381
2382 /* check for links -- if seg->serif is set, then seg->link must */
2383 /* be ignored */
2384 is_serif = FT_BOOL( seg->serif &&
2385 seg->serif->edge &&
2386 seg->serif->edge != edge );
2387
2388 if ( ( seg->link && seg->link->edge ) || is_serif )
2389 {
2390 AF_Edge edge2;
2391 AF_Segment seg2;
2392
2393
2394 edge2 = edge->link;
2395 seg2 = seg->link;
2396
2397 if ( is_serif )
2398 {
2399 seg2 = seg->serif;
2400 edge2 = edge->serif;
2401 }
2402
2403 if ( edge2 )
2404 {
2405 FT_Pos edge_delta;
2406 FT_Pos seg_delta;
2407
2408
2409 edge_delta = edge->fpos - edge2->fpos;
2410 if ( edge_delta < 0 )
2411 edge_delta = -edge_delta;
2412
2413 seg_delta = seg->pos - seg2->pos;
2414 if ( seg_delta < 0 )
2415 seg_delta = -seg_delta;
2416
2417 if ( seg_delta < edge_delta )
2418 edge2 = seg2->edge;
2419 }
2420 else
2421 edge2 = seg2->edge;
2422
2423 if ( is_serif )
2424 {
2425 edge->serif = edge2;
2426 edge2->flags |= AF_EDGE_SERIF;
2427 }
2428 else
2429 edge->link = edge2;
2430 }
2431
2432 seg = seg->edge_next;
2433
2434 } while ( seg != edge->first );
2435
2436 /* set the round/straight flags */
2437 edge->flags = AF_EDGE_NORMAL;
2438
2439 if ( is_round > 0 && is_round >= is_straight )
2440 edge->flags |= AF_EDGE_ROUND;
2441
2442#if 0
2443 /* set the edge's main direction */
2444 edge->dir = AF_DIR_NONE;
2445
2446 if ( ups > downs )
2447 edge->dir = (FT_Char)up_dir;
2448
2449 else if ( ups < downs )
2450 edge->dir = (FT_Char)-up_dir;
2451
2452 else if ( ups == downs )
2453 edge->dir = 0; /* both up and down! */
2454#endif
2455
2456 /* get rid of serifs if link is set */
2457 /* XXX: This gets rid of many unpleasant artefacts! */
2458 /* Example: the `c' in cour.pfa at size 13 */
2459
2460 if ( edge->serif && edge->link )
2461 edge->serif = NULL;
2462 }
2463 }
2464
2465 Exit:
2466 return error;
2467 }
af_axis_hints_new_edge(AF_AxisHints axis, FT_Int fpos, AF_Direction dir, FT_Bool top_to_bottom_hinting, FT_Memory memory, AF_Edge *anedge)
Definition: afhints.c:99
enum AF_Direction_ AF_Direction
#define AF_EDGE_NORMAL
Definition: afhints.h:229
@ AF_DIR_RIGHT
Definition: afhints.h:50
@ AF_DIR_UP
Definition: afhints.h:52
@ AF_DIR_NONE
Definition: afhints.h:49
unsigned int dir
Definition: maze.c:112
FT_DivFix(FT_Long a, FT_Long b)
Definition: ftcalc.c:607
return FT_Err_Ok
Definition: ftbbox.c:526
#define FT_OFFSET(base, count)
Definition: ftmemory.h:66
#define FT_ZERO(p)
Definition: ftmemory.h:246
typedefFT_BEGIN_HEADER struct FT_MemoryRec_ * FT_Memory
Definition: ftsystem.h:64
signed char FT_Char
Definition: fttypes.h:143
static char memory[1024 *256]
Definition: process.c:122
AF_Segment segments
Definition: afhints.h:315
FT_Int num_segments
Definition: afhints.h:313
AF_Segment first
Definition: afhints.h:303
AF_Segment last
Definition: afhints.h:304
FT_Pos edge_distance_threshold
Definition: aflatin.h:95
FT_Byte flags
Definition: afhints.h:266
FT_Char dir
Definition: afhints.h:267
FT_Short min_coord
Definition: afhints.h:270
FT_Short max_coord
Definition: afhints.h:271
FT_Short height
Definition: afhints.h:272
AF_Segment edge_next
Definition: afhints.h:275
FT_Short delta
Definition: afhints.h:269
AF_Segment link
Definition: afhints.h:277
FT_Short pos
Definition: afhints.h:268
AF_Edge edge
Definition: afhints.h:274
AF_Segment serif
Definition: afhints.h:278

Referenced by af_latin_hints_detect_features().

◆ af_latin_hints_compute_segments()

af_latin_hints_compute_segments ( AF_GlyphHints  hints,
AF_Dimension  dim 
)

Definition at line 1555 of file aflatin.c.

1557 {
1559 AF_AxisHints axis = &hints->axis[dim];
1560 FT_Memory memory = hints->memory;
1562 AF_Segment segment = NULL;
1563 AF_SegmentRec seg0;
1564 AF_Point* contour = hints->contours;
1565 AF_Point* contour_limit = contour + hints->num_contours;
1566 AF_Direction major_dir, segment_dir;
1567
1568 FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em );
1569
1570
1571 FT_ZERO( &seg0 );
1572 seg0.score = 32000;
1573 seg0.flags = AF_EDGE_NORMAL;
1574
1575 major_dir = (AF_Direction)FT_ABS( axis->major_dir );
1576 segment_dir = major_dir;
1577
1578 axis->num_segments = 0;
1579
1580 /* set up (u,v) in each point */
1581 if ( dim == AF_DIMENSION_HORZ )
1582 {
1583 AF_Point point = hints->points;
1584 AF_Point limit = point + hints->num_points;
1585
1586
1587 for ( ; point < limit; point++ )
1588 {
1589 point->u = point->fx;
1590 point->v = point->fy;
1591 }
1592 }
1593 else
1594 {
1595 AF_Point point = hints->points;
1596 AF_Point limit = point + hints->num_points;
1597
1598
1599 for ( ; point < limit; point++ )
1600 {
1601 point->u = point->fy;
1602 point->v = point->fx;
1603 }
1604 }
1605
1606 /* do each contour separately */
1607 for ( ; contour < contour_limit; contour++ )
1608 {
1609 AF_Point point = contour[0];
1610 AF_Point last = point->prev;
1611 int on_edge = 0;
1612
1613 /* we call values measured along a segment (point->v) */
1614 /* `coordinates', and values orthogonal to it (point->u) */
1615 /* `positions' */
1616 FT_Pos min_pos = 32000;
1617 FT_Pos max_pos = -32000;
1618 FT_Pos min_coord = 32000;
1619 FT_Pos max_coord = -32000;
1620 FT_UShort min_flags = AF_FLAG_NONE;
1621 FT_UShort max_flags = AF_FLAG_NONE;
1622 FT_Pos min_on_coord = 32000;
1623 FT_Pos max_on_coord = -32000;
1624
1625 FT_Bool passed;
1626
1627 AF_Segment prev_segment = NULL;
1628
1629 FT_Pos prev_min_pos = min_pos;
1630 FT_Pos prev_max_pos = max_pos;
1631 FT_Pos prev_min_coord = min_coord;
1632 FT_Pos prev_max_coord = max_coord;
1633 FT_UShort prev_min_flags = min_flags;
1634 FT_UShort prev_max_flags = max_flags;
1635 FT_Pos prev_min_on_coord = min_on_coord;
1636 FT_Pos prev_max_on_coord = max_on_coord;
1637
1638
1639 if ( FT_ABS( last->out_dir ) == major_dir &&
1640 FT_ABS( point->out_dir ) == major_dir )
1641 {
1642 /* we are already on an edge, try to locate its start */
1643 last = point;
1644
1645 for (;;)
1646 {
1647 point = point->prev;
1648 if ( FT_ABS( point->out_dir ) != major_dir )
1649 {
1650 point = point->next;
1651 break;
1652 }
1653 if ( point == last )
1654 break;
1655 }
1656 }
1657
1658 last = point;
1659 passed = 0;
1660
1661 for (;;)
1662 {
1663 FT_Pos u, v;
1664
1665
1666 if ( on_edge )
1667 {
1668 /* get minimum and maximum position */
1669 u = point->u;
1670 if ( u < min_pos )
1671 min_pos = u;
1672 if ( u > max_pos )
1673 max_pos = u;
1674
1675 /* get minimum and maximum coordinate together with flags */
1676 v = point->v;
1677 if ( v < min_coord )
1678 {
1679 min_coord = v;
1680 min_flags = point->flags;
1681 }
1682 if ( v > max_coord )
1683 {
1684 max_coord = v;
1685 max_flags = point->flags;
1686 }
1687
1688 /* get minimum and maximum coordinate of `on' points */
1689 if ( !( point->flags & AF_FLAG_CONTROL ) )
1690 {
1691 v = point->v;
1692 if ( v < min_on_coord )
1693 min_on_coord = v;
1694 if ( v > max_on_coord )
1695 max_on_coord = v;
1696 }
1697
1698 if ( point->out_dir != segment_dir || point == last )
1699 {
1700 /* check whether the new segment's start point is identical to */
1701 /* the previous segment's end point; for example, this might */
1702 /* happen for spikes */
1703
1704 if ( !prev_segment || segment->first != prev_segment->last )
1705 {
1706 /* points are different: we are just leaving an edge, thus */
1707 /* record a new segment */
1708
1709 segment->last = point;
1710 segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 );
1711 segment->delta = (FT_Short)( ( max_pos - min_pos ) >> 1 );
1712
1713 /* a segment is round if either its first or last point */
1714 /* is a control point, and the length of the on points */
1715 /* inbetween doesn't exceed a heuristic limit */
1716 if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL &&
1717 ( max_on_coord - min_on_coord ) < flat_threshold )
1718 segment->flags |= AF_EDGE_ROUND;
1719
1720 segment->min_coord = (FT_Short)min_coord;
1721 segment->max_coord = (FT_Short)max_coord;
1722 segment->height = segment->max_coord - segment->min_coord;
1723
1724 prev_segment = segment;
1725 prev_min_pos = min_pos;
1726 prev_max_pos = max_pos;
1727 prev_min_coord = min_coord;
1728 prev_max_coord = max_coord;
1729 prev_min_flags = min_flags;
1730 prev_max_flags = max_flags;
1731 prev_min_on_coord = min_on_coord;
1732 prev_max_on_coord = max_on_coord;
1733 }
1734 else
1735 {
1736 /* points are the same: we don't create a new segment but */
1737 /* merge the current segment with the previous one */
1738
1739 if ( prev_segment->last->in_dir == point->in_dir )
1740 {
1741 /* we have identical directions (this can happen for */
1742 /* degenerate outlines that move zig-zag along the main */
1743 /* axis without changing the coordinate value of the other */
1744 /* axis, and where the segments have just been merged): */
1745 /* unify segments */
1746
1747 /* update constraints */
1748
1749 if ( prev_min_pos < min_pos )
1750 min_pos = prev_min_pos;
1751 if ( prev_max_pos > max_pos )
1752 max_pos = prev_max_pos;
1753
1754 if ( prev_min_coord < min_coord )
1755 {
1756 min_coord = prev_min_coord;
1757 min_flags = prev_min_flags;
1758 }
1759 if ( prev_max_coord > max_coord )
1760 {
1761 max_coord = prev_max_coord;
1762 max_flags = prev_max_flags;
1763 }
1764
1765 if ( prev_min_on_coord < min_on_coord )
1766 min_on_coord = prev_min_on_coord;
1767 if ( prev_max_on_coord > max_on_coord )
1768 max_on_coord = prev_max_on_coord;
1769
1770 prev_segment->last = point;
1771 prev_segment->pos = (FT_Short)( ( min_pos +
1772 max_pos ) >> 1 );
1773 prev_segment->delta = (FT_Short)( ( max_pos -
1774 min_pos ) >> 1 );
1775
1776 if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL &&
1777 ( max_on_coord - min_on_coord ) < flat_threshold )
1778 prev_segment->flags |= AF_EDGE_ROUND;
1779 else
1780 prev_segment->flags &= ~AF_EDGE_ROUND;
1781
1782 prev_segment->min_coord = (FT_Short)min_coord;
1783 prev_segment->max_coord = (FT_Short)max_coord;
1784 prev_segment->height = prev_segment->max_coord -
1785 prev_segment->min_coord;
1786 }
1787 else
1788 {
1789 /* we have different directions; use the properties of the */
1790 /* longer segment and discard the other one */
1791
1792 if ( FT_ABS( prev_max_coord - prev_min_coord ) >
1793 FT_ABS( max_coord - min_coord ) )
1794 {
1795 /* discard current segment */
1796
1797 if ( min_pos < prev_min_pos )
1798 prev_min_pos = min_pos;
1799 if ( max_pos > prev_max_pos )
1800 prev_max_pos = max_pos;
1801
1802 prev_segment->last = point;
1803 prev_segment->pos = (FT_Short)( ( prev_min_pos +
1804 prev_max_pos ) >> 1 );
1805 prev_segment->delta = (FT_Short)( ( prev_max_pos -
1806 prev_min_pos ) >> 1 );
1807 }
1808 else
1809 {
1810 /* discard previous segment */
1811
1812 if ( prev_min_pos < min_pos )
1813 min_pos = prev_min_pos;
1814 if ( prev_max_pos > max_pos )
1815 max_pos = prev_max_pos;
1816
1817 segment->last = point;
1818 segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 );
1819 segment->delta = (FT_Short)( ( max_pos - min_pos ) >> 1 );
1820
1821 if ( ( min_flags | max_flags ) & AF_FLAG_CONTROL &&
1822 ( max_on_coord - min_on_coord ) < flat_threshold )
1823 segment->flags |= AF_EDGE_ROUND;
1824
1825 segment->min_coord = (FT_Short)min_coord;
1826 segment->max_coord = (FT_Short)max_coord;
1827 segment->height = segment->max_coord -
1828 segment->min_coord;
1829
1830 *prev_segment = *segment;
1831
1832 prev_min_pos = min_pos;
1833 prev_max_pos = max_pos;
1834 prev_min_coord = min_coord;
1835 prev_max_coord = max_coord;
1836 prev_min_flags = min_flags;
1837 prev_max_flags = max_flags;
1838 prev_min_on_coord = min_on_coord;
1839 prev_max_on_coord = max_on_coord;
1840 }
1841 }
1842
1843 axis->num_segments--;
1844 }
1845
1846 on_edge = 0;
1847 segment = NULL;
1848
1849 /* fall through */
1850 }
1851 }
1852
1853 /* now exit if we are at the start/end point */
1854 if ( point == last )
1855 {
1856 if ( passed )
1857 break;
1858 passed = 1;
1859 }
1860
1861 /* if we are not on an edge, check whether the major direction */
1862 /* coincides with the current point's `out' direction, or */
1863 /* whether we have a single-point contour */
1864 if ( !on_edge &&
1865 ( FT_ABS( point->out_dir ) == major_dir ||
1866 point == point->prev ) )
1867 {
1868 /* this is the start of a new segment! */
1869 segment_dir = (AF_Direction)point->out_dir;
1870
1871 error = af_axis_hints_new_segment( axis, memory, &segment );
1872 if ( error )
1873 goto Exit;
1874
1875 /* clear all segment fields */
1876 segment[0] = seg0;
1877
1878 segment->dir = (FT_Char)segment_dir;
1879 segment->first = point;
1880 segment->last = point;
1881
1882 /* `af_axis_hints_new_segment' reallocates memory, */
1883 /* thus we have to refresh the `prev_segment' pointer */
1884 if ( prev_segment )
1885 prev_segment = segment - 1;
1886
1887 min_pos = max_pos = point->u;
1888 min_coord = max_coord = point->v;
1889 min_flags = max_flags = point->flags;
1890
1891 if ( point->flags & AF_FLAG_CONTROL )
1892 {
1893 min_on_coord = 32000;
1894 max_on_coord = -32000;
1895 }
1896 else
1897 min_on_coord = max_on_coord = point->v;
1898
1899 on_edge = 1;
1900
1901 if ( point == point->prev )
1902 {
1903 /* we have a one-point segment: this is a one-point */
1904 /* contour with `in' and `out' direction set to */
1905 /* AF_DIR_NONE */
1906 segment->pos = (FT_Short)min_pos;
1907
1908 if (point->flags & AF_FLAG_CONTROL)
1909 segment->flags |= AF_EDGE_ROUND;
1910
1911 segment->min_coord = (FT_Short)point->v;
1912 segment->max_coord = (FT_Short)point->v;
1913 segment->height = 0;
1914
1915 on_edge = 0;
1916 segment = NULL;
1917 }
1918 }
1919
1920 point = point->next;
1921 }
1922
1923 } /* contours */
1924
1925
1926 /* now slightly increase the height of segments if this makes */
1927 /* sense -- this is used to better detect and ignore serifs */
1928 {
1929 AF_Segment segments = axis->segments;
1930 AF_Segment segments_end = FT_OFFSET( segments, axis->num_segments );
1931
1932
1933 for ( segment = segments; segment < segments_end; segment++ )
1934 {
1935 AF_Point first = segment->first;
1936 AF_Point last = segment->last;
1937 FT_Pos first_v = first->v;
1938 FT_Pos last_v = last->v;
1939
1940
1941 if ( first_v < last_v )
1942 {
1943 AF_Point p;
1944
1945
1946 p = first->prev;
1947 if ( p->v < first_v )
1948 segment->height = (FT_Short)( segment->height +
1949 ( ( first_v - p->v ) >> 1 ) );
1950
1951 p = last->next;
1952 if ( p->v > last_v )
1953 segment->height = (FT_Short)( segment->height +
1954 ( ( p->v - last_v ) >> 1 ) );
1955 }
1956 else
1957 {
1958 AF_Point p;
1959
1960
1961 p = first->prev;
1962 if ( p->v > first_v )
1963 segment->height = (FT_Short)( segment->height +
1964 ( ( p->v - first_v ) >> 1 ) );
1965
1966 p = last->next;
1967 if ( p->v < last_v )
1968 segment->height = (FT_Short)( segment->height +
1969 ( ( last_v - p->v ) >> 1 ) );
1970 }
1971 }
1972 }
1973
1974 Exit:
1975 return error;
1976 }
af_axis_hints_new_segment(AF_AxisHints axis, FT_Memory memory, AF_Segment *asegment)
Definition: afhints.c:38
#define AF_FLAG_NONE
Definition: afhints.h:210
#define AF_FLAG_CONTROL
Definition: afhints.h:215
#define FLAT_THRESHOLD(x)
Definition: aflatin.c:43
POINTL point
Definition: edittest.c:50
unsigned short FT_UShort
Definition: fttypes.h:209
signed short FT_Short
Definition: fttypes.h:198
const GLdouble * v
Definition: gl.h:2040
GLint limit
Definition: glext.h:10326
const GLint * first
Definition: glext.h:5794
GLfloat GLfloat p
Definition: glext.h:8902
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble * u
Definition: glfuncs.h:240
static UINT UINT last
Definition: font.c:45
FT_Char in_dir
Definition: afhints.h:244
AF_Point last
Definition: afhints.h:283

Referenced by af_latin_hints_detect_features(), and af_latin_metrics_init_widths().

◆ af_latin_hints_detect_features()

af_latin_hints_detect_features ( AF_GlyphHints  hints,
FT_UInt  width_count,
AF_WidthRec widths,
AF_Dimension  dim 
)

Definition at line 2473 of file aflatin.c.

2477 {
2479
2480
2482 if ( !error )
2483 {
2484 af_latin_hints_link_segments( hints, width_count, widths, dim );
2485
2487 }
2488
2489 return error;
2490 }
af_latin_hints_link_segments(AF_GlyphHints hints, FT_UInt width_count, AF_WidthRec *widths, AF_Dimension dim)
Definition: aflatin.c:1983
af_latin_hints_compute_segments(AF_GlyphHints hints, AF_Dimension dim)
Definition: aflatin.c:1555
af_latin_hints_compute_edges(AF_GlyphHints hints, AF_Dimension dim)
Definition: aflatin.c:2121

Referenced by af_latin_hints_apply().

◆ af_latin_hints_init()

static FT_Error af_latin_hints_init ( AF_GlyphHints  hints,
AF_LatinMetrics  metrics 
)
static

Definition at line 2610 of file aflatin.c.

2612 {
2614 FT_UInt32 scaler_flags, other_flags;
2615 FT_Face face = metrics->root.scaler.face;
2616
2617
2619
2620 /*
2621 * correct x_scale and y_scale if needed, since they may have
2622 * been modified by `af_latin_metrics_scale_dim' above
2623 */
2624 hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
2625 hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
2626 hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale;
2627 hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta;
2628
2629 /* compute flags depending on render mode, etc. */
2630 mode = metrics->root.scaler.render_mode;
2631
2632#if 0 /* #ifdef AF_CONFIG_OPTION_USE_WARPER */
2634 metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL;
2635#endif
2636
2637 scaler_flags = hints->scaler_flags;
2638 other_flags = 0;
2639
2640 /*
2641 * We snap the width of vertical stems for the monochrome and
2642 * horizontal LCD rendering targets only.
2643 */
2645 other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
2646
2647 /*
2648 * We snap the width of horizontal stems for the monochrome and
2649 * vertical LCD rendering targets only.
2650 */
2652 other_flags |= AF_LATIN_HINTS_VERT_SNAP;
2653
2654 /*
2655 * We adjust stems to full pixels unless in `light' or `lcd' mode.
2656 */
2658 other_flags |= AF_LATIN_HINTS_STEM_ADJUST;
2659
2660 if ( mode == FT_RENDER_MODE_MONO )
2661 other_flags |= AF_LATIN_HINTS_MONO;
2662
2663 /*
2664 * In `light' or `lcd' mode we disable horizontal hinting completely.
2665 * We also do it if the face is italic.
2666 *
2667 * However, if warping is enabled (which only works in `light' hinting
2668 * mode), advance widths get adjusted, too.
2669 */
2671 ( face->style_flags & FT_STYLE_FLAG_ITALIC ) != 0 )
2672 scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL;
2673
2674#ifdef AF_CONFIG_OPTION_USE_WARPER
2675 /* get (global) warper flag */
2676 if ( !metrics->root.globals->module->warping )
2677 scaler_flags |= AF_SCALER_FLAG_NO_WARPER;
2678#endif
2679
2680 hints->scaler_flags = scaler_flags;
2681 hints->other_flags = other_flags;
2682
2683 return FT_Err_Ok;
2684 }
af_glyph_hints_rescale(AF_GlyphHints hints, AF_StyleMetrics metrics)
Definition: afhints.c:750
#define AF_LATIN_HINTS_STEM_ADJUST
Definition: aflatin.h:145
#define AF_LATIN_HINTS_VERT_SNAP
Definition: aflatin.h:144
#define AF_LATIN_HINTS_MONO
Definition: aflatin.h:147
#define AF_LATIN_HINTS_HORZ_SNAP
Definition: aflatin.h:143
#define AF_SCALER_FLAG_NO_WARPER
Definition: aftypes.h:175
#define AF_SCALER_FLAG_NO_HORIZONTAL
Definition: aftypes.h:172
#define FT_STYLE_FLAG_ITALIC
Definition: freetype.h:1475
enum FT_Render_Mode_ FT_Render_Mode
@ FT_RENDER_MODE_MONO
Definition: freetype.h:3251
@ FT_RENDER_MODE_LIGHT
Definition: freetype.h:3250
@ FT_RENDER_MODE_LCD_V
Definition: freetype.h:3253
@ FT_RENDER_MODE_LCD
Definition: freetype.h:3252
GLenum GLuint GLint GLenum face
Definition: glext.h:7025
GLenum mode
Definition: glext.h:6217

◆ af_latin_hints_link_segments()

af_latin_hints_link_segments ( AF_GlyphHints  hints,
FT_UInt  width_count,
AF_WidthRec widths,
AF_Dimension  dim 
)

Definition at line 1983 of file aflatin.c.

1987 {
1988 AF_AxisHints axis = &hints->axis[dim];
1989 AF_Segment segments = axis->segments;
1990 AF_Segment segment_limit = segments + axis->num_segments;
1991 FT_Pos len_threshold, len_score, dist_score, max_width;
1992 AF_Segment seg1, seg2;
1993
1994
1995 if ( width_count )
1996 max_width = widths[width_count - 1].org;
1997 else
1998 max_width = 0;
1999
2000 /* a heuristic value to set up a minimum value for overlapping */
2001 len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 );
2002 if ( len_threshold == 0 )
2003 len_threshold = 1;
2004
2005 /* a heuristic value to weight lengths */
2006 len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 );
2007
2008 /* a heuristic value to weight distances (no call to */
2009 /* AF_LATIN_CONSTANT needed, since we work on multiples */
2010 /* of the stem width) */
2011 dist_score = 3000;
2012
2013 /* now compare each segment to the others */
2014 for ( seg1 = segments; seg1 < segment_limit; seg1++ )
2015 {
2016 if ( seg1->dir != axis->major_dir )
2017 continue;
2018
2019 /* search for stems having opposite directions, */
2020 /* with seg1 to the `left' of seg2 */
2021 for ( seg2 = segments; seg2 < segment_limit; seg2++ )
2022 {
2023 FT_Pos pos1 = seg1->pos;
2024 FT_Pos pos2 = seg2->pos;
2025
2026
2027 if ( seg1->dir + seg2->dir == 0 && pos2 > pos1 )
2028 {
2029 /* compute distance between the two segments */
2030 FT_Pos min = seg1->min_coord;
2031 FT_Pos max = seg1->max_coord;
2032 FT_Pos len;
2033
2034
2035 if ( min < seg2->min_coord )
2036 min = seg2->min_coord;
2037
2038 if ( max > seg2->max_coord )
2039 max = seg2->max_coord;
2040
2041 /* compute maximum coordinate difference of the two segments */
2042 /* (this is, how much they overlap) */
2043 len = max - min;
2044 if ( len >= len_threshold )
2045 {
2046 /*
2047 * The score is the sum of two demerits indicating the
2048 * `badness' of a fit, measured along the segments' main axis
2049 * and orthogonal to it, respectively.
2050 *
2051 * - The less overlapping along the main axis, the worse it
2052 * is, causing a larger demerit.
2053 *
2054 * - The nearer the orthogonal distance to a stem width, the
2055 * better it is, causing a smaller demerit. For simplicity,
2056 * however, we only increase the demerit for values that
2057 * exceed the largest stem width.
2058 */
2059
2060 FT_Pos dist = pos2 - pos1;
2061
2062 FT_Pos dist_demerit, score;
2063
2064
2065 if ( max_width )
2066 {
2067 /* distance demerits are based on multiples of `max_width'; */
2068 /* we scale by 1024 for getting more precision */
2069 FT_Pos delta = ( dist << 10 ) / max_width - ( 1 << 10 );
2070
2071
2072 if ( delta > 10000 )
2073 dist_demerit = 32000;
2074 else if ( delta > 0 )
2075 dist_demerit = delta * delta / dist_score;
2076 else
2077 dist_demerit = 0;
2078 }
2079 else
2080 dist_demerit = dist; /* default if no widths available */
2081
2082 score = dist_demerit + len_score / len;
2083
2084 /* and we search for the smallest score */
2085 if ( score < seg1->score )
2086 {
2087 seg1->score = score;
2088 seg1->link = seg2;
2089 }
2090
2091 if ( score < seg2->score )
2092 {
2093 seg2->score = score;
2094 seg2->link = seg1;
2095 }
2096 }
2097 }
2098 }
2099 }
2100
2101 /* now compute the `serif' segments, cf. explanations in `afhints.h' */
2102 for ( seg1 = segments; seg1 < segment_limit; seg1++ )
2103 {
2104 seg2 = seg1->link;
2105
2106 if ( seg2 )
2107 {
2108 if ( seg2->link != seg1 )
2109 {
2110 seg1->link = 0;
2111 seg1->serif = seg2->link;
2112 }
2113 }
2114 }
2115 }
#define AF_LATIN_CONSTANT(metrics, c)
Definition: aflatin.h:34
GLenum GLsizei len
Definition: glext.h:6722
#define min(a, b)
Definition: monoChain.cc:55
FT_Pos score
Definition: afhints.h:279
#define max(a, b)
Definition: svc.c:63

Referenced by af_latin_hints_detect_features(), and af_latin_metrics_init_widths().

◆ af_latin_metrics_check_digits()

af_latin_metrics_check_digits ( AF_LatinMetrics  metrics,
FT_Face  face 
)

Definition at line 1092 of file aflatin.c.

1094 {
1095 FT_Bool started = 0, same_width = 1;
1096 FT_Fixed advance = 0, old_advance = 0;
1097
1098 /* If HarfBuzz is not available, we need a pointer to a single */
1099 /* unsigned long value. */
1100#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
1101 void* shaper_buf;
1102#else
1103 FT_ULong shaper_buf_;
1104 void* shaper_buf = &shaper_buf_;
1105#endif
1106
1107 /* in all supported charmaps, digits have character codes 0x30-0x39 */
1108 const char digits[] = "0 1 2 3 4 5 6 7 8 9";
1109 const char* p;
1110
1111
1112 p = digits;
1113
1114#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
1115 shaper_buf = af_shaper_buf_create( face );
1116#endif
1117
1118 while ( *p )
1119 {
1120 FT_ULong glyph_index;
1121 unsigned int num_idx;
1122
1123
1124 /* reject input that maps to more than a single glyph */
1125 p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
1126 if ( num_idx > 1 )
1127 continue;
1128
1129 glyph_index = af_shaper_get_elem( &metrics->root,
1130 shaper_buf,
1131 0,
1132 &advance,
1133 NULL );
1134 if ( !glyph_index )
1135 continue;
1136
1137 if ( started )
1138 {
1139 if ( advance != old_advance )
1140 {
1141 same_width = 0;
1142 break;
1143 }
1144 }
1145 else
1146 {
1147 old_advance = advance;
1148 started = 1;
1149 }
1150 }
1151
1152 af_shaper_buf_destroy( face, shaper_buf );
1153
1154 metrics->root.digits_have_same_width = same_width;
1155 }
_STLP_MOVE_TO_STD_NAMESPACE void _STLP_CALL advance(_InputIterator &__i, _Distance __n)
void * af_shaper_buf_create(FT_Face face)
Definition: afshaper.c:591
const char * af_shaper_get_cluster(const char *p, AF_StyleMetrics metrics, void *buf_, unsigned int *count)
Definition: afshaper.c:609
FT_ULong af_shaper_get_elem(AF_StyleMetrics metrics, void *buf_, unsigned int idx, FT_Long *advance, FT_Long *y_offset)
Definition: afshaper.c:645
void af_shaper_buf_destroy(FT_Face face, void *buf)
Definition: afshaper.c:600
unsigned long FT_ULong
Definition: fttypes.h:253
static const int digits[]
Definition: decode.c:71

Referenced by af_latin_metrics_init().

◆ af_latin_metrics_init()

af_latin_metrics_init ( AF_LatinMetrics  metrics,
FT_Face  face 
)

Definition at line 1161 of file aflatin.c.

1163 {
1165
1166 FT_CharMap oldmap = face->charmap;
1167
1168
1169 metrics->units_per_em = face->units_per_EM;
1170
1171 if ( !FT_Select_Charmap( face, FT_ENCODING_UNICODE ) )
1172 {
1175 {
1176 /* use internal error code to indicate missing blue zones */
1177 error = -1;
1178 goto Exit;
1179 }
1181 }
1182
1183 Exit:
1184 FT_Set_Charmap( face, oldmap );
1185 return error;
1186 }
static int af_latin_metrics_init_blues(AF_LatinMetrics metrics, FT_Face face)
Definition: aflatin.c:337
af_latin_metrics_init_widths(AF_LatinMetrics metrics, FT_Face face)
Definition: aflatin.c:59
af_latin_metrics_check_digits(AF_LatinMetrics metrics, FT_Face face)
Definition: aflatin.c:1092
FT_Select_Charmap(FT_Face face, FT_Encoding encoding)
Definition: ftobjs.c:3521
FT_Set_Charmap(FT_Face face, FT_CharMap charmap)
Definition: ftobjs.c:3564

◆ af_latin_metrics_init_blues()

static int af_latin_metrics_init_blues ( AF_LatinMetrics  metrics,
FT_Face  face 
)
static

Definition at line 337 of file aflatin.c.

339 {
342
343 FT_UInt num_flats;
344 FT_UInt num_rounds;
345
350
351 AF_StyleClass sc = metrics->root.style_class;
352
355
356 FT_Pos flat_threshold = FLAT_THRESHOLD( metrics->units_per_em );
357
358 /* If HarfBuzz is not available, we need a pointer to a single */
359 /* unsigned long value. */
360#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
361 void* shaper_buf;
362#else
363 FT_ULong shaper_buf_;
364 void* shaper_buf = &shaper_buf_;
365#endif
366
367
368 /* we walk over the blue character strings as specified in the */
369 /* style's entry in the `af_blue_stringset' array */
370
371 FT_TRACE5(( "latin blue zones computation\n"
372 "============================\n"
373 "\n" ));
374
375#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
376 shaper_buf = af_shaper_buf_create( face );
377#endif
378
379 for ( ; bs->string != AF_BLUE_STRING_MAX; bs++ )
380 {
381 const char* p = &af_blue_strings[bs->string];
382 FT_Pos* blue_ref;
383 FT_Pos* blue_shoot;
384 FT_Pos ascender;
385 FT_Pos descender;
386
387
388#ifdef FT_DEBUG_LEVEL_TRACE
389 {
390 FT_Bool have_flag = 0;
391
392
393 FT_TRACE5(( "blue zone %d", axis->blue_count ));
394
395 if ( bs->properties )
396 {
397 FT_TRACE5(( " (" ));
398
399 if ( AF_LATIN_IS_TOP_BLUE( bs ) )
400 {
401 FT_TRACE5(( "top" ));
402 have_flag = 1;
403 }
404 else if ( AF_LATIN_IS_SUB_TOP_BLUE( bs ) )
405 {
406 FT_TRACE5(( "sub top" ));
407 have_flag = 1;
408 }
409
411 {
412 if ( have_flag )
413 FT_TRACE5(( ", " ));
414 FT_TRACE5(( "neutral" ));
415 have_flag = 1;
416 }
417
419 {
420 if ( have_flag )
421 FT_TRACE5(( ", " ));
422 FT_TRACE5(( "small top" ));
423 have_flag = 1;
424 }
425
426 if ( AF_LATIN_IS_LONG_BLUE( bs ) )
427 {
428 if ( have_flag )
429 FT_TRACE5(( ", " ));
430 FT_TRACE5(( "long" ));
431 }
432
433 FT_TRACE5(( ")" ));
434 }
435
436 FT_TRACE5(( ":\n" ));
437 }
438#endif /* FT_DEBUG_LEVEL_TRACE */
439
440 num_flats = 0;
441 num_rounds = 0;
442 ascender = 0;
443 descender = 0;
444
445 while ( *p )
446 {
447 FT_ULong glyph_index;
448 FT_Long y_offset;
449 FT_Int best_point, best_contour_first, best_contour_last;
451
452 FT_Pos best_y_extremum; /* same as points.y */
453 FT_Bool best_round = 0;
454
455 unsigned int i, num_idx;
456
457#ifdef FT_DEBUG_LEVEL_TRACE
458 const char* p_old;
459 FT_ULong ch;
460#endif
461
462
463 while ( *p == ' ' )
464 p++;
465
466#ifdef FT_DEBUG_LEVEL_TRACE
467 p_old = p;
468 GET_UTF8_CHAR( ch, p_old );
469#endif
470
471 p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
472
473 if ( !num_idx )
474 {
475 FT_TRACE5(( " U+%04lX unavailable\n", ch ));
476 continue;
477 }
478
479 if ( AF_LATIN_IS_TOP_BLUE( bs ) )
480 best_y_extremum = FT_INT_MIN;
481 else
482 best_y_extremum = FT_INT_MAX;
483
484 /* iterate over all glyph elements of the character cluster */
485 /* and get the data of the `biggest' one */
486 for ( i = 0; i < num_idx; i++ )
487 {
488 FT_Pos best_y;
489 FT_Bool round = 0;
490
491
492 /* load the character in the face -- skip unknown or empty ones */
493 glyph_index = af_shaper_get_elem( &metrics->root,
494 shaper_buf,
495 i,
496 NULL,
497 &y_offset );
498 if ( glyph_index == 0 )
499 {
500 FT_TRACE5(( " U+%04lX unavailable\n", ch ));
501 continue;
502 }
503
504 error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
505 outline = face->glyph->outline;
506 /* reject glyphs that don't produce any rendering */
507 if ( error || outline.n_points <= 2 )
508 {
509#ifdef FT_DEBUG_LEVEL_TRACE
510 if ( num_idx == 1 )
511 FT_TRACE5(( " U+%04lX contains no (usable) outlines\n", ch ));
512 else
513 FT_TRACE5(( " component %d of cluster starting with U+%04lX"
514 " contains no (usable) outlines\n", i, ch ));
515#endif
516 continue;
517 }
518
519 /* now compute min or max point indices and coordinates */
520 points = outline.points;
521 best_point = -1;
522 best_y = 0; /* make compiler happy */
523 best_contour_first = 0; /* ditto */
524 best_contour_last = 0; /* ditto */
525
526 {
527 FT_Int nn;
528 FT_Int first = 0;
529 FT_Int last = -1;
530
531
532 for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ )
533 {
534 FT_Int old_best_point = best_point;
535 FT_Int pp;
536
537
538 last = outline.contours[nn];
539
540 /* Avoid single-point contours since they are never */
541 /* rasterized. In some fonts, they correspond to mark */
542 /* attachment points that are way outside of the glyph's */
543 /* real outline. */
544 if ( last <= first )
545 continue;
546
547 if ( AF_LATIN_IS_TOP_BLUE( bs ) ||
549 {
550 for ( pp = first; pp <= last; pp++ )
551 {
552 if ( best_point < 0 || points[pp].y > best_y )
553 {
554 best_point = pp;
555 best_y = points[pp].y;
556 ascender = FT_MAX( ascender, best_y + y_offset );
557 }
558 else
559 descender = FT_MIN( descender, points[pp].y + y_offset );
560 }
561 }
562 else
563 {
564 for ( pp = first; pp <= last; pp++ )
565 {
566 if ( best_point < 0 || points[pp].y < best_y )
567 {
568 best_point = pp;
569 best_y = points[pp].y;
570 descender = FT_MIN( descender, best_y + y_offset );
571 }
572 else
573 ascender = FT_MAX( ascender, points[pp].y + y_offset );
574 }
575 }
576
577 if ( best_point != old_best_point )
578 {
579 best_contour_first = first;
580 best_contour_last = last;
581 }
582 }
583 }
584
585 /* now check whether the point belongs to a straight or round */
586 /* segment; we first need to find in which contour the extremum */
587 /* lies, then inspect its previous and next points */
588 if ( best_point >= 0 )
589 {
590 FT_Pos best_x = points[best_point].x;
591 FT_Int prev, next;
592 FT_Int best_segment_first, best_segment_last;
593 FT_Int best_on_point_first, best_on_point_last;
594 FT_Pos dist;
595
596
597 best_segment_first = best_point;
598 best_segment_last = best_point;
599
600 if ( FT_CURVE_TAG( outline.tags[best_point] ) == FT_CURVE_TAG_ON )
601 {
602 best_on_point_first = best_point;
603 best_on_point_last = best_point;
604 }
605 else
606 {
607 best_on_point_first = -1;
608 best_on_point_last = -1;
609 }
610
611 /* look for the previous and next points on the contour */
612 /* that are not on the same Y coordinate, then threshold */
613 /* the `closeness'... */
614 prev = best_point;
615 next = prev;
616
617 do
618 {
619 if ( prev > best_contour_first )
620 prev--;
621 else
622 prev = best_contour_last;
623
624 dist = FT_ABS( points[prev].y - best_y );
625 /* accept a small distance or a small angle (both values are */
626 /* heuristic; value 20 corresponds to approx. 2.9 degrees) */
627 if ( dist > 5 )
628 if ( FT_ABS( points[prev].x - best_x ) <= 20 * dist )
629 break;
630
631 best_segment_first = prev;
632
633 if ( FT_CURVE_TAG( outline.tags[prev] ) == FT_CURVE_TAG_ON )
634 {
635 best_on_point_first = prev;
636 if ( best_on_point_last < 0 )
637 best_on_point_last = prev;
638 }
639
640 } while ( prev != best_point );
641
642 do
643 {
644 if ( next < best_contour_last )
645 next++;
646 else
647 next = best_contour_first;
648
649 dist = FT_ABS( points[next].y - best_y );
650 if ( dist > 5 )
651 if ( FT_ABS( points[next].x - best_x ) <= 20 * dist )
652 break;
653
654 best_segment_last = next;
655
656 if ( FT_CURVE_TAG( outline.tags[next] ) == FT_CURVE_TAG_ON )
657 {
658 best_on_point_last = next;
659 if ( best_on_point_first < 0 )
660 best_on_point_first = next;
661 }
662
663 } while ( next != best_point );
664
665 if ( AF_LATIN_IS_LONG_BLUE( bs ) )
666 {
667 /* If this flag is set, we have an additional constraint to */
668 /* get the blue zone distance: Find a segment of the topmost */
669 /* (or bottommost) contour that is longer than a heuristic */
670 /* threshold. This ensures that small bumps in the outline */
671 /* are ignored (for example, the `vertical serifs' found in */
672 /* many Hebrew glyph designs). */
673
674 /* If this segment is long enough, we are done. Otherwise, */
675 /* search the segment next to the extremum that is long */
676 /* enough, has the same direction, and a not too large */
677 /* vertical distance from the extremum. Note that the */
678 /* algorithm doesn't check whether the found segment is */
679 /* actually the one (vertically) nearest to the extremum. */
680
681 /* heuristic threshold value */
682 FT_Pos length_threshold = metrics->units_per_em / 25;
683
684
685 dist = FT_ABS( points[best_segment_last].x -
686 points[best_segment_first].x );
687
688 if ( dist < length_threshold &&
689 best_segment_last - best_segment_first + 2 <=
690 best_contour_last - best_contour_first )
691 {
692 /* heuristic threshold value */
693 FT_Pos height_threshold = metrics->units_per_em / 4;
694
696 FT_Int last;
697 FT_Bool hit;
698
699 /* we intentionally declare these two variables */
700 /* outside of the loop since various compilers emit */
701 /* incorrect warning messages otherwise, talking about */
702 /* `possibly uninitialized variables' */
703 FT_Int p_first = 0; /* make compiler happy */
704 FT_Int p_last = 0;
705
706 FT_Bool left2right;
707
708
709 /* compute direction */
710 prev = best_point;
711
712 do
713 {
714 if ( prev > best_contour_first )
715 prev--;
716 else
717 prev = best_contour_last;
718
719 if ( points[prev].x != best_x )
720 break;
721
722 } while ( prev != best_point );
723
724 /* skip glyph for the degenerate case */
725 if ( prev == best_point )
726 continue;
727
728 left2right = FT_BOOL( points[prev].x < points[best_point].x );
729
730 first = best_segment_last;
731 last = first;
732 hit = 0;
733
734 do
735 {
736 FT_Bool l2r;
737 FT_Pos d;
738
739
740 if ( !hit )
741 {
742 /* no hit; adjust first point */
743 first = last;
744
745 /* also adjust first and last on point */
746 if ( FT_CURVE_TAG( outline.tags[first] ) ==
748 {
749 p_first = first;
750 p_last = first;
751 }
752 else
753 {
754 p_first = -1;
755 p_last = -1;
756 }
757
758 hit = 1;
759 }
760
761 if ( last < best_contour_last )
762 last++;
763 else
764 last = best_contour_first;
765
766 if ( FT_ABS( best_y - points[first].y ) > height_threshold )
767 {
768 /* vertical distance too large */
769 hit = 0;
770 continue;
771 }
772
773 /* same test as above */
774 dist = FT_ABS( points[last].y - points[first].y );
775 if ( dist > 5 )
776 if ( FT_ABS( points[last].x - points[first].x ) <=
777 20 * dist )
778 {
779 hit = 0;
780 continue;
781 }
782
783 if ( FT_CURVE_TAG( outline.tags[last] ) == FT_CURVE_TAG_ON )
784 {
785 p_last = last;
786 if ( p_first < 0 )
787 p_first = last;
788 }
789
790 l2r = FT_BOOL( points[first].x < points[last].x );
791 d = FT_ABS( points[last].x - points[first].x );
792
793 if ( l2r == left2right &&
794 d >= length_threshold )
795 {
796 /* all constraints are met; update segment after */
797 /* finding its end */
798 do
799 {
800 if ( last < best_contour_last )
801 last++;
802 else
803 last = best_contour_first;
804
805 d = FT_ABS( points[last].y - points[first].y );
806 if ( d > 5 )
807 if ( FT_ABS( points[next].x - points[first].x ) <=
808 20 * dist )
809 {
810 if ( last > best_contour_first )
811 last--;
812 else
813 last = best_contour_last;
814 break;
815 }
816
817 p_last = last;
818
819 if ( FT_CURVE_TAG( outline.tags[last] ) ==
821 {
822 p_last = last;
823 if ( p_first < 0 )
824 p_first = last;
825 }
826
827 } while ( last != best_segment_first );
828
829 best_y = points[first].y;
830
831 best_segment_first = first;
832 best_segment_last = last;
833
834 best_on_point_first = p_first;
835 best_on_point_last = p_last;
836
837 break;
838 }
839
840 } while ( last != best_segment_first );
841 }
842 }
843
844 /* for computing blue zones, we add the y offset as returned */
845 /* by the currently used OpenType feature -- for example, */
846 /* superscript glyphs might be identical to subscript glyphs */
847 /* with a vertical shift */
848 best_y += y_offset;
849
850#ifdef FT_DEBUG_LEVEL_TRACE
851 if ( num_idx == 1 )
852 FT_TRACE5(( " U+%04lX: best_y = %5ld", ch, best_y ));
853 else
854 FT_TRACE5(( " component %d of cluster starting with U+%04lX:"
855 " best_y = %5ld", i, ch, best_y ));
856#endif
857
858 /* now set the `round' flag depending on the segment's kind: */
859 /* */
860 /* - if the horizontal distance between the first and last */
861 /* `on' point is larger than a heuristic threshold */
862 /* we have a flat segment */
863 /* - if either the first or the last point of the segment is */
864 /* an `off' point, the segment is round, otherwise it is */
865 /* flat */
866 if ( best_on_point_first >= 0 &&
867 best_on_point_last >= 0 &&
868 ( FT_ABS( points[best_on_point_last].x -
869 points[best_on_point_first].x ) ) >
870 flat_threshold )
871 round = 0;
872 else
873 round = FT_BOOL(
874 FT_CURVE_TAG( outline.tags[best_segment_first] ) !=
876 FT_CURVE_TAG( outline.tags[best_segment_last] ) !=
878
880 {
881 /* only use flat segments for a neutral blue zone */
882 FT_TRACE5(( " (round, skipped)\n" ));
883 continue;
884 }
885
886 FT_TRACE5(( " (%s)\n", round ? "round" : "flat" ));
887 }
888
889 if ( AF_LATIN_IS_TOP_BLUE( bs ) )
890 {
891 if ( best_y > best_y_extremum )
892 {
893 best_y_extremum = best_y;
894 best_round = round;
895 }
896 }
897 else
898 {
899 if ( best_y < best_y_extremum )
900 {
901 best_y_extremum = best_y;
902 best_round = round;
903 }
904 }
905
906 } /* end for loop */
907
908 if ( !( best_y_extremum == FT_INT_MIN ||
909 best_y_extremum == FT_INT_MAX ) )
910 {
911 if ( best_round )
912 rounds[num_rounds++] = best_y_extremum;
913 else
914 flats[num_flats++] = best_y_extremum;
915 }
916
917 } /* end while loop */
918
919 if ( num_flats == 0 && num_rounds == 0 )
920 {
921 /*
922 * we couldn't find a single glyph to compute this blue zone,
923 * we will simply ignore it then
924 */
925 FT_TRACE5(( " empty\n" ));
926 continue;
927 }
928
929 /* we have computed the contents of the `rounds' and `flats' tables, */
930 /* now determine the reference and overshoot position of the blue -- */
931 /* we simply take the median value after a simple sort */
932 af_sort_pos( num_rounds, rounds );
933 af_sort_pos( num_flats, flats );
934
935 blue = &axis->blues[axis->blue_count];
936 blue_ref = &blue->ref.org;
937 blue_shoot = &blue->shoot.org;
938
939 axis->blue_count++;
940
941 if ( num_flats == 0 )
942 {
943 *blue_ref =
944 *blue_shoot = rounds[num_rounds / 2];
945 }
946 else if ( num_rounds == 0 )
947 {
948 *blue_ref =
949 *blue_shoot = flats[num_flats / 2];
950 }
951 else
952 {
953 *blue_ref = flats [num_flats / 2];
954 *blue_shoot = rounds[num_rounds / 2];
955 }
956
957 /* there are sometimes problems: if the overshoot position of top */
958 /* zones is under its reference position, or the opposite for bottom */
959 /* zones. We must thus check everything there and correct the errors */
960 if ( *blue_shoot != *blue_ref )
961 {
962 FT_Pos ref = *blue_ref;
963 FT_Pos shoot = *blue_shoot;
964 FT_Bool over_ref = FT_BOOL( shoot > ref );
965
966
967 if ( ( AF_LATIN_IS_TOP_BLUE( bs ) ||
968 AF_LATIN_IS_SUB_TOP_BLUE( bs) ) ^ over_ref )
969 {
970 *blue_ref =
971 *blue_shoot = ( shoot + ref ) / 2;
972
973 FT_TRACE5(( " [overshoot smaller than reference,"
974 " taking mean value]\n" ));
975 }
976 }
977
978 blue->ascender = ascender;
979 blue->descender = descender;
980
981 blue->flags = 0;
982 if ( AF_LATIN_IS_TOP_BLUE( bs ) )
983 blue->flags |= AF_LATIN_BLUE_TOP;
985 blue->flags |= AF_LATIN_BLUE_SUB_TOP;
987 blue->flags |= AF_LATIN_BLUE_NEUTRAL;
988
989 /*
990 * The following flag is used later to adjust the y and x scales
991 * in order to optimize the pixel grid alignment of the top of small
992 * letters.
993 */
996
997 FT_TRACE5(( " -> reference = %ld\n"
998 " overshoot = %ld\n",
999 *blue_ref, *blue_shoot ));
1000
1001 } /* end for loop */
1002
1003 af_shaper_buf_destroy( face, shaper_buf );
1004
1005 if ( axis->blue_count )
1006 {
1007 /* we finally check whether blue zones are ordered; */
1008 /* `ref' and `shoot' values of two blue zones must not overlap */
1009
1010 FT_UInt i;
1011 AF_LatinBlue blue_sorted[AF_BLUE_STRINGSET_MAX_LEN + 2];
1012
1013
1014 for ( i = 0; i < axis->blue_count; i++ )
1015 blue_sorted[i] = &axis->blues[i];
1016
1017 /* sort bottoms of blue zones... */
1018 af_latin_sort_blue( axis->blue_count, blue_sorted );
1019
1020 /* ...and adjust top values if necessary */
1021 for ( i = 0; i < axis->blue_count - 1; i++ )
1022 {
1023 FT_Pos* a;
1024 FT_Pos* b;
1025
1026#ifdef FT_DEBUG_LEVEL_TRACE
1027 FT_Bool a_is_top = 0;
1028#endif
1029
1030
1031 if ( blue_sorted[i]->flags & ( AF_LATIN_BLUE_TOP |
1033 {
1034 a = &blue_sorted[i]->shoot.org;
1035#ifdef FT_DEBUG_LEVEL_TRACE
1036 a_is_top = 1;
1037#endif
1038 }
1039 else
1040 a = &blue_sorted[i]->ref.org;
1041
1042 if ( blue_sorted[i + 1]->flags & ( AF_LATIN_BLUE_TOP |
1044 b = &blue_sorted[i + 1]->shoot.org;
1045 else
1046 b = &blue_sorted[i + 1]->ref.org;
1047
1048 if ( *a > *b )
1049 {
1050 *a = *b;
1051 FT_TRACE5(( "blue zone overlap:"
1052 " adjusting %s %ld to %ld\n",
1053 a_is_top ? "overshoot" : "reference",
1054 blue_sorted[i] - axis->blues,
1055 *a ));
1056 }
1057 }
1058
1059 FT_TRACE5(( "\n" ));
1060
1061 return 0;
1062 }
1063 else
1064 {
1065 /* disable hinting for the current style if there are no blue zones */
1066
1067 AF_FaceGlobals globals = metrics->root.globals;
1068 FT_UShort* gstyles = globals->glyph_styles;
1069
1070 FT_Long i;
1071
1072
1073 FT_TRACE5(( "no blue zones found:"
1074 " hinting disabled for this style\n" ));
1075
1076 for ( i = 0; i < globals->glyph_count; i++ )
1077 {
1078 if ( ( gstyles[i] & AF_STYLE_MASK ) == sc->style )
1079 gstyles[i] = AF_STYLE_NONE_DFLT;
1080 }
1081
1082 FT_TRACE5(( "\n" ));
1083
1084 return 1;
1085 }
1086 }
af_sort_pos(FT_UInt count, FT_Pos *table)
Definition: afangles.c:187
af_blue_stringsets[]
Definition: afblue.c:467
af_blue_strings[]
Definition: afblue.c:26
@ AF_BLUE_STRING_MAX
Definition: afblue.h:294
#define AF_BLUE_STRING_MAX_LEN
Definition: afblue.h:73
#define GET_UTF8_CHAR(ch, p)
Definition: afblue.h:31
#define AF_BLUE_STRINGSET_MAX_LEN
Definition: afblue.h:328
enum AF_Blue_Stringset_ AF_Blue_Stringset
#define AF_STYLE_MASK
Definition: afglobal.h:77
static void af_latin_sort_blue(FT_UInt count, AF_LatinBlue *table)
Definition: aflatin.c:295
#define AF_LATIN_IS_X_HEIGHT_BLUE(b)
Definition: aflatin.h:60
#define AF_LATIN_IS_TOP_BLUE(b)
Definition: aflatin.h:54
#define AF_LATIN_IS_LONG_BLUE(b)
Definition: aflatin.h:62
#define AF_LATIN_IS_NEUTRAL_BLUE(b)
Definition: aflatin.h:58
#define AF_LATIN_IS_SUB_TOP_BLUE(b)
Definition: aflatin.h:56
#define AF_LATIN_BLUE_ADJUSTMENT
Definition: aflatin.h:73
unsigned char ch[4][2]
Definition: console.c:118
FT_Load_Glyph(FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags)
Definition: ftobjs.c:796
#define FT_LOAD_NO_SCALE
Definition: freetype.h:3022
#define FT_CURVE_TAG(flag)
Definition: ftimage.h:459
#define FT_CURVE_TAG_ON
Definition: ftimage.h:462
#define FT_MIN(a, b)
Definition: ftobjs.h:70
#define FT_MAX(a, b)
Definition: ftobjs.h:71
#define FT_INT_MIN
Definition: ftstdlib.h:64
#define FT_INT_MAX
Definition: ftstdlib.h:63
signed long FT_Long
Definition: fttypes.h:242
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
GLsizei const GLfloat * points
Definition: glext.h:8112
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define d
Definition: ke_i.h:81
#define a
Definition: ke_i.h:78
#define b
Definition: ke_i.h:79
static struct msdos_boot_sector bs
Definition: mkdosfs.c:539
#define round(x)
Definition: opentype.c:47
static unsigned __int64 next
Definition: rand_nt.c:6
FT_UShort * glyph_styles
Definition: afglobal.h:109
FT_Long glyph_count
Definition: afglobal.h:108
AF_WidthRec ref
Definition: aflatin.h:79
AF_WidthRec shoot
Definition: aflatin.h:80
AF_Style style
Definition: aftypes.h:448
AF_Blue_Stringset blue_stringset
Definition: aftypes.h:452
Definition: send.c:48

Referenced by af_latin_metrics_init().

◆ af_latin_metrics_init_widths()

af_latin_metrics_init_widths ( AF_LatinMetrics  metrics,
FT_Face  face 
)

Definition at line 59 of file aflatin.c.

61 {
62 /* scan the array of segments in each direction */
63#ifdef __REACTOS__
65 if (!hints) return;
66#else
68#endif
69
70 FT_TRACE5(( "\n"
71 "latin standard widths computation (style `%s')\n"
72 "=====================================================\n"
73 "\n",
74 af_style_names[metrics->root.style_class->style] ));
75
76 af_glyph_hints_init( hints, face->memory );
77
78 metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
79 metrics->axis[AF_DIMENSION_VERT].width_count = 0;
80
81 {
83 FT_ULong glyph_index;
84 int dim;
85#ifdef __REACTOS__
87 if (!dummy)
88 goto Exit;
89 {
90#else
92#endif
93 AF_Scaler scaler = &dummy->root.scaler;
94
95 AF_StyleClass style_class = metrics->root.style_class;
96 AF_ScriptClass script_class = af_script_classes[style_class->script];
97
98 /* If HarfBuzz is not available, we need a pointer to a single */
99 /* unsigned long value. */
100#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
101 void* shaper_buf;
102#else
103 FT_ULong shaper_buf_;
104 void* shaper_buf = &shaper_buf_;
105#endif
106
107 const char* p;
108
109#ifdef FT_DEBUG_LEVEL_TRACE
110 FT_ULong ch = 0;
111#endif
112
113
114 p = script_class->standard_charstring;
115
116#ifdef FT_CONFIG_OPTION_USE_HARFBUZZ
117 shaper_buf = af_shaper_buf_create( face );
118#endif
119 /*
120 * We check a list of standard characters to catch features like
121 * `c2sc' (small caps from caps) that don't contain lowercase letters
122 * by definition, or other features that mainly operate on numerals.
123 * The first match wins.
124 */
125
126 glyph_index = 0;
127 while ( *p )
128 {
129 unsigned int num_idx;
130
131#ifdef FT_DEBUG_LEVEL_TRACE
132 const char* p_old;
133#endif
134
135
136 while ( *p == ' ' )
137 p++;
138
139#ifdef FT_DEBUG_LEVEL_TRACE
140 p_old = p;
141 GET_UTF8_CHAR( ch, p_old );
142#endif
143
144 /* reject input that maps to more than a single glyph */
145 p = af_shaper_get_cluster( p, &metrics->root, shaper_buf, &num_idx );
146 if ( num_idx > 1 )
147 continue;
148
149 /* otherwise exit loop if we have a result */
150 glyph_index = af_shaper_get_elem( &metrics->root,
151 shaper_buf,
152 0,
153 NULL,
154 NULL );
155 if ( glyph_index )
156 break;
157 }
158
159 af_shaper_buf_destroy( face, shaper_buf );
160
161 if ( !glyph_index )
162 {
163 FT_TRACE5(( "standard character missing;"
164 " using fallback stem widths\n" ));
165 goto Exit;
166 }
167
168 FT_TRACE5(( "standard character: U+%04lX (glyph index %ld)\n",
169 ch, glyph_index ));
170
171 error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
172 if ( error || face->glyph->outline.n_points <= 0 )
173 goto Exit;
174
175 FT_ZERO( dummy );
176
177 dummy->units_per_em = metrics->units_per_em;
178
179 scaler->x_scale = 0x10000L;
180 scaler->y_scale = 0x10000L;
181 scaler->x_delta = 0;
182 scaler->y_delta = 0;
183
184 scaler->face = face;
186 scaler->flags = 0;
187
189
190 error = af_glyph_hints_reload( hints, &face->glyph->outline );
191 if ( error )
192 goto Exit;
193
194 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
195 {
196 AF_LatinAxis axis = &metrics->axis[dim];
197 AF_AxisHints axhints = &hints->axis[dim];
198 AF_Segment seg, limit, link;
199 FT_UInt num_widths = 0;
200
201
203 (AF_Dimension)dim );
204 if ( error )
205 goto Exit;
206
207 /*
208 * We assume that the glyphs selected for the stem width
209 * computation are `featureless' enough so that the linking
210 * algorithm works fine without adjustments of its scoring
211 * function.
212 */
214 0,
215 NULL,
216 (AF_Dimension)dim );
217
218 seg = axhints->segments;
219 limit = seg + axhints->num_segments;
220
221 for ( ; seg < limit; seg++ )
222 {
223 link = seg->link;
224
225 /* we only consider stem segments there! */
226 if ( link && link->link == seg && link > seg )
227 {
228 FT_Pos dist;
229
230
231 dist = seg->pos - link->pos;
232 if ( dist < 0 )
233 dist = -dist;
234
235 if ( num_widths < AF_LATIN_MAX_WIDTHS )
236 axis->widths[num_widths++].org = dist;
237 }
238 }
239
240 /* this also replaces multiple almost identical stem widths */
241 /* with a single one (the value 100 is heuristic) */
242 af_sort_and_quantize_widths( &num_widths, axis->widths,
243 dummy->units_per_em / 100 );
244 axis->width_count = num_widths;
245 }
246
247 Exit:
248 for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
249 {
250 AF_LatinAxis axis = &metrics->axis[dim];
251 FT_Pos stdw;
252
253
254 stdw = ( axis->width_count > 0 ) ? axis->widths[0].org
255 : AF_LATIN_CONSTANT( metrics, 50 );
256
257 /* let's try 20% of the smallest width */
258 axis->edge_distance_threshold = stdw / 5;
259 axis->standard_width = stdw;
260 axis->extra_light = 0;
261
262#ifdef FT_DEBUG_LEVEL_TRACE
263 {
264 FT_UInt i;
265
266
267 FT_TRACE5(( "%s widths:\n",
268 dim == AF_DIMENSION_VERT ? "horizontal"
269 : "vertical" ));
270
271 FT_TRACE5(( " %ld (standard)", axis->standard_width ));
272 for ( i = 1; i < axis->width_count; i++ )
273 FT_TRACE5(( " %ld", axis->widths[i].org ));
274
275 FT_TRACE5(( "\n" ));
276 }
277#endif
278 }
279#ifdef __REACTOS__
280 free(dummy);
281 }
282#endif
283 }
284
285 FT_TRACE5(( "\n" ));
286
288#ifdef __REACTOS__
289 free(hints);
290#endif
291 }
af_sort_and_quantize_widths(FT_UInt *count, AF_Width table, FT_Pos threshold)
Definition: afangles.c:210
af_glyph_hints_done(AF_GlyphHints hints)
Definition: afhints.c:702
af_glyph_hints_init(AF_GlyphHints hints, FT_Memory memory)
Definition: afhints.c:692
#define AF_LATIN_MAX_WIDTHS
Definition: aflatin.h:65
const WCHAR * link
Definition: db.cpp:998
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
WORD face[3]
Definition: mesh.c:4747
FT_Bool extra_light
Definition: aflatin.h:97
FT_Pos standard_width
Definition: aflatin.h:96
FT_UInt32 flags
Definition: aftypes.h:186
FT_Render_Mode render_mode
Definition: aftypes.h:185
FT_Pos y_delta
Definition: aftypes.h:184
FT_Face face
Definition: aftypes.h:180
FT_Pos x_delta
Definition: aftypes.h:183
FT_Fixed y_scale
Definition: aftypes.h:182
FT_Fixed x_scale
Definition: aftypes.h:181
const char * standard_charstring
Definition: aftypes.h:349

Referenced by af_latin_metrics_init().

◆ af_latin_metrics_scale()

af_latin_metrics_scale ( AF_LatinMetrics  metrics,
AF_Scaler  scaler 
)

Definition at line 1515 of file aflatin.c.

1517 {
1518 metrics->root.scaler.render_mode = scaler->render_mode;
1519 metrics->root.scaler.face = scaler->face;
1520 metrics->root.scaler.flags = scaler->flags;
1521
1524 }
static void af_latin_metrics_scale_dim(AF_LatinMetrics metrics, AF_Scaler scaler, AF_Dimension dim)
Definition: aflatin.c:1193

◆ af_latin_metrics_scale_dim()

static void af_latin_metrics_scale_dim ( AF_LatinMetrics  metrics,
AF_Scaler  scaler,
AF_Dimension  dim 
)
static

Definition at line 1193 of file aflatin.c.

1196 {
1198 FT_Pos delta;
1199 AF_LatinAxis axis;
1200 FT_UInt nn;
1201
1202
1203 if ( dim == AF_DIMENSION_HORZ )
1204 {
1205 scale = scaler->x_scale;
1206 delta = scaler->x_delta;
1207 }
1208 else
1209 {
1210 scale = scaler->y_scale;
1211 delta = scaler->y_delta;
1212 }
1213
1214 axis = &metrics->axis[dim];
1215
1216 if ( axis->org_scale == scale && axis->org_delta == delta )
1217 return;
1218
1219 axis->org_scale = scale;
1220 axis->org_delta = delta;
1221
1222 /*
1223 * correct X and Y scale to optimize the alignment of the top of small
1224 * letters to the pixel grid
1225 */
1226 {
1227 AF_LatinAxis Axis = &metrics->axis[AF_DIMENSION_VERT];
1229
1230
1231 for ( nn = 0; nn < Axis->blue_count; nn++ )
1232 {
1233 if ( Axis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT )
1234 {
1235 blue = &Axis->blues[nn];
1236 break;
1237 }
1238 }
1239
1240 if ( blue )
1241 {
1242 FT_Pos scaled;
1243 FT_Pos threshold;
1244 FT_Pos fitted;
1245 FT_UInt limit;
1246 FT_UInt ppem;
1247
1248
1249 scaled = FT_MulFix( blue->shoot.org, scale );
1250 ppem = metrics->root.scaler.face->size->metrics.x_ppem;
1251 limit = metrics->root.globals->increase_x_height;
1252 threshold = 40;
1253
1254 /* if the `increase-x-height' property is active, */
1255 /* we round up much more often */
1256 if ( limit &&
1257 ppem <= limit &&
1259 threshold = 52;
1260
1261 fitted = ( scaled + threshold ) & ~63;
1262
1263 if ( scaled != fitted )
1264 {
1265#if 0
1266 if ( dim == AF_DIMENSION_HORZ )
1267 {
1268 if ( fitted < scaled )
1269 scale -= scale / 50; /* scale *= 0.98 */
1270 }
1271 else
1272#endif
1273 if ( dim == AF_DIMENSION_VERT )
1274 {
1275 FT_Pos max_height;
1276 FT_Pos dist;
1277 FT_Fixed new_scale;
1278
1279
1280 new_scale = FT_MulDiv( scale, fitted, scaled );
1281
1282 /* the scaling should not change the result by more than two pixels */
1283 max_height = metrics->units_per_em;
1284
1285 for ( nn = 0; nn < Axis->blue_count; nn++ )
1286 {
1287 max_height = FT_MAX( max_height, Axis->blues[nn].ascender );
1288 max_height = FT_MAX( max_height, -Axis->blues[nn].descender );
1289 }
1290
1291 dist = FT_ABS( FT_MulFix( max_height, new_scale - scale ) );
1292 dist &= ~127;
1293
1294 if ( dist == 0 )
1295 {
1296 FT_TRACE5((
1297 "af_latin_metrics_scale_dim:"
1298 " x height alignment (style `%s'):\n"
1299 " "
1300 " vertical scaling changed from %.5f to %.5f (by %ld%%)\n"
1301 "\n",
1302 af_style_names[metrics->root.style_class->style],
1303 scale / 65536.0,
1304 new_scale / 65536.0,
1305 ( fitted - scaled ) * 100 / scaled ));
1306
1307 scale = new_scale;
1308 }
1309#ifdef FT_DEBUG_LEVEL_TRACE
1310 else
1311 {
1312 FT_TRACE5((
1313 "af_latin_metrics_scale_dim:"
1314 " x height alignment (style `%s'):\n"
1315 " "
1316 " excessive vertical scaling abandoned\n"
1317 "\n",
1318 af_style_names[metrics->root.style_class->style] ));
1319 }
1320#endif
1321 }
1322 }
1323 }
1324 }
1325
1326 axis->scale = scale;
1327 axis->delta = delta;
1328
1329 if ( dim == AF_DIMENSION_HORZ )
1330 {
1331 metrics->root.scaler.x_scale = scale;
1332 metrics->root.scaler.x_delta = delta;
1333 }
1334 else
1335 {
1336 metrics->root.scaler.y_scale = scale;
1337 metrics->root.scaler.y_delta = delta;
1338 }
1339
1340 FT_TRACE5(( "%s widths (style `%s')\n",
1341 dim == AF_DIMENSION_HORZ ? "horizontal" : "vertical",
1342 af_style_names[metrics->root.style_class->style] ));
1343
1344 /* scale the widths */
1345 for ( nn = 0; nn < axis->width_count; nn++ )
1346 {
1347 AF_Width width = axis->widths + nn;
1348
1349
1350 width->cur = FT_MulFix( width->org, scale );
1351 width->fit = width->cur;
1352
1353 FT_TRACE5(( " %ld scaled to %.2f\n",
1354 width->org,
1355 width->cur / 64.0 ));
1356 }
1357
1358 FT_TRACE5(( "\n" ));
1359
1360 /* an extra-light axis corresponds to a standard width that is */
1361 /* smaller than 5/8 pixels */
1362 axis->extra_light =
1363 FT_BOOL( FT_MulFix( axis->standard_width, scale ) < 32 + 8 );
1364
1365#ifdef FT_DEBUG_LEVEL_TRACE
1366 if ( axis->extra_light )
1367 FT_TRACE5(( "`%s' style is extra light (at current resolution)\n"
1368 "\n",
1369 af_style_names[metrics->root.style_class->style] ));
1370#endif
1371
1372 if ( dim == AF_DIMENSION_VERT )
1373 {
1374#ifdef FT_DEBUG_LEVEL_TRACE
1375 if ( axis->blue_count )
1376 FT_TRACE5(( "blue zones (style `%s')\n",
1377 af_style_names[metrics->root.style_class->style] ));
1378#endif
1379
1380 /* scale the blue zones */
1381 for ( nn = 0; nn < axis->blue_count; nn++ )
1382 {
1383 AF_LatinBlue blue = &axis->blues[nn];
1384 FT_Pos dist;
1385
1386
1387 blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta;
1388 blue->ref.fit = blue->ref.cur;
1389 blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
1390 blue->shoot.fit = blue->shoot.cur;
1391 blue->flags &= ~AF_LATIN_BLUE_ACTIVE;
1392
1393 /* a blue zone is only active if it is less than 3/4 pixels tall */
1394 dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
1395 if ( dist <= 48 && dist >= -48 )
1396 {
1397#if 0
1398 FT_Pos delta1;
1399#endif
1400 FT_Pos delta2;
1401
1402
1403 /* use discrete values for blue zone widths */
1404
1405#if 0
1406
1407 /* generic, original code */
1408 delta1 = blue->shoot.org - blue->ref.org;
1409 delta2 = delta1;
1410 if ( delta1 < 0 )
1411 delta2 = -delta2;
1412
1413 delta2 = FT_MulFix( delta2, scale );
1414
1415 if ( delta2 < 32 )
1416 delta2 = 0;
1417 else if ( delta2 < 64 )
1418 delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 );
1419 else
1420 delta2 = FT_PIX_ROUND( delta2 );
1421
1422 if ( delta1 < 0 )
1423 delta2 = -delta2;
1424
1425 blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
1426 blue->shoot.fit = blue->ref.fit + delta2;
1427
1428#else
1429
1430 /* simplified version due to abs(dist) <= 48 */
1431 delta2 = dist;
1432 if ( dist < 0 )
1433 delta2 = -delta2;
1434
1435 if ( delta2 < 32 )
1436 delta2 = 0;
1437 else if ( delta2 < 48 )
1438 delta2 = 32;
1439 else
1440 delta2 = 64;
1441
1442 if ( dist < 0 )
1443 delta2 = -delta2;
1444
1445 blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
1446 blue->shoot.fit = blue->ref.fit - delta2;
1447
1448#endif
1449
1450 blue->flags |= AF_LATIN_BLUE_ACTIVE;
1451 }
1452 }
1453
1454 /* use sub-top blue zone only if it doesn't overlap with */
1455 /* another (non-sup-top) blue zone; otherwise, the */
1456 /* effect would be similar to a neutral blue zone, which */
1457 /* is not desired here */
1458 for ( nn = 0; nn < axis->blue_count; nn++ )
1459 {
1460 AF_LatinBlue blue = &axis->blues[nn];
1461 FT_UInt i;
1462
1463
1464 if ( !( blue->flags & AF_LATIN_BLUE_SUB_TOP ) )
1465 continue;
1466 if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
1467 continue;
1468
1469 for ( i = 0; i < axis->blue_count; i++ )
1470 {
1471 AF_LatinBlue b = &axis->blues[i];
1472
1473
1474 if ( b->flags & AF_LATIN_BLUE_SUB_TOP )
1475 continue;
1476 if ( !( b->flags & AF_LATIN_BLUE_ACTIVE ) )
1477 continue;
1478
1479 if ( b->ref.fit <= blue->shoot.fit &&
1480 b->shoot.fit >= blue->ref.fit )
1481 {
1482 blue->flags &= ~AF_LATIN_BLUE_ACTIVE;
1483 break;
1484 }
1485 }
1486 }
1487
1488#ifdef FT_DEBUG_LEVEL_TRACE
1489 for ( nn = 0; nn < axis->blue_count; nn++ )
1490 {
1491 AF_LatinBlue blue = &axis->blues[nn];
1492
1493
1494 FT_TRACE5(( " reference %d: %ld scaled to %.2f%s\n"
1495 " overshoot %d: %ld scaled to %.2f%s\n",
1496 nn,
1497 blue->ref.org,
1498 blue->ref.fit / 64.0,
1499 ( blue->flags & AF_LATIN_BLUE_ACTIVE ) ? ""
1500 : " (inactive)",
1501 nn,
1502 blue->shoot.org,
1503 blue->shoot.fit / 64.0,
1504 ( blue->flags & AF_LATIN_BLUE_ACTIVE ) ? ""
1505 : " (inactive)" ));
1506 }
1507#endif
1508 }
1509 }
#define AF_PROP_INCREASE_X_HEIGHT_MIN
Definition: afglobal.h:87
FT_Pos delta
Definition: aflatin.h:91
FT_Pos org_delta
Definition: aflatin.h:104
FT_Fixed org_scale
Definition: aflatin.h:103
FT_UInt flags
Definition: aflatin.h:83
FT_Pos descender
Definition: aflatin.h:82
FT_Pos ascender
Definition: aflatin.h:81

Referenced by af_latin_metrics_scale().

◆ af_latin_snap_width()

static FT_Pos af_latin_snap_width ( AF_Width  widths,
FT_UInt  count,
FT_Pos  width 
)
static

Definition at line 2699 of file aflatin.c.

2702 {
2703 FT_UInt n;
2704 FT_Pos best = 64 + 32 + 2;
2706 FT_Pos scaled;
2707
2708
2709 for ( n = 0; n < count; n++ )
2710 {
2711 FT_Pos w;
2712 FT_Pos dist;
2713
2714
2715 w = widths[n].cur;
2716 dist = width - w;
2717 if ( dist < 0 )
2718 dist = -dist;
2719 if ( dist < best )
2720 {
2721 best = dist;
2722 reference = w;
2723 }
2724 }
2725
2726 scaled = FT_PIX_ROUND( reference );
2727
2728 if ( width >= reference )
2729 {
2730 if ( width < scaled + 48 )
2731 width = reference;
2732 }
2733 else
2734 {
2735 if ( width > scaled - 48 )
2736 width = reference;
2737 }
2738
2739 return width;
2740 }
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLdouble n
Definition: glext.h:7729
GLint reference
Definition: glext.h:11729
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:6102

Referenced by af_latin_compute_stem_width().

◆ af_latin_sort_blue()

static void af_latin_sort_blue ( FT_UInt  count,
AF_LatinBlue table 
)
static

Definition at line 295 of file aflatin.c.

297 {
298 FT_UInt i, j;
300
301
302 /* we sort from bottom to top */
303 for ( i = 1; i < count; i++ )
304 {
305 for ( j = i; j > 0; j-- )
306 {
307 FT_Pos a, b;
308
309
310 if ( table[j - 1]->flags & ( AF_LATIN_BLUE_TOP |
312 a = table[j - 1]->ref.org;
313 else
314 a = table[j - 1]->shoot.org;
315
316 if ( table[j]->flags & ( AF_LATIN_BLUE_TOP |
318 b = table[j]->ref.org;
319 else
320 b = table[j]->shoot.org;
321
322 if ( b >= a )
323 break;
324
325 swap = table[j];
326 table[j] = table[j - 1];
327 table[j - 1] = swap;
328 }
329 }
330 }
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define swap(a, b)
Definition: qsort.c:63

Referenced by af_latin_metrics_init_blues().