1 /***************************************************************************/
5 /* Glyph hinter (body). */
7 /* Copyright 2000-2001, 2002 Catharon Productions Inc. */
8 /* Author: David Turner */
10 /* This file is part of the Catharon Typography Project and shall only */
11 /* be used, modified, and distributed under the terms of the Catharon */
12 /* Open Source License that should come with this file under the name */
13 /* `CatharonLicense.txt'. By continuing to use, modify, or distribute */
14 /* this file you indicate that you have read the license and */
15 /* understand and accept it fully. */
17 /* Note that this license is compatible with the FreeType license. */
19 /***************************************************************************/
30 #define FACE_GLOBALS( face ) ((AH_Face_Globals*)(face)->autohint.data)
35 /*************************************************************************/
36 /*************************************************************************/
38 /**** Hinting routines ****/
40 /*************************************************************************/
41 /*************************************************************************/
44 /* snap a given width in scaled coordinates to one of the */
45 /* current standard widths */
47 ah_snap_width( FT_Pos
* widths
,
52 FT_Pos best
= 64 + 32 + 2;
53 FT_Pos reference
= width
;
56 for ( n
= 0; n
< count
; n
++ )
73 if ( width
>= reference
)
76 if ( width
< reference
)
82 if ( width
> reference
)
90 /* align one stem edge relative to the previous stem edge */
92 ah_align_linked_edge( AH_Hinter
* hinter
,
97 FT_Pos dist
= stem_edge
->opos
- base_edge
->opos
;
98 AH_Globals
* globals
= &hinter
->globals
->scaled
;
110 dist
= ah_snap_width( globals
->heights
, globals
->num_heights
, dist
);
112 /* in the case of vertical hinting, always round */
113 /* the stem heights to integer pixels */
115 dist
= ( dist
+ 16 ) & -64;
121 dist
= ah_snap_width( globals
->widths
, globals
->num_widths
, dist
);
123 if ( hinter
->flags
& ah_hinter_monochrome
)
125 /* monochrome horizontal hinting: snap widths to integer pixels */
126 /* with a different threshold */
130 dist
= ( dist
+ 32 ) & -64;
134 /* for horizontal anti-aliased hinting, we adopt a more subtle */
135 /* approach: we strengthen small stems, round stems whose size */
136 /* is between 1 and 2 pixels to an integer, otherwise nothing */
138 dist
= ( dist
+ 64 ) >> 1;
140 else if ( dist
< 128 )
141 dist
= ( dist
+ 42 ) & -64;
143 /* XXX: round otherwise, prevent color fringes in LCD mode */
144 dist
= ( dist
+ 32 ) & -64;
148 stem_edge
->pos
= base_edge
->pos
+ sign
* dist
;
153 ah_align_serif_edge( AH_Hinter
* hinter
,
164 dist
= serif
->opos
- base
->opos
;
171 /* do not strengthen serifs */
172 if ( base
->flags
& ah_edge_done
)
175 dist
= (dist
+8) & -64;
177 else if ( dist
<= 32 && !vertical
)
178 dist
= ( dist
+ 33 ) >> 1;
183 serif
->pos
= base
->pos
+ sign
* dist
;
187 /*************************************************************************/
188 /*************************************************************************/
189 /*************************************************************************/
191 /**** E D G E H I N T I N G ****/
193 /*************************************************************************/
194 /*************************************************************************/
195 /*************************************************************************/
198 /* Another alternative edge hinting algorithm */
200 ah_hint_edges_3( AH_Hinter
* hinter
)
204 AH_Outline
* outline
= hinter
->glyph
;
208 edges
= outline
->horz_edges
;
209 edge_limit
= edges
+ outline
->num_hedges
;
211 for ( dimension
= 1; dimension
>= 0; dimension
-- )
218 if ( ah_debug_disable_vert
&& !dimension
)
221 if ( ah_debug_disable_horz
&& dimension
)
224 /* we begin by aligning all stems relative to the blue zone */
225 /* if needed -- that's only for horizontal edges */
228 for ( edge
= edges
; edge
< edge_limit
; edge
++ )
231 AH_Edge
*edge1
, *edge2
;
234 if ( edge
->flags
& ah_edge_done
)
237 blue
= edge
->blue_edge
;
245 else if (edge2
&& edge2
->blue_edge
)
247 blue
= edge2
->blue_edge
;
255 edge1
->pos
= blue
[0];
256 edge1
->flags
|= ah_edge_done
;
258 if ( edge2
&& !edge2
->blue_edge
)
260 ah_align_linked_edge( hinter
, edge1
, edge2
, dimension
);
261 edge2
->flags
|= ah_edge_done
;
269 /* now, we will align all stem edges, trying to maintain the */
270 /* relative order of stems in the glyph.. */
271 for ( edge
= edges
; edge
< edge_limit
; edge
++ )
276 if ( edge
->flags
& ah_edge_done
)
279 /* skip all non-stem edges */
287 /* now, align the stem */
289 /* this should not happen, but it's better to be safe.. */
290 if ( edge2
->blue_edge
|| edge2
< edge
)
294 printf( "strange blue alignement, edge %d to %d\n",
295 edge
- edges
, edge2
- edges
);
298 ah_align_linked_edge( hinter
, edge2
, edge
, dimension
);
299 edge
->flags
|= ah_edge_done
;
309 edge
->pos
= ( edge
->opos
+ 32 ) & -64;
313 edge
->pos
= anchor
->pos
+
314 ( ( edge
->opos
- anchor
->opos
+ 32 ) & -64 );
316 edge
->flags
|= ah_edge_done
;
318 if ( edge
> edges
&& edge
->pos
< edge
[-1].pos
)
320 edge
->pos
= edge
[-1].pos
;
324 ah_align_linked_edge( hinter
, edge
, edge2
, dimension
);
326 if ( edge2
+ 1 < edge_limit
&&
327 edge2
[1].flags
& ah_edge_done
)
328 delta
= edge2
[1].pos
- edge2
->pos
;
336 edge2
->flags
|= ah_edge_done
;
343 /* now, hint the remaining edges (serifs and single) in order */
344 /* to complete our processing */
345 for ( edge
= edges
; edge
< edge_limit
; edge
++ )
347 if ( edge
->flags
& ah_edge_done
)
352 ah_align_serif_edge( hinter
, edge
->serif
, edge
, dimension
);
356 edge
->pos
= ( edge
->opos
+ 32 ) & -64;
360 edge
->pos
= anchor
->pos
+
361 ( ( edge
->opos
-anchor
->opos
+ 32 ) & -64 );
363 edge
->flags
|= ah_edge_done
;
365 if ( edge
> edges
&& edge
->pos
< edge
[-1].pos
)
366 edge
->pos
= edge
[-1].pos
;
368 if ( edge
+ 1 < edge_limit
&&
369 edge
[1].flags
& ah_edge_done
&&
370 edge
->pos
> edge
[1].pos
)
371 edge
->pos
= edge
[1].pos
;
375 edges
= outline
->vert_edges
;
376 edge_limit
= edges
+ outline
->num_vedges
;
382 ah_hinter_hint_edges( AH_Hinter
* hinter
,
383 FT_Bool no_horz_edges
,
384 FT_Bool no_vert_edges
)
387 ah_debug_disable_horz
= no_horz_edges
;
388 ah_debug_disable_vert
= no_vert_edges
;
390 FT_UNUSED( no_horz_edges
);
391 FT_UNUSED( no_vert_edges
);
393 /* AH_Interpolate_Blue_Edges( hinter ); -- doesn't seem to help */
394 /* reduce the problem of the disappearing eye in the `e' of Times... */
395 /* also, creates some artifacts near the blue zones? */
397 ah_hint_edges_3( hinter
);
400 /* outline optimizer removed temporarily */
401 if ( hinter
->flags
& ah_hinter_optimize
)
406 if ( !AH_Optimizer_Init( &opt
, hinter
->glyph
, hinter
->memory
) )
408 AH_Optimizer_Compute( &opt
);
409 AH_Optimizer_Done( &opt
);
418 /*************************************************************************/
419 /*************************************************************************/
420 /*************************************************************************/
422 /**** P O I N T H I N T I N G ****/
424 /*************************************************************************/
425 /*************************************************************************/
426 /*************************************************************************/
429 ah_hinter_align_edge_points( AH_Hinter
* hinter
)
431 AH_Outline
* outline
= hinter
->glyph
;
437 edges
= outline
->horz_edges
;
438 edge_limit
= edges
+ outline
->num_hedges
;
440 for ( dimension
= 1; dimension
>= 0; dimension
-- )
446 for ( ; edge
< edge_limit
; edge
++ )
448 /* move the points of each segment */
449 /* in each edge to the edge's position */
450 AH_Segment
* seg
= edge
->first
;
455 AH_Point
* point
= seg
->first
;
462 point
->y
= edge
->pos
;
463 point
->flags
|= ah_flag_touch_y
;
467 point
->x
= edge
->pos
;
468 point
->flags
|= ah_flag_touch_x
;
471 if ( point
== seg
->last
)
477 seg
= seg
->edge_next
;
479 } while ( seg
!= edge
->first
);
482 edges
= outline
->vert_edges
;
483 edge_limit
= edges
+ outline
->num_vedges
;
488 /* hint the strong points -- this is equivalent to the TrueType `IP' */
490 ah_hinter_align_strong_points( AH_Hinter
* hinter
)
492 AH_Outline
* outline
= hinter
->glyph
;
497 AH_Point
* point_limit
;
501 points
= outline
->points
;
502 point_limit
= points
+ outline
->num_points
;
504 edges
= outline
->horz_edges
;
505 edge_limit
= edges
+ outline
->num_hedges
;
506 touch_flag
= ah_flag_touch_y
;
508 for ( dimension
= 1; dimension
>= 0; dimension
-- )
514 if ( edges
< edge_limit
)
515 for ( point
= points
; point
< point_limit
; point
++ )
517 FT_Pos u
, ou
, fu
; /* point position */
521 if ( point
->flags
& touch_flag
)
524 #ifndef AH_OPTION_NO_WEAK_INTERPOLATION
525 /* if this point is candidate to weak interpolation, we will */
526 /* interpolate it after all strong points have been processed */
527 if ( point
->flags
& ah_flag_weak_interpolation
)
544 /* is the point before the first edge? */
546 delta
= edge
->fpos
- u
;
549 u
= edge
->pos
- ( edge
->opos
- ou
);
553 /* is the point after the last edge ? */
554 edge
= edge_limit
- 1;
555 delta
= u
- edge
->fpos
;
558 u
= edge
->pos
+ ( ou
- edge
->opos
);
562 /* otherwise, interpolate the point in between */
568 for ( edge
= edges
; edge
< edge_limit
; edge
++ )
570 if ( u
== edge
->fpos
)
575 if ( u
< edge
->fpos
)
580 for ( edge
= edge_limit
- 1; edge
>= edges
; edge
-- )
582 if ( u
== edge
->fpos
)
587 if ( u
> edge
->fpos
)
592 /* assert( before && after && before != after ) */
593 u
= before
->pos
+ FT_MulDiv( fu
- before
->fpos
,
594 after
->pos
- before
->pos
,
595 after
->fpos
- before
->fpos
);
600 /* save the point position */
606 point
->flags
|= touch_flag
;
609 edges
= outline
->vert_edges
;
610 edge_limit
= edges
+ outline
->num_vedges
;
611 touch_flag
= ah_flag_touch_x
;
616 #ifndef AH_OPTION_NO_WEAK_INTERPOLATION
619 ah_iup_shift( AH_Point
* p1
,
624 FT_Pos delta
= ref
->u
- ref
->v
;
627 for ( p
= p1
; p
< ref
; p
++ )
630 for ( p
= ref
+ 1; p
<= p2
; p
++ )
636 ah_iup_interp( AH_Point
* p1
,
645 FT_Pos d1
= ref1
->u
- v1
;
646 FT_Pos d2
= ref2
->u
- v2
;
654 for ( p
= p1
; p
<= p2
; p
++ )
670 for ( p
= p1
; p
<= p2
; p
++ )
679 u
= ref1
->u
+ FT_MulDiv( u
- v1
, ref2
->u
- ref1
->u
, v2
- v1
);
686 for ( p
= p1
; p
<= p2
; p
++ )
695 u
= ref1
->u
+ FT_MulDiv( u
- v1
, ref2
->u
- ref1
->u
, v2
- v1
);
703 /* interpolate weak points -- this is equivalent to the TrueType `IUP' */
705 ah_hinter_align_weak_points( AH_Hinter
* hinter
)
707 AH_Outline
* outline
= hinter
->glyph
;
710 AH_Point
* point_limit
;
711 AH_Point
** contour_limit
;
715 points
= outline
->points
;
716 point_limit
= points
+ outline
->num_points
;
718 /* PASS 1: Move segment points to edge positions */
720 touch_flag
= ah_flag_touch_y
;
722 contour_limit
= outline
->contours
+ outline
->num_contours
;
724 ah_setup_uv( outline
, ah_uv_oy
);
726 for ( dimension
= 1; dimension
>= 0; dimension
-- )
730 AH_Point
* first_point
;
735 contour
= outline
->contours
;
737 for ( ; contour
< contour_limit
; contour
++ )
740 end_point
= point
->prev
;
743 while ( point
<= end_point
&& !( point
->flags
& touch_flag
) )
746 if ( point
<= end_point
)
748 AH_Point
* first_touched
= point
;
749 AH_Point
* cur_touched
= point
;
753 while ( point
<= end_point
)
755 if ( point
->flags
& touch_flag
)
757 /* we found two successive touched points; we interpolate */
758 /* all contour points between them */
759 ah_iup_interp( cur_touched
+ 1, point
- 1,
760 cur_touched
, point
);
766 if ( cur_touched
== first_touched
)
768 /* this is a special case: only one point was touched in the */
769 /* contour; we thus simply shift the whole contour */
770 ah_iup_shift( first_point
, end_point
, cur_touched
);
774 /* now interpolate after the last touched point to the end */
776 ah_iup_interp( cur_touched
+ 1, end_point
,
777 cur_touched
, first_touched
);
779 /* if the first contour point isn't touched, interpolate */
780 /* from the contour start to the first touched point */
781 if ( first_touched
> points
)
782 ah_iup_interp( first_point
, first_touched
- 1,
783 cur_touched
, first_touched
);
788 /* now save the interpolated values back to x/y */
791 for ( point
= points
; point
< point_limit
; point
++ )
794 touch_flag
= ah_flag_touch_x
;
795 ah_setup_uv( outline
, ah_uv_ox
);
799 for ( point
= points
; point
< point_limit
; point
++ )
802 break; /* exit loop */
807 #endif /* !AH_OPTION_NO_WEAK_INTERPOLATION */
811 ah_hinter_align_points( AH_Hinter
* hinter
)
813 ah_hinter_align_edge_points( hinter
);
815 #ifndef AH_OPTION_NO_STRONG_INTERPOLATION
816 ah_hinter_align_strong_points( hinter
);
819 #ifndef AH_OPTION_NO_WEAK_INTERPOLATION
820 ah_hinter_align_weak_points( hinter
);
825 /*************************************************************************/
826 /*************************************************************************/
827 /*************************************************************************/
829 /**** H I N T E R O B J E C T M E T H O D S ****/
831 /*************************************************************************/
832 /*************************************************************************/
833 /*************************************************************************/
836 /* scale and fit the global metrics */
838 ah_hinter_scale_globals( AH_Hinter
* hinter
,
843 AH_Face_Globals
* globals
= hinter
->globals
;
844 AH_Globals
* design
= &globals
->design
;
845 AH_Globals
* scaled
= &globals
->scaled
;
851 /* scale the standard widths & heights */
852 for ( n
= 0; n
< design
->num_widths
; n
++ )
853 scaled
->widths
[n
] = FT_MulFix( design
->widths
[n
], x_scale
);
855 for ( n
= 0; n
< design
->num_heights
; n
++ )
856 scaled
->heights
[n
] = FT_MulFix( design
->heights
[n
], y_scale
);
858 /* scale the blue zones */
859 for ( n
= 0; n
< ah_blue_max
; n
++ )
861 FT_Pos delta
, delta2
;
864 delta
= design
->blue_shoots
[n
] - design
->blue_refs
[n
];
868 delta2
= FT_MulFix( delta2
, y_scale
);
872 else if ( delta2
< 64 )
873 delta2
= 32 + ( ( ( delta2
- 32 ) + 16 ) & -32 );
875 delta2
= ( delta2
+ 32 ) & -64;
880 scaled
->blue_refs
[n
] =
881 ( FT_MulFix( design
->blue_refs
[n
], y_scale
) + 32 ) & -64;
882 scaled
->blue_shoots
[n
] = scaled
->blue_refs
[n
] + delta2
;
885 globals
->x_scale
= x_scale
;
886 globals
->y_scale
= y_scale
;
891 ah_hinter_align( AH_Hinter
* hinter
)
893 ah_hinter_align_edge_points( hinter
);
894 ah_hinter_align_points( hinter
);
898 /* finalize a hinter object */
900 ah_hinter_done( AH_Hinter
* hinter
)
904 FT_Memory memory
= hinter
->memory
;
907 ah_loader_done( hinter
->loader
);
908 ah_outline_done( hinter
->glyph
);
910 /* note: the `globals' pointer is _not_ owned by the hinter */
911 /* but by the current face object, we don't need to */
921 /* create a new empty hinter object */
922 FT_LOCAL_DEF( FT_Error
)
923 ah_hinter_new( FT_Library library
,
924 AH_Hinter
** ahinter
)
926 AH_Hinter
* hinter
= 0;
927 FT_Memory memory
= library
->memory
;
933 /* allocate object */
934 if ( FT_NEW( hinter
) )
937 hinter
->memory
= memory
;
940 /* allocate outline and loader */
941 error
= ah_outline_new( memory
, &hinter
->glyph
) ||
942 ah_loader_new ( memory
, &hinter
->loader
) ||
943 ah_loader_create_extra( hinter
->loader
);
951 ah_hinter_done( hinter
);
957 /* create a face's autohint globals */
958 FT_LOCAL_DEF( FT_Error
)
959 ah_hinter_new_face_globals( AH_Hinter
* hinter
,
961 AH_Globals
* globals
)
964 FT_Memory memory
= hinter
->memory
;
965 AH_Face_Globals
* face_globals
;
968 if ( FT_NEW( face_globals
) )
972 hinter
->globals
= face_globals
;
975 face_globals
->design
= *globals
;
977 ah_hinter_compute_globals( hinter
);
979 face
->autohint
.data
= face_globals
;
980 face
->autohint
.finalizer
= (FT_Generic_Finalizer
)
981 ah_hinter_done_face_globals
;
982 face_globals
->face
= face
;
989 /* discard a face's autohint globals */
991 ah_hinter_done_face_globals( AH_Face_Globals
* globals
)
993 FT_Face face
= globals
->face
;
994 FT_Memory memory
= face
->memory
;
1002 ah_hinter_load( AH_Hinter
* hinter
,
1003 FT_UInt glyph_index
,
1007 FT_Face face
= hinter
->face
;
1008 FT_GlyphSlot slot
= face
->glyph
;
1009 FT_Slot_Internal internal
= slot
->internal
;
1010 FT_Fixed x_scale
= face
->size
->metrics
.x_scale
;
1011 FT_Fixed y_scale
= face
->size
->metrics
.y_scale
;
1013 AH_Outline
* outline
= hinter
->glyph
;
1014 AH_Loader gloader
= hinter
->loader
;
1015 FT_Bool no_horz_hints
= FT_BOOL(
1016 ( load_flags
& AH_HINT_NO_HORZ_EDGES
) != 0 );
1017 FT_Bool no_vert_hints
= FT_BOOL(
1018 ( load_flags
& AH_HINT_NO_VERT_EDGES
) != 0 );
1021 /* load the glyph */
1022 error
= FT_Load_Glyph( face
, glyph_index
, load_flags
);
1026 /* Set `hinter->transformed' after loading with FT_LOAD_NO_RECURSE. */
1027 hinter
->transformed
= internal
->glyph_transformed
;
1029 if ( hinter
->transformed
)
1033 imatrix
= internal
->glyph_matrix
;
1034 hinter
->trans_delta
= internal
->glyph_delta
;
1035 hinter
->trans_matrix
= imatrix
;
1037 FT_Matrix_Invert( &imatrix
);
1038 FT_Vector_Transform( &hinter
->trans_delta
, &imatrix
);
1041 /* set linear horizontal metrics */
1042 slot
->linearHoriAdvance
= slot
->metrics
.horiAdvance
;
1043 slot
->linearVertAdvance
= slot
->metrics
.vertAdvance
;
1045 switch ( slot
->format
)
1047 case ft_glyph_format_outline
:
1049 /* translate glyph outline if we need to */
1050 if ( hinter
->transformed
)
1052 FT_UInt n
= slot
->outline
.n_points
;
1053 FT_Vector
* point
= slot
->outline
.points
;
1056 for ( ; n
> 0; point
++, n
-- )
1058 point
->x
+= hinter
->trans_delta
.x
;
1059 point
->y
+= hinter
->trans_delta
.y
;
1063 /* copy the outline points in the loader's current */
1064 /* extra points, which is used to keep original glyph coordinates */
1065 error
= ah_loader_check_points( gloader
, slot
->outline
.n_points
+ 2,
1066 slot
->outline
.n_contours
);
1070 FT_MEM_COPY( gloader
->current
.extra_points
, slot
->outline
.points
,
1071 slot
->outline
.n_points
* sizeof ( FT_Vector
) );
1073 FT_MEM_COPY( gloader
->current
.outline
.contours
, slot
->outline
.contours
,
1074 slot
->outline
.n_contours
* sizeof ( short ) );
1076 FT_MEM_COPY( gloader
->current
.outline
.tags
, slot
->outline
.tags
,
1077 slot
->outline
.n_points
* sizeof ( char ) );
1079 gloader
->current
.outline
.n_points
= slot
->outline
.n_points
;
1080 gloader
->current
.outline
.n_contours
= slot
->outline
.n_contours
;
1082 /* compute original phantom points */
1085 hinter
->pp2
.x
= FT_MulFix( slot
->metrics
.horiAdvance
, x_scale
);
1088 /* be sure to check for spacing glyphs */
1089 if ( slot
->outline
.n_points
== 0 )
1092 /* now, load the slot image into the auto-outline, and run the */
1093 /* automatic hinting process */
1094 error
= ah_outline_load( outline
, face
); /* XXX: change to slot */
1098 /* perform feature detection */
1099 ah_outline_detect_features( outline
);
1101 if ( !no_horz_hints
)
1103 ah_outline_compute_blue_edges( outline
, hinter
->globals
);
1104 ah_outline_scale_blue_edges( outline
, hinter
->globals
);
1107 /* perform alignment control */
1108 ah_hinter_hint_edges( hinter
, no_horz_hints
, no_vert_hints
);
1109 ah_hinter_align( hinter
);
1111 /* now save the current outline into the loader's current table */
1112 ah_outline_save( outline
, gloader
);
1114 /* we now need to hint the metrics according to the change in */
1115 /* width/positioning that occured during the hinting process */
1117 FT_Pos old_advance
, old_rsb
, old_lsb
, new_lsb
;
1118 AH_Edge
* edge1
= outline
->vert_edges
; /* leftmost edge */
1119 AH_Edge
* edge2
= edge1
+
1120 outline
->num_vedges
- 1; /* rightmost edge */
1123 old_advance
= hinter
->pp2
.x
;
1124 old_rsb
= old_advance
- edge2
->opos
;
1125 old_lsb
= edge1
->opos
;
1126 new_lsb
= edge1
->pos
;
1128 hinter
->pp1
.x
= ( ( new_lsb
- old_lsb
) + 32 ) & -64;
1129 hinter
->pp2
.x
= ( ( edge2
->pos
+ old_rsb
) + 32 ) & -64;
1131 /* try to fix certain bad advance computations */
1132 if ( hinter
->pp2
.x
+ hinter
->pp1
.x
== edge2
->pos
&& old_rsb
> 4 )
1133 hinter
->pp2
.x
+= 64;
1136 /* good, we simply add the glyph to our loader's base */
1137 ah_loader_add( gloader
);
1140 case ft_glyph_format_composite
:
1142 FT_UInt nn
, num_subglyphs
= slot
->num_subglyphs
;
1143 FT_UInt num_base_subgs
, start_point
;
1144 FT_SubGlyph subglyph
;
1147 start_point
= gloader
->base
.outline
.n_points
;
1149 /* first of all, copy the subglyph descriptors in the glyph loader */
1150 error
= ah_loader_check_subglyphs( gloader
, num_subglyphs
);
1154 FT_MEM_COPY( gloader
->current
.subglyphs
, slot
->subglyphs
,
1155 num_subglyphs
* sizeof ( FT_SubGlyph
) );
1157 gloader
->current
.num_subglyphs
= num_subglyphs
;
1158 num_base_subgs
= gloader
->base
.num_subglyphs
;
1160 /* now, read each subglyph independently */
1161 for ( nn
= 0; nn
< num_subglyphs
; nn
++ )
1165 FT_UInt num_points
, num_new_points
, num_base_points
;
1168 /* gloader.current.subglyphs can change during glyph loading due */
1169 /* to re-allocation -- we must recompute the current subglyph on */
1170 /* each iteration */
1171 subglyph
= gloader
->base
.subglyphs
+ num_base_subgs
+ nn
;
1176 num_base_points
= gloader
->base
.outline
.n_points
;
1178 error
= ah_hinter_load( hinter
, subglyph
->index
,
1179 load_flags
, depth
+ 1 );
1183 /* recompute subglyph pointer */
1184 subglyph
= gloader
->base
.subglyphs
+ num_base_subgs
+ nn
;
1186 if ( subglyph
->flags
& FT_SUBGLYPH_FLAG_USE_MY_METRICS
)
1197 num_points
= gloader
->base
.outline
.n_points
;
1198 num_new_points
= num_points
- num_base_points
;
1200 /* now perform the transform required for this subglyph */
1202 if ( subglyph
->flags
& ( FT_SUBGLYPH_FLAG_SCALE
|
1203 FT_SUBGLYPH_FLAG_XY_SCALE
|
1204 FT_SUBGLYPH_FLAG_2X2
) )
1206 FT_Vector
* cur
= gloader
->base
.outline
.points
+
1208 FT_Vector
* org
= gloader
->base
.extra_points
+
1210 FT_Vector
* limit
= cur
+ num_new_points
;
1213 for ( ; cur
< limit
; cur
++, org
++ )
1215 FT_Vector_Transform( cur
, &subglyph
->transform
);
1216 FT_Vector_Transform( org
, &subglyph
->transform
);
1222 if ( !( subglyph
->flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
) )
1224 FT_Int k
= subglyph
->arg1
;
1225 FT_UInt l
= subglyph
->arg2
;
1230 if ( start_point
+ k
>= num_base_points
||
1231 l
>= (FT_UInt
)num_new_points
)
1233 error
= AH_Err_Invalid_Composite
;
1237 l
+= num_base_points
;
1239 /* for now, only use the current point coordinates */
1240 /* we may consider another approach in the near future */
1241 p1
= gloader
->base
.outline
.points
+ start_point
+ k
;
1242 p2
= gloader
->base
.outline
.points
+ start_point
+ l
;
1249 x
= FT_MulFix( subglyph
->arg1
, x_scale
);
1250 y
= FT_MulFix( subglyph
->arg2
, y_scale
);
1252 x
= ( x
+ 32 ) & -64;
1253 y
= ( y
+ 32 ) & -64;
1257 FT_Outline dummy
= gloader
->base
.outline
;
1260 dummy
.points
+= num_base_points
;
1261 dummy
.n_points
= (short)num_new_points
;
1263 FT_Outline_Translate( &dummy
, x
, y
);
1270 /* we don't support other formats (yet?) */
1271 error
= AH_Err_Unimplemented_Feature
;
1280 /* transform the hinted outline if needed */
1281 if ( hinter
->transformed
)
1282 FT_Outline_Transform( &gloader
->base
.outline
, &hinter
->trans_matrix
);
1284 /* we must translate our final outline by -pp1.x, and compute */
1285 /* the new metrics */
1286 if ( hinter
->pp1
.x
)
1287 FT_Outline_Translate( &gloader
->base
.outline
, -hinter
->pp1
.x
, 0 );
1289 FT_Outline_Get_CBox( &gloader
->base
.outline
, &bbox
);
1292 bbox
.xMax
= ( bbox
.xMax
+ 63 ) & -64;
1293 bbox
.yMax
= ( bbox
.yMax
+ 63 ) & -64;
1295 slot
->metrics
.width
= bbox
.xMax
- bbox
.xMin
;
1296 slot
->metrics
.height
= bbox
.yMax
- bbox
.yMin
;
1297 slot
->metrics
.horiBearingX
= bbox
.xMin
;
1298 slot
->metrics
.horiBearingY
= bbox
.yMax
;
1300 /* for mono-width fonts (like Andale, Courier, etc.), we need */
1301 /* to keep the original rounded advance width */
1302 if ( !FT_IS_FIXED_WIDTH( slot
->face
) )
1303 slot
->metrics
.horiAdvance
= hinter
->pp2
.x
- hinter
->pp1
.x
;
1305 slot
->metrics
.horiAdvance
= FT_MulFix( slot
->metrics
.horiAdvance
,
1308 slot
->metrics
.horiAdvance
= ( slot
->metrics
.horiAdvance
+ 32 ) & -64;
1310 /* now copy outline into glyph slot */
1311 ah_loader_rewind( slot
->internal
->loader
);
1312 error
= ah_loader_copy_points( slot
->internal
->loader
, gloader
);
1316 slot
->outline
= slot
->internal
->loader
->base
.outline
;
1317 slot
->format
= ft_glyph_format_outline
;
1321 ah_debug_hinter
= hinter
;
1329 /* load and hint a given glyph */
1330 FT_LOCAL_DEF( FT_Error
)
1331 ah_hinter_load_glyph( AH_Hinter
* hinter
,
1334 FT_UInt glyph_index
,
1337 FT_Face face
= slot
->face
;
1339 FT_Fixed x_scale
= size
->metrics
.x_scale
;
1340 FT_Fixed y_scale
= size
->metrics
.y_scale
;
1341 AH_Face_Globals
* face_globals
= FACE_GLOBALS( face
);
1344 /* first of all, we need to check that we're using the correct face and */
1345 /* global hints to load the glyph */
1346 if ( hinter
->face
!= face
|| hinter
->globals
!= face_globals
)
1348 hinter
->face
= face
;
1349 if ( !face_globals
)
1351 error
= ah_hinter_new_face_globals( hinter
, face
, 0 );
1356 hinter
->globals
= FACE_GLOBALS( face
);
1357 face_globals
= FACE_GLOBALS( face
);
1361 /* now, we must check the current character pixel size to see if we */
1362 /* need to rescale the global metrics */
1363 if ( face_globals
->x_scale
!= x_scale
||
1364 face_globals
->y_scale
!= y_scale
)
1365 ah_hinter_scale_globals( hinter
, x_scale
, y_scale
);
1367 ah_loader_rewind( hinter
->loader
);
1370 load_flags
= FT_LOAD_NO_SCALE
1371 | FT_LOAD_IGNORE_TRANSFORM
;
1373 load_flags
|= FT_LOAD_NO_SCALE
| FT_LOAD_NO_RECURSE
;
1376 error
= ah_hinter_load( hinter
, glyph_index
, load_flags
, 0 );
1383 /* retrieve a face's autohint globals for client applications */
1384 FT_LOCAL_DEF( void )
1385 ah_hinter_get_global_hints( AH_Hinter
* hinter
,
1387 void** global_hints
,
1390 AH_Globals
* globals
= 0;
1391 FT_Memory memory
= hinter
->memory
;
1395 /* allocate new master globals */
1396 if ( FT_NEW( globals
) )
1399 /* compute face globals if needed */
1400 if ( !FACE_GLOBALS( face
) )
1402 error
= ah_hinter_new_face_globals( hinter
, face
, 0 );
1407 *globals
= FACE_GLOBALS( face
)->design
;
1408 *global_hints
= globals
;
1409 *global_len
= sizeof( *globals
);
1421 FT_LOCAL_DEF( void )
1422 ah_hinter_done_global_hints( AH_Hinter
* hinter
,
1423 void* global_hints
)
1425 FT_Memory memory
= hinter
->memory
;
1428 FT_FREE( global_hints
);