1 /***************************************************************************/
5 /* Routines used to load and analyze a given glyph before hinting */
8 /* Copyright 2000 Catharon Productions Inc. */
9 /* Author: David Turner */
11 /* This file is part of the Catharon Typography Project and shall only */
12 /* be used, modified, and distributed under the terms of the Catharon */
13 /* Open Source License that should come with this file under the name */
14 /* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
15 /* this file you indicate that you have read the license and */
16 /* understand and accept it fully. */
18 /* Note that this license is compatible with the FreeType license. */
20 /***************************************************************************/
23 #ifdef FT_FLAT_COMPILE
31 #include <autohint/ahglyph.h>
32 #include <autohint/ahangles.h>
33 #include <autohint/ahglobal.h>
41 #define xxxAH_DEBUG_GLYPH
44 /* compute the direction value of a given vector.. */
46 AH_Direction
ah_compute_direction( FT_Pos dx
,
50 FT_Pos ax
= ABS( dx
);
51 FT_Pos ay
= ABS( dy
);
56 /* test for vertical direction */
59 dir
= dy
> 0 ? ah_dir_up
: ah_dir_down
;
61 /* test for horizontal direction */
62 else if ( ay
* 12 < ax
)
64 dir
= dx
> 0 ? ah_dir_right
: ah_dir_left
;
71 /*************************************************************************/
77 /* Creates a new and empty AH_Outline object. */
80 FT_Error
ah_outline_new( FT_Memory memory
,
81 AH_Outline
** aoutline
)
87 if ( !ALLOC( outline
, sizeof ( *outline
) ) )
89 outline
->memory
= memory
;
97 /*************************************************************************/
100 /* ah_outline_done */
103 /* Destroys a given AH_Outline object. */
106 void ah_outline_done( AH_Outline
* outline
)
108 FT_Memory memory
= outline
->memory
;
111 FREE( outline
->horz_edges
);
112 FREE( outline
->horz_segments
);
113 FREE( outline
->contours
);
114 FREE( outline
->points
);
120 /*************************************************************************/
123 /* ah_outline_save */
126 /* Saves the content of a given AH_Outline object into a face's glyph */
130 void ah_outline_save( AH_Outline
* outline
,
133 AH_Point
* point
= outline
->points
;
134 AH_Point
* limit
= point
+ outline
->num_points
;
135 FT_Vector
* vec
= gloader
->current
.outline
.points
;
136 char* tag
= gloader
->current
.outline
.tags
;
139 /* we assume that the glyph loader has already been checked for storage */
140 for ( ; point
< limit
; point
++, vec
++, tag
++ )
145 if ( point
->flags
& ah_flah_conic
)
146 tag
[0] = FT_Curve_Tag_Conic
;
147 else if ( point
->flags
& ah_flah_cubic
)
148 tag
[0] = FT_Curve_Tag_Cubic
;
150 tag
[0] = FT_Curve_Tag_On
;
155 /*************************************************************************/
158 /* ah_outline_load */
161 /* Loads an unscaled outline from a glyph slot into an AH_Outline */
165 FT_Error
ah_outline_load( AH_Outline
* outline
,
168 FT_Memory memory
= outline
->memory
;
169 FT_Error error
= FT_Err_Ok
;
170 FT_Outline
* source
= &face
->glyph
->outline
;
171 FT_Int num_points
= source
->n_points
;
172 FT_Int num_contours
= source
->n_contours
;
176 /* check arguments */
179 face
->glyph
->format
!= ft_glyph_format_outline
)
180 return FT_Err_Invalid_Argument
;
182 /* first of all, reallocate the contours array if necessary */
183 if ( num_contours
> outline
->max_contours
)
185 FT_Int new_contours
= ( num_contours
+ 3 ) & -4;
188 if ( REALLOC_ARRAY( outline
->contours
, outline
->max_contours
,
189 new_contours
, AH_Point
* ) )
192 outline
->max_contours
= new_contours
;
195 /* then, realloc the points, segments & edges arrays if needed */
196 if ( num_points
> outline
->max_points
)
198 FT_Int news
= ( num_points
+ 7 ) & -8;
199 FT_Int max
= outline
->max_points
;
202 if ( REALLOC_ARRAY( outline
->points
, max
, news
, AH_Point
) ||
203 REALLOC_ARRAY( outline
->horz_edges
, max
, news
, AH_Edge
) ||
204 REALLOC_ARRAY( outline
->horz_segments
, max
, news
, AH_Segment
) )
207 /* readjust some pointers */
208 outline
->vert_edges
= outline
->horz_edges
+ ( news
>> 1 );
209 outline
->vert_segments
= outline
->horz_segments
+ ( news
>> 1 );
210 outline
->max_points
= news
;
213 outline
->num_points
= num_points
;
214 outline
->num_contours
= num_contours
;
216 outline
->num_hedges
= 0;
217 outline
->num_vedges
= 0;
218 outline
->num_hsegments
= 0;
219 outline
->num_vsegments
= 0;
221 /* Compute the vertical and horizontal major directions; this is */
222 /* currently done by inspecting the `ft_outline_reverse_fill' flag. */
223 /* However, some fonts have improper glyphs, and it'd be a good idea */
224 /* to be able to re-compute these values on the fly. */
225 outline
->vert_major_dir
= ah_dir_up
;
226 outline
->horz_major_dir
= ah_dir_left
;
228 if ( source
->flags
& ft_outline_reverse_fill
)
230 outline
->vert_major_dir
= ah_dir_down
;
231 outline
->horz_major_dir
= ah_dir_right
;
234 outline
->x_scale
= face
->size
->metrics
.x_scale
;
235 outline
->y_scale
= face
->size
->metrics
.y_scale
;
237 points
= outline
->points
;
240 /* do one thing at a time -- it is easier to understand, and */
241 /* the code is clearer */
242 AH_Point
* point
= points
;
243 AH_Point
* limit
= point
+ outline
->num_points
;
246 /* compute coordinates */
248 FT_Vector
* vec
= source
->points
;
249 FT_Fixed x_scale
= outline
->x_scale
;
250 FT_Fixed y_scale
= outline
->y_scale
;
253 for (; point
< limit
; vec
++, point
++ )
257 point
->ox
= point
->x
= FT_MulFix( vec
->x
, x_scale
);
258 point
->oy
= point
->y
= FT_MulFix( vec
->y
, y_scale
);
264 /* compute Bezier flags */
266 char* tag
= source
->tags
;
269 for ( point
= points
; point
< limit
; point
++, tag
++ )
271 switch ( FT_CURVE_TAG( *tag
) )
273 case FT_Curve_Tag_Conic
:
274 point
->flags
= ah_flah_conic
; break;
275 case FT_Curve_Tag_Cubic
:
276 point
->flags
= ah_flah_cubic
; break;
283 /* compute `next' and `prev' */
285 FT_Int contour_index
;
294 end
= points
+ source
->contours
[0];
297 for ( point
= points
; point
< limit
; point
++ )
302 point
->next
= point
+ 1;
309 if ( point
+ 1 < limit
)
311 end
= points
+ source
->contours
[contour_index
];
319 /* set-up the contours array */
321 AH_Point
** contour
= outline
->contours
;
322 AH_Point
** limit
= contour
+ outline
->num_contours
;
323 short* end
= source
->contours
;
327 for ( ; contour
< limit
; contour
++, end
++ )
329 contour
[0] = points
+ index
;
334 /* compute directions of in & out vectors */
336 for ( point
= points
; point
< limit
; point
++ )
344 vec
.x
= point
->fx
- prev
->fx
;
345 vec
.y
= point
->fy
- prev
->fy
;
347 point
->in_dir
= ah_compute_direction( vec
.x
, vec
.y
);
349 #ifndef AH_OPTION_NO_WEAK_INTERPOLATION
350 point
->in_angle
= ah_angle( &vec
);
354 vec
.x
= next
->fx
- point
->fx
;
355 vec
.y
= next
->fy
- point
->fy
;
357 point
->out_dir
= ah_compute_direction( vec
.x
, vec
.y
);
359 #ifndef AH_OPTION_NO_WEAK_INTERPOLATION
360 point
->out_angle
= ah_angle( &vec
);
363 AH_Angle delta
= point
->in_angle
- point
->out_angle
;
369 point
->flags
|= ah_flah_weak_interpolation
;
373 if ( point
->flags
& ( ah_flah_conic
| ah_flah_cubic
) )
374 point
->flags
|= ah_flah_weak_interpolation
;
377 #endif /* !AH_OPTION_NO_WEAK_INTERPOLATION */
379 #ifdef AH_OPTION_NO_STRONG_INTERPOLATION
380 point
->flags
|= ah_flah_weak_interpolation
;
392 void ah_setup_uv( AH_Outline
* outline
,
395 AH_Point
* point
= outline
->points
;
396 AH_Point
* limit
= point
+ outline
->num_points
;
399 for ( ; point
< limit
; point
++ )
446 void ah_outline_compute_segments( AH_Outline
* outline
)
449 AH_Segment
* segments
;
450 FT_Int
* p_num_segments
;
451 AH_Direction segment_dir
;
452 AH_Direction major_dir
;
455 segments
= outline
->horz_segments
;
456 p_num_segments
= &outline
->num_hsegments
;
457 major_dir
= ah_dir_right
; /* This value must be positive! */
458 segment_dir
= major_dir
;
460 /* set up (u,v) in each point */
461 ah_setup_uv( outline
, ah_uv_fyx
);
463 for ( dimension
= 1; dimension
>= 0; dimension
-- )
465 AH_Point
** contour
= outline
->contours
;
466 AH_Point
** contour_limit
= contour
+ outline
->num_contours
;
467 AH_Segment
* segment
= segments
;
468 FT_Int num_segments
= 0;
470 #ifdef AH_HINT_METRICS
471 AH_Point
* min_point
= 0;
472 AH_Point
* max_point
= 0;
473 FT_Pos min_coord
= 32000;
474 FT_Pos max_coord
= -32000;
478 /* do each contour separately */
479 for ( ; contour
< contour_limit
; contour
++ )
481 AH_Point
* point
= contour
[0];
482 AH_Point
* last
= point
->prev
;
484 FT_Pos min_pos
= +32000; /* minimum segment pos != min_coord */
485 FT_Pos max_pos
= -32000; /* maximum segment pos != max_coord */
489 #ifdef AH_HINT_METRICS
490 if ( point
->u
< min_coord
)
492 min_coord
= point
->u
;
495 if ( point
->u
> max_coord
)
497 max_coord
= point
->u
;
502 if ( point
== last
) /* skip singletons -- just in case? */
505 if ( ABS( last
->out_dir
) == major_dir
&&
506 ABS( point
->out_dir
) == major_dir
)
508 /* we are already on an edge, try to locate its start */
514 if ( ABS( point
->out_dir
) != major_dir
)
541 if ( point
->out_dir
!= segment_dir
|| point
== last
)
543 /* we are just leaving an edge; record a new segment! */
544 segment
->last
= point
;
545 segment
->pos
= ( min_pos
+ max_pos
) >> 1;
547 /* a segment is round if either its first or last point */
548 /* is a control point */
549 if ( ( segment
->first
->flags
| point
->flags
) &
551 segment
->flags
|= ah_edge_round
;
553 /* compute segment size */
554 min_pos
= max_pos
= point
->v
;
556 v
= segment
->first
->v
;
562 segment
->min_coord
= min_pos
;
563 segment
->max_coord
= max_pos
;
572 /* now exit if we are at the start/end point */
580 if ( !on_edge
&& ABS( point
->out_dir
) == major_dir
)
582 /* this is the start of a new segment! */
583 segment_dir
= point
->out_dir
;
585 /* clear all segment fields */
586 memset( segment
, 0, sizeof ( *segment
) );
588 segment
->dir
= segment_dir
;
589 segment
->flags
= ah_edge_normal
;
590 min_pos
= max_pos
= point
->u
;
591 segment
->first
= point
;
592 segment
->last
= point
;
593 segment
->contour
= contour
;
596 if ( point
== max_point
)
599 if ( point
== min_point
)
608 #ifdef AH_HINT_METRICS
609 /* we need to ensure that there are edges on the left-most and */
610 /* right-most points of the glyph in order to hint the metrics; */
611 /* we do this by inserting fake segments when needed */
612 if ( dimension
== 0 )
614 AH_Point
* point
= outline
->points
;
615 AH_Point
* limit
= point
+ outline
->num_points
;
617 AH_Point
* min_point
= 0;
618 AH_Point
* max_point
= 0;
619 FT_Pos min_pos
= 32000;
620 FT_Pos max_pos
= -32000;
623 /* compute minimum and maximum points */
624 for ( ; point
< limit
; point
++ )
626 FT_Pos x
= point
->fx
;
641 /* insert minimum segment */
644 /* clear all segment fields */
645 memset( segment
, 0, sizeof ( *segment
) );
647 segment
->dir
= segment_dir
;
648 segment
->flags
= ah_edge_normal
;
649 segment
->first
= min_point
;
650 segment
->last
= min_point
;
651 segment
->pos
= min_pos
;
657 /* insert maximum segment */
660 /* clear all segment fields */
661 memset( segment
, 0, sizeof ( *segment
) );
663 segment
->dir
= segment_dir
;
664 segment
->flags
= ah_edge_normal
;
665 segment
->first
= max_point
;
666 segment
->last
= max_point
;
667 segment
->pos
= max_pos
;
673 #endif /* AH_HINT_METRICS */
675 *p_num_segments
= num_segments
;
677 segments
= outline
->vert_segments
;
678 major_dir
= ah_dir_up
;
679 p_num_segments
= &outline
->num_vsegments
;
680 ah_setup_uv( outline
, ah_uv_fxy
);
686 void ah_outline_link_segments( AH_Outline
* outline
)
688 AH_Segment
* segments
;
693 ah_setup_uv( outline
, ah_uv_fyx
);
695 segments
= outline
->horz_segments
;
696 limit
= segments
+ outline
->num_hsegments
;
698 for ( dimension
= 1; dimension
>= 0; dimension
-- )
704 /* now compare each segment to the others */
705 for ( seg1
= segments
; seg1
< limit
; seg1
++ )
707 FT_Pos best_score
= 32000;
708 AH_Segment
* best_segment
= 0;
711 /* the fake segments are introduced to hint the metrics -- */
712 /* we must never link them to anything */
713 if ( seg1
->first
== seg1
->last
)
716 for ( seg2
= segments
; seg2
< limit
; seg2
++ )
717 if ( seg1
!= seg2
&& seg1
->dir
+ seg2
->dir
== 0 )
719 FT_Pos pos1
= seg1
->pos
;
720 FT_Pos pos2
= seg2
->pos
;
725 /* check that the segments are correctly oriented and */
726 /* positioned to form a black distance */
728 is_dir
= ( seg1
->dir
== outline
->horz_major_dir
||
729 seg1
->dir
== outline
->vert_major_dir
);
730 is_pos
= pos1
> pos2
;
732 if ( pos1
== pos2
|| !(is_dir
^ is_pos
) )
735 /* Check the two segments. We now have a better algorithm */
736 /* that doesn't rely on the segment points themselves but */
737 /* on their relative position. This gets rids of many */
738 /* unpleasant artefacts and incorrect stem/serifs */
741 /* first of all, compute the size of the `common' height */
743 FT_Pos min
= seg1
->min_coord
;
744 FT_Pos max
= seg1
->max_coord
;
750 size2
= seg2
->max_coord
- seg2
->min_coord
;
752 if ( min
< seg2
->min_coord
)
753 min
= seg2
->min_coord
;
755 if ( max
< seg2
->max_coord
)
756 max
= seg2
->max_coord
;
759 score
= seg2
->pos
- seg1
->pos
;
763 /* before comparing the scores, take care that the segments */
764 /* are really facing each other (often not for italics..) */
765 if ( 4 * len
>= size1
&& 4 * len
>= size2
)
766 if ( score
< best_score
)
776 seg1
->link
= best_segment
;
777 seg1
->score
= best_score
;
779 best_segment
->num_linked
++;
785 /* now, compute the `serif' segments */
786 for ( seg1
= segments
; seg1
< limit
; seg1
++ )
790 if ( seg2
&& seg2
->link
!= seg1
)
793 seg1
->serif
= seg2
->link
;
797 ah_setup_uv( outline
, ah_uv_fxy
);
799 segments
= outline
->vert_segments
;
800 limit
= segments
+ outline
->num_vsegments
;
805 #ifdef AH_DEBUG_GLYPH
807 /* A function used to dump the array of linked segments */
808 void ah_dump_segments( AH_Outline
* outline
)
810 AH_Segment
* segments
;
816 points
= outline
->points
;
817 segments
= outline
->horz_segments
;
818 limit
= segments
+ outline
->num_hsegments
;
820 for ( dimension
= 1; dimension
>= 0; dimension
-- )
825 printf ( "Table of %s segments:\n",
826 !dimension
? "vertical" : "horizontal" );
827 printf ( " [ index | pos | dir | link | serif |"
828 " numl | first | start ]\n" );
830 for ( seg
= segments
; seg
< limit
; seg
++ )
832 printf ( " [ %5d | %4d | %5s | %4d | %5d | %4d | %5d | %5d ]\n",
835 seg
->dir
== ah_dir_up
837 : ( seg
->dir
== ah_dir_down
839 : ( seg
->dir
== ah_dir_left
841 : ( seg
->dir
== ah_dir_right
844 seg
->link
? (seg
->link
-segments
) : -1,
845 seg
->serif
? (seg
->serif
-segments
) : -1,
846 (int)seg
->num_linked
,
848 seg
->last
- points
);
851 segments
= outline
->vert_segments
;
852 limit
= segments
+ outline
->num_vsegments
;
856 #endif /* AH_DEBUG_GLYPH */
860 void ah_outline_compute_edges( AH_Outline
* outline
)
863 AH_Segment
* segments
;
864 AH_Segment
* segment_limit
;
869 FT_Pos edge_distance_threshold
;
872 edges
= outline
->horz_edges
;
873 segments
= outline
->horz_segments
;
874 segment_limit
= segments
+ outline
->num_hsegments
;
875 p_num_edges
= &outline
->num_hedges
;
876 up_dir
= ah_dir_right
;
877 scale
= outline
->y_scale
;
879 for ( dimension
= 1; dimension
>= 0; dimension
-- )
882 AH_Edge
* edge_limit
; /* really == edge + num_edges */
886 /*********************************************************************/
888 /* We will begin by generating a sorted table of edges for the */
889 /* current direction. To do so, we simply scan each segment and try */
890 /* to find an edge in our table that corresponds to its position. */
892 /* If no edge is found, we create and insert a new edge in the */
893 /* sorted table. Otherwise, we simply add the segment to the edge's */
894 /* list which will be processed in the second step to compute the */
895 /* edge's properties. */
897 /* Note that the edges table is sorted along the segment/edge */
900 /*********************************************************************/
902 edge_distance_threshold
= FT_MulFix( outline
->edge_distance_threshold
,
904 if ( edge_distance_threshold
> 64 / 4 )
905 edge_distance_threshold
= 64 / 4;
908 for ( seg
= segments
; seg
< segment_limit
; seg
++ )
913 /* look for an edge corresponding to the segment */
914 for ( edge
= edges
; edge
< edge_limit
; edge
++ )
919 dist
= seg
->pos
- edge
->fpos
;
923 dist
= FT_MulFix( dist
, scale
);
924 if ( dist
< edge_distance_threshold
)
933 /* insert a new edge in the list and */
934 /* sort according to the position */
935 while ( edge
> edges
&& edge
[-1].fpos
> seg
->pos
)
942 /* clear all edge fields */
943 memset( edge
, 0, sizeof ( *edge
) );
945 /* add the segment to the new edge's list */
948 edge
->fpos
= seg
->pos
;
949 edge
->opos
= edge
->pos
= FT_MulFix( seg
->pos
, scale
);
950 seg
->edge_next
= seg
;
954 /* if an edge was found, simply add the segment to the edge's */
956 seg
->edge_next
= edge
->first
;
957 edge
->last
->edge_next
= seg
;
962 *p_num_edges
= edge_limit
- edges
;
965 /*********************************************************************/
967 /* Good, we will now compute each edge's properties according to */
968 /* segments found on its position. Basically, these are: */
970 /* - edge's main direction */
971 /* - stem edge, serif edge or both (which defaults to stem then) */
972 /* - rounded edge, straigth or both (which defaults to straight) */
973 /* - link for edge */
975 /*********************************************************************/
977 /* first of all, set the `edge' field in each segment -- this is */
978 /* required in order to compute edge links */
979 for ( edge
= edges
; edge
< edge_limit
; edge
++ )
986 seg
= seg
->edge_next
;
988 while ( seg
!= edge
->first
);
991 /* now, compute each edge properties */
992 for ( edge
= edges
; edge
< edge_limit
; edge
++ )
994 int is_round
= 0; /* does it contain round segments? */
995 int is_straight
= 0; /* does it contain straight segments? */
996 int ups
= 0; /* number of upwards segments */
997 int downs
= 0; /* number of downwards segments */
1007 /* check for roundness of segment */
1008 if ( seg
->flags
& ah_edge_round
)
1013 /* check for segment direction */
1014 if ( seg
->dir
== up_dir
)
1015 ups
+= seg
->max_coord
-seg
->min_coord
;
1017 downs
+= seg
->max_coord
-seg
->min_coord
;
1019 /* check for links -- if seg->serif is set, then seg->link must */
1021 is_serif
= seg
->serif
&& seg
->serif
->edge
!= edge
;
1023 if ( seg
->link
|| is_serif
)
1035 edge2
= edge
->serif
;
1044 edge_delta
= edge
->fpos
- edge2
->fpos
;
1045 if ( edge_delta
< 0 )
1046 edge_delta
= -edge_delta
;
1048 seg_delta
= seg
->pos
- seg2
->pos
;
1049 if ( seg_delta
< 0 )
1050 seg_delta
= -seg_delta
;
1052 if ( seg_delta
< edge_delta
)
1059 edge
->serif
= edge2
;
1064 seg
= seg
->edge_next
;
1066 } while ( seg
!= edge
->first
);
1068 /* set the round/straight flags */
1069 edge
->flags
= ah_edge_normal
;
1071 if ( is_straight
== 0 && is_round
)
1072 edge
->flags
|= ah_edge_round
;
1074 /* set the edge's main direction */
1075 edge
->dir
= ah_dir_none
;
1080 else if ( ups
< downs
)
1081 edge
->dir
= - up_dir
;
1083 else if ( ups
== downs
)
1084 edge
->dir
= 0; /* both up and down !! */
1086 /* gets rid of serifs if link is set */
1087 /* XXX: This gets rid of many unpleasant artefacts! */
1088 /* Example: the `c' in cour.pfa at size 13 */
1090 if ( edge
->serif
&& edge
->link
)
1094 edges
= outline
->vert_edges
;
1095 segments
= outline
->vert_segments
;
1096 segment_limit
= segments
+ outline
->num_vsegments
;
1097 p_num_edges
= &outline
->num_vedges
;
1099 scale
= outline
->x_scale
;
1104 /*************************************************************************/
1107 /* ah_outline_detect_features */
1110 /* Performs feature detection on a given AH_Outline object. */
1113 void ah_outline_detect_features( AH_Outline
* outline
)
1115 ah_outline_compute_segments( outline
);
1116 ah_outline_link_segments ( outline
);
1117 ah_outline_compute_edges ( outline
);
1121 /*************************************************************************/
1124 /* ah_outline_compute_blue_edges */
1127 /* Computes the `blue edges' in a given outline (i.e. those that must */
1128 /* be snapped to a blue zone edge (top or bottom). */
1131 void ah_outline_compute_blue_edges( AH_Outline
* outline
,
1132 AH_Face_Globals
* face_globals
)
1134 AH_Edge
* edge
= outline
->horz_edges
;
1135 AH_Edge
* limit
= edge
+ outline
->num_hedges
;
1136 AH_Globals
* globals
= &face_globals
->design
;
1137 FT_Fixed y_scale
= outline
->y_scale
;
1140 /* compute for each horizontal edge, which blue zone is closer */
1141 for ( ; edge
< limit
; edge
++ )
1144 FT_Pos
* best_blue
= 0;
1145 FT_Pos best_dist
; /* initial threshold */
1148 /* compute the initial threshold as a fraction of the EM size */
1149 best_dist
= FT_MulFix( face_globals
->face
->units_per_EM
/ 40, y_scale
);
1150 if ( best_dist
> 64 / 4 )
1153 for ( blue
= ah_blue_capital_top
; blue
< ah_blue_max
; blue
++ )
1155 /* if it is a top zone, check for right edges -- if it is a bottom */
1156 /* zone, check for left edges */
1158 /* of course, that's for TrueType XXX */
1159 FT_Bool is_top_blue
= AH_IS_TOP_BLUE( blue
);
1160 FT_Bool is_major_dir
= edge
->dir
== outline
->horz_major_dir
;
1163 /* if it is a top zone, the edge must be against the major */
1164 /* direction; if it is a bottom zone, it must be in the major */
1166 if ( is_top_blue
^ is_major_dir
)
1169 FT_Pos
* blue_pos
= globals
->blue_refs
+ blue
;
1172 /* first of all, compare it to the reference position */
1173 dist
= edge
->fpos
- *blue_pos
;
1177 dist
= FT_MulFix( dist
, y_scale
);
1178 if ( dist
< best_dist
)
1181 best_blue
= blue_pos
;
1184 /* now, compare it to the overshoot position if the edge is */
1185 /* rounded, and if the edge is over the reference position of a */
1186 /* top zone, or under the reference position of a bottom zone */
1187 if ( edge
->flags
& ah_edge_round
&& dist
!= 0 )
1189 FT_Bool is_under_ref
= edge
->fpos
< *blue_pos
;
1192 if ( is_top_blue
^ is_under_ref
)
1194 blue_pos
= globals
->blue_shoots
+ blue
;
1195 dist
= edge
->fpos
- *blue_pos
;
1199 dist
= FT_MulFix( dist
, y_scale
);
1200 if ( dist
< best_dist
)
1203 best_blue
= blue_pos
;
1211 edge
->blue_edge
= best_blue
;
1216 /*************************************************************************/
1219 /* ah_outline_scale_blue_edges */
1222 /* This functions must be called before hinting in order to re-adjust */
1223 /* the contents of the detected edges (basically change the `blue */
1224 /* edge' pointer from `design units' to `scaled ones'). */
1227 void ah_outline_scale_blue_edges( AH_Outline
* outline
,
1228 AH_Face_Globals
* globals
)
1230 AH_Edge
* edge
= outline
->horz_edges
;
1231 AH_Edge
* limit
= edge
+ outline
->num_hedges
;
1235 delta
= globals
->scaled
.blue_refs
- globals
->design
.blue_refs
;
1237 for ( ; edge
< limit
; edge
++ )
1239 if ( edge
->blue_edge
)
1240 edge
->blue_edge
+= delta
;
1245 #ifdef AH_DEBUG_GLYPH
1247 void ah_dump_edges( AH_Outline
* outline
)
1251 AH_Segment
* segments
;
1255 edges
= outline
->horz_edges
;
1256 limit
= edges
+ outline
->num_hedges
;
1257 segments
= outline
->horz_segments
;
1259 for ( dimension
= 1; dimension
>= 0; dimension
-- )
1264 printf ( "Table of %s edges:\n",
1265 !dimension
? "vertical" : "horizontal" );
1266 printf ( " [ index | pos | dir | link |"
1267 " serif | blue | opos | pos ]\n" );
1269 for ( edge
= edges
; edge
< limit
; edge
++ )
1271 printf ( " [ %5d | %4d | %5s | %4d | %5d | %c | %5.2f | %5.2f ]\n",
1274 edge
->dir
== ah_dir_up
1276 : ( edge
->dir
== ah_dir_down
1278 : ( edge
->dir
== ah_dir_left
1280 : ( edge
->dir
== ah_dir_right
1283 edge
->link
? ( edge
->link
- edges
) : -1,
1284 edge
->serif
? ( edge
->serif
- edges
) : -1,
1285 edge
->blue_edge
? 'y' : 'n',
1290 edges
= outline
->vert_edges
;
1291 limit
= edges
+ outline
->num_vedges
;
1292 segments
= outline
->vert_segments
;
1296 #endif /* AH_DEBUG_GLYPH */