1 /***************************************************************************/
5 /* Glyph hinter (body). */
7 /* Copyright 2000 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 /***************************************************************************/
22 #ifdef FT_FLAT_COMPILE
30 #include <autohint/ahhint.h>
31 #include <autohint/ahglyph.h>
32 #include <autohint/ahangles.h>
36 #include <freetype/ftoutln.h>
39 #define FACE_GLOBALS( face ) ((AH_Face_Globals*)(face)->autohint.data)
44 /*************************************************************************/
45 /*************************************************************************/
47 /**** Hinting routines ****/
49 /*************************************************************************/
50 /*************************************************************************/
53 static int disable_horz_edges
= 0;
54 static int disable_vert_edges
= 0;
57 /* snap a given width in scaled coordinates to one of the */
58 /* current standard widths */
60 FT_Pos
ah_snap_width( FT_Pos
* widths
,
65 FT_Pos best
= 64 + 32 + 2;
66 FT_Pos reference
= width
;
69 for ( n
= 0; n
< count
; n
++ )
86 if ( width
>= reference
)
89 if ( width
< reference
)
95 if ( width
> reference
)
103 /* align one stem edge relative to the previous stem edge */
105 void ah_align_linked_edge( AH_Hinter
* hinter
,
110 FT_Pos dist
= stem_edge
->opos
- base_edge
->opos
;
111 AH_Globals
* globals
= &hinter
->globals
->scaled
;
123 dist
= ah_snap_width( globals
->heights
, globals
->num_heights
, dist
);
125 /* in the case of vertical hinting, always round */
126 /* the stem heights to integer pixels */
128 dist
= ( dist
+ 16 ) & -64;
134 dist
= ah_snap_width( globals
->widths
, globals
->num_widths
, dist
);
136 if ( hinter
->flags
& ah_hinter_monochrome
)
138 /* monochrome horizontal hinting: snap widths to integer pixels */
139 /* with a different threshold */
143 dist
= ( dist
+ 32 ) & -64;
147 /* for horizontal anti-aliased hinting, we adopt a more subtle */
148 /* approach: we strengthen small stems, round stems whose size */
149 /* is between 1 and 2 pixels to an integer, otherwise nothing */
151 dist
= ( dist
+ 64 ) >> 1;
153 else if ( dist
< 128 )
154 dist
= ( dist
+ 42 ) & -64;
158 stem_edge
->pos
= base_edge
->pos
+ sign
* dist
;
163 void ah_align_serif_edge( AH_Hinter
* hinter
,
173 dist
= serif
->opos
- base
->opos
;
180 /* do not strengthen serifs */
181 if ( base
->flags
& ah_edge_done
)
184 dist
= ( dist
+ 16 ) & -64;
186 else if ( dist
<= 32 )
187 dist
= ( dist
+ 33 ) >> 1;
190 serif
->pos
= base
->pos
+ sign
* dist
;
194 /*************************************************************************/
195 /*************************************************************************/
196 /*************************************************************************/
198 /**** E D G E H I N T I N G ****/
200 /*************************************************************************/
201 /*************************************************************************/
202 /*************************************************************************/
205 /* Another alternative edge hinting algorithm */
207 void ah_hint_edges_3( AH_Hinter
* hinter
)
211 AH_Outline
* outline
= hinter
->glyph
;
215 edges
= outline
->horz_edges
;
216 edge_limit
= edges
+ outline
->num_hedges
;
218 for ( dimension
= 1; dimension
>= 0; dimension
-- )
227 if ( disable_vert_edges
&& !dimension
)
230 if ( disable_horz_edges
&& dimension
)
233 /* we begin by aligning all stems relative to the blue zone */
234 /* if needed -- that's only for horizontal edges */
237 for ( edge
= edges
; edge
< edge_limit
; edge
++ )
240 AH_Edge
*edge1
, *edge2
;
243 if ( edge
->flags
& ah_edge_done
)
246 blue
= edge
->blue_edge
;
254 else if (edge2
&& edge2
->blue_edge
)
256 blue
= edge2
->blue_edge
;
264 edge1
->pos
= blue
[0];
265 edge1
->flags
|= ah_edge_done
;
267 if ( edge2
&& !edge2
->blue_edge
)
269 ah_align_linked_edge( hinter
, edge1
, edge2
, dimension
);
270 edge2
->flags
|= ah_edge_done
;
278 /* now, we will align all stem edges, trying to maintain the */
279 /* relative order of stems in the glyph.. */
282 for ( edge
= edges
; edge
< edge_limit
; edge
++ )
287 if ( edge
->flags
& ah_edge_done
)
290 /* skip all non-stem edges */
298 /* now, align the stem */
300 /* this should not happen, but it's better to be safe.. */
301 if ( edge2
->blue_edge
|| edge2
< edge
)
305 printf( "strange blue alignement, edge %d to %d\n",
306 edge
- edges
, edge2
- edges
);
309 ah_align_linked_edge( hinter
, edge2
, edge
, dimension
);
310 edge
->flags
|= ah_edge_done
;
320 edge
->pos
= ( edge
->opos
+ 32 ) & -64;
324 edge
->pos
= anchor
->pos
+
325 ( ( edge
->opos
- anchor
->opos
+ 32 ) & -64 );
327 edge
->flags
|= ah_edge_done
;
329 if ( edge
> edges
&& edge
->pos
< edge
[-1].pos
)
331 edge
->pos
= edge
[-1].pos
;
335 ah_align_linked_edge( hinter
, edge
, edge2
, dimension
);
337 if ( edge2
+ 1 < edge_limit
&&
338 edge2
[1].flags
& ah_edge_done
)
339 delta
= edge2
[1].pos
- edge2
->pos
;
347 edge2
->flags
|= ah_edge_done
;
354 /* now, hint the remaining edges (serifs and single) in order */
355 /* to complete our processing */
356 for ( edge
= edges
; edge
< edge_limit
; edge
++ )
358 if ( edge
->flags
& ah_edge_done
)
363 ah_align_serif_edge( hinter
, edge
->serif
, edge
);
367 edge
->pos
= ( edge
->opos
+ 32 ) & -64;
371 edge
->pos
= anchor
->pos
+
372 ( ( edge
->opos
-anchor
->opos
+ 32 ) & -64 );
374 edge
->flags
|= ah_edge_done
;
376 if ( edge
> edges
&& edge
->pos
< edge
[-1].pos
)
377 edge
->pos
= edge
[-1].pos
;
379 if ( edge
+ 1 < edge_limit
&&
380 edge
[1].flags
& ah_edge_done
&&
381 edge
->pos
> edge
[1].pos
)
382 edge
->pos
= edge
[1].pos
;
386 edges
= outline
->vert_edges
;
387 edge_limit
= edges
+ outline
->num_vedges
;
393 void ah_hinter_hint_edges( AH_Hinter
* hinter
,
397 disable_horz_edges
= no_horz_edges
;
398 disable_vert_edges
= no_vert_edges
;
400 /* AH_Interpolate_Blue_Edges( hinter ); -- doesn't seem to help */
401 /* reduce the problem of the disappearing eye in the `e' of Times... */
402 /* also, creates some artifacts near the blue zones? */
404 ah_hint_edges_3( hinter
);
407 /* outline optimizer removed temporarily */
408 if ( hinter
->flags
& ah_hinter_optimize
)
413 if ( !AH_Optimizer_Init( &opt
, hinter
->glyph
, hinter
->memory
) )
415 AH_Optimizer_Compute( &opt
);
416 AH_Optimizer_Done( &opt
);
425 /*************************************************************************/
426 /*************************************************************************/
427 /*************************************************************************/
429 /**** P O I N T H I N T I N G ****/
431 /*************************************************************************/
432 /*************************************************************************/
433 /*************************************************************************/
436 void ah_hinter_align_edge_points( AH_Hinter
* hinter
)
438 AH_Outline
* outline
= hinter
->glyph
;
444 edges
= outline
->horz_edges
;
445 edge_limit
= edges
+ outline
->num_hedges
;
447 for ( dimension
= 1; dimension
>= 0; dimension
-- )
458 for ( ; edge
< edge_limit
; edge
++ )
460 /* move the points of each segment */
461 /* in each edge to the edge's position */
462 AH_Segment
* seg
= edge
->first
;
467 AH_Point
* point
= seg
->first
;
474 point
->y
= edge
->pos
;
475 point
->flags
|= ah_flah_touch_y
;
479 point
->x
= edge
->pos
;
480 point
->flags
|= ah_flah_touch_x
;
483 if ( point
== seg
->last
)
489 seg
= seg
->edge_next
;
491 } while ( seg
!= edge
->first
);
494 edges
= outline
->vert_edges
;
495 edge_limit
= edges
+ outline
->num_vedges
;
500 /* hint the strong points -- this is equivalent to the TrueType `IP' */
502 void ah_hinter_align_strong_points( AH_Hinter
* hinter
)
504 AH_Outline
* outline
= hinter
->glyph
;
509 AH_Point
* point_limit
;
513 points
= outline
->points
;
514 point_limit
= points
+ outline
->num_points
;
516 edges
= outline
->horz_edges
;
517 edge_limit
= edges
+ outline
->num_hedges
;
518 touch_flag
= ah_flah_touch_y
;
520 for ( dimension
= 1; dimension
>= 0; dimension
-- )
531 if ( edges
< edge_limit
)
532 for ( point
= points
; point
< point_limit
; point
++ )
534 FT_Pos u
, ou
, fu
; /* point position */
538 if ( point
->flags
& touch_flag
)
541 #ifndef AH_OPTION_NO_WEAK_INTERPOLATION
542 /* if this point is candidate to weak interpolation, we will */
543 /* interpolate it after all strong points have been processed */
544 if ( point
->flags
& ah_flah_weak_interpolation
)
561 /* is the point before the first edge? */
563 delta
= edge
->fpos
- u
;
566 u
= edge
->pos
- ( edge
->opos
- ou
);
570 /* is the point after the last edge ? */
571 edge
= edge_limit
- 1;
572 delta
= u
- edge
->fpos
;
575 u
= edge
->pos
+ ( ou
- edge
->opos
);
579 /* otherwise, interpolate the point in between */
585 for ( edge
= edges
; edge
< edge_limit
; edge
++ )
587 if ( u
== edge
->fpos
)
592 if ( u
< edge
->fpos
)
597 for ( edge
= edge_limit
- 1; edge
>= edges
; edge
-- )
599 if ( u
== edge
->fpos
)
604 if ( u
> edge
->fpos
)
609 /* assert( before && after && before != after ) */
610 u
= before
->pos
+ FT_MulDiv( fu
- before
->fpos
,
611 after
->pos
- before
->pos
,
612 after
->fpos
- before
->fpos
);
617 /* save the point position */
623 point
->flags
|= touch_flag
;
626 edges
= outline
->vert_edges
;
627 edge_limit
= edges
+ outline
->num_vedges
;
628 touch_flag
= ah_flah_touch_x
;
633 #ifndef AH_OPTION_NO_WEAK_INTERPOLATION
636 void ah_iup_shift( AH_Point
* p1
,
641 FT_Pos delta
= ref
->u
- ref
->v
;
644 for ( p
= p1
; p
< ref
; p
++ )
647 for ( p
= ref
+ 1; p
<= p2
; p
++ )
653 void ah_iup_interp( AH_Point
* p1
,
662 FT_Pos d1
= ref1
->u
- v1
;
663 FT_Pos d2
= ref2
->u
- v2
;
671 for ( p
= p1
; p
<= p2
; p
++ )
688 for ( p
= p1
; p
<= p2
; p
++ )
697 u
= ref1
->u
+ FT_MulDiv( u
- v1
, ref2
->u
- ref1
->u
, v2
- v1
);
704 for ( p
= p1
; p
<= p2
; p
++ )
713 u
= ref1
->u
+ FT_MulDiv( u
- v1
, ref2
->u
- ref1
->u
, v2
- v1
);
721 /* interpolate weak points -- this is equivalent to the TrueType `IUP' */
723 void ah_hinter_align_weak_points( AH_Hinter
* hinter
)
725 AH_Outline
* outline
= hinter
->glyph
;
730 AH_Point
* point_limit
;
731 AH_Point
** contour_limit
;
735 points
= outline
->points
;
736 point_limit
= points
+ outline
->num_points
;
738 /* PASS 1: Move segment points to edge positions */
740 edges
= outline
->horz_edges
;
741 edge_limit
= edges
+ outline
->num_hedges
;
742 touch_flag
= ah_flah_touch_y
;
744 contour_limit
= outline
->contours
+ outline
->num_contours
;
746 ah_setup_uv( outline
, ah_uv_oy
);
748 for ( dimension
= 1; dimension
>= 0; dimension
-- )
752 AH_Point
* first_point
;
757 contour
= outline
->contours
;
759 for ( ; contour
< contour_limit
; contour
++ )
762 end_point
= point
->prev
;
765 while ( point
<= end_point
&& !( point
->flags
& touch_flag
) )
768 if ( point
<= end_point
)
770 AH_Point
* first_touched
= point
;
771 AH_Point
* cur_touched
= point
;
775 while ( point
<= end_point
)
777 if ( point
->flags
& touch_flag
)
779 /* we found two successive touched points; we interpolate */
780 /* all contour points between them */
781 ah_iup_interp( cur_touched
+ 1, point
- 1,
782 cur_touched
, point
);
788 if ( cur_touched
== first_touched
)
790 /* this is a special case: only one point was touched in the */
791 /* contour; we thus simply shift the whole contour */
792 ah_iup_shift( first_point
, end_point
, cur_touched
);
796 /* now interpolate after the last touched point to the end */
798 ah_iup_interp( cur_touched
+ 1, end_point
,
799 cur_touched
, first_touched
);
801 /* if the first contour point isn't touched, interpolate */
802 /* from the contour start to the first touched point */
803 if ( first_touched
> points
)
804 ah_iup_interp( first_point
, first_touched
- 1,
805 cur_touched
, first_touched
);
810 /* now save the interpolated values back to x/y */
813 for ( point
= points
; point
< point_limit
; point
++ )
816 touch_flag
= ah_flah_touch_x
;
817 ah_setup_uv( outline
, ah_uv_ox
);
821 for ( point
= points
; point
< point_limit
; point
++ )
824 break; /* exit loop */
829 #endif /* !AH_OPTION_NO_WEAK_INTERPOLATION */
833 void ah_hinter_align_points( AH_Hinter
* hinter
)
835 ah_hinter_align_edge_points( hinter
);
837 #ifndef AH_OPTION_NO_STRONG_INTERPOLATION
838 ah_hinter_align_strong_points( hinter
);
841 #ifndef AH_OPTION_NO_WEAK_INTERPOLATION
842 ah_hinter_align_weak_points( hinter
);
847 /*************************************************************************/
848 /*************************************************************************/
849 /*************************************************************************/
851 /**** H I N T E R O B J E C T M E T H O D S ****/
853 /*************************************************************************/
854 /*************************************************************************/
855 /*************************************************************************/
858 /* scale and fit the global metrics */
860 void ah_hinter_scale_globals( AH_Hinter
* hinter
,
865 AH_Face_Globals
* globals
= hinter
->globals
;
866 AH_Globals
* design
= &globals
->design
;
867 AH_Globals
* scaled
= &globals
->scaled
;
873 /* scale the standard widths & heights */
874 for ( n
= 0; n
< design
->num_widths
; n
++ )
875 scaled
->widths
[n
] = FT_MulFix( design
->widths
[n
], x_scale
);
877 for ( n
= 0; n
< design
->num_heights
; n
++ )
878 scaled
->heights
[n
] = FT_MulFix( design
->heights
[n
], y_scale
);
880 /* scale the blue zones */
881 for ( n
= 0; n
< ah_blue_max
; n
++ )
883 FT_Pos delta
, delta2
;
886 delta
= design
->blue_shoots
[n
] - design
->blue_refs
[n
];
890 delta2
= FT_MulFix( delta2
, y_scale
);
894 else if ( delta2
< 64 )
895 delta2
= 32 + ( ( ( delta2
- 32 ) + 16 ) & -32 );
897 delta2
= ( delta2
+ 32 ) & -64;
902 scaled
->blue_refs
[n
] =
903 ( FT_MulFix( design
->blue_refs
[n
], y_scale
) + 32 ) & -64;
904 scaled
->blue_shoots
[n
] = scaled
->blue_refs
[n
] + delta2
;
907 globals
->x_scale
= x_scale
;
908 globals
->y_scale
= y_scale
;
913 void ah_hinter_align( AH_Hinter
* hinter
)
915 ah_hinter_align_edge_points( hinter
);
916 ah_hinter_align_points( hinter
);
920 /* finalize a hinter object */
921 void ah_hinter_done( AH_Hinter
* hinter
)
925 FT_Memory memory
= hinter
->memory
;
928 ah_loader_done( hinter
->loader
);
929 ah_outline_done( hinter
->glyph
);
931 /* note: the `globals' pointer is _not_ owned by the hinter */
932 /* but by the current face object, we don't need to */
942 /* create a new empty hinter object */
943 FT_Error
ah_hinter_new( FT_Library library
,
944 AH_Hinter
** ahinter
)
946 AH_Hinter
* hinter
= 0;
947 FT_Memory memory
= library
->memory
;
953 /* allocate object */
954 if ( ALLOC( hinter
, sizeof ( *hinter
) ) )
957 hinter
->memory
= memory
;
960 /* allocate outline and loader */
961 error
= ah_outline_new( memory
, &hinter
->glyph
) ||
962 ah_loader_new ( memory
, &hinter
->loader
) ||
963 ah_loader_create_extra( hinter
->loader
);
971 ah_hinter_done( hinter
);
977 /* create a face's autohint globals */
978 FT_Error
ah_hinter_new_face_globals( AH_Hinter
* hinter
,
980 AH_Globals
* globals
)
983 FT_Memory memory
= hinter
->memory
;
984 AH_Face_Globals
* face_globals
;
987 if ( ALLOC( face_globals
, sizeof ( *face_globals
) ) )
991 hinter
->globals
= face_globals
;
994 face_globals
->design
= *globals
;
996 ah_hinter_compute_globals( hinter
);
998 face
->autohint
.data
= face_globals
;
999 face
->autohint
.finalizer
= (FT_Generic_Finalizer
)
1000 ah_hinter_done_face_globals
;
1001 face_globals
->face
= face
;
1008 /* discard a face's autohint globals */
1009 void ah_hinter_done_face_globals( AH_Face_Globals
* globals
)
1011 FT_Face face
= globals
->face
;
1012 FT_Memory memory
= face
->memory
;
1020 FT_Error
ah_hinter_load( AH_Hinter
* hinter
,
1021 FT_UInt glyph_index
,
1025 FT_Face face
= hinter
->face
;
1026 FT_GlyphSlot slot
= face
->glyph
;
1027 FT_Fixed x_scale
= face
->size
->metrics
.x_scale
;
1028 FT_Fixed y_scale
= face
->size
->metrics
.y_scale
;
1029 FT_Glyph_Metrics metrics
; /* temporary metrics */
1031 AH_Outline
* outline
= hinter
->glyph
;
1032 AH_Loader
* gloader
= hinter
->loader
;
1033 FT_Bool no_horz_hints
=
1034 ( load_flags
& AH_HINT_NO_HORZ_EDGES
) != 0;
1035 FT_Bool no_vert_hints
=
1036 ( load_flags
& AH_HINT_NO_VERT_EDGES
) != 0;
1039 /* load the glyph */
1040 error
= FT_Load_Glyph( face
, glyph_index
, load_flags
);
1044 /* save current glyph metrics */
1045 metrics
= slot
->metrics
;
1047 switch ( slot
->format
)
1049 case ft_glyph_format_outline
:
1050 /* first of all, copy the outline points in the loader's current */
1051 /* extra points, which is used to keep original glyph coordinates */
1052 error
= ah_loader_check_points( gloader
, slot
->outline
.n_points
+ 2,
1053 slot
->outline
.n_contours
);
1057 MEM_Copy( gloader
->current
.extra_points
, slot
->outline
.points
,
1058 slot
->outline
.n_points
* sizeof ( FT_Vector
) );
1060 MEM_Copy( gloader
->current
.outline
.contours
, slot
->outline
.contours
,
1061 slot
->outline
.n_contours
* sizeof ( short ) );
1063 MEM_Copy( gloader
->current
.outline
.tags
, slot
->outline
.tags
,
1064 slot
->outline
.n_points
* sizeof ( char ) );
1066 gloader
->current
.outline
.n_points
= slot
->outline
.n_points
;
1067 gloader
->current
.outline
.n_contours
= slot
->outline
.n_contours
;
1069 /* compute original phantom points */
1072 hinter
->pp2
.x
= FT_MulFix( slot
->metrics
.horiAdvance
, x_scale
);
1075 /* be sure to check for spacing glyphs */
1076 if ( slot
->outline
.n_points
== 0 )
1079 /* now, load the slot image into the auto-outline, and run the */
1080 /* automatic hinting process */
1081 error
= ah_outline_load( outline
, face
); /* XXX: change to slot */
1085 /* perform feature detection */
1086 ah_outline_detect_features( outline
);
1088 if ( !no_horz_hints
)
1090 ah_outline_compute_blue_edges( outline
, hinter
->globals
);
1091 ah_outline_scale_blue_edges( outline
, hinter
->globals
);
1094 /* perform alignment control */
1095 ah_hinter_hint_edges( hinter
, no_horz_hints
, no_vert_hints
);
1096 ah_hinter_align( hinter
);
1098 /* now save the current outline into the loader's current table */
1099 ah_outline_save( outline
, gloader
);
1101 /* we now need to hint the metrics according to the change in */
1102 /* width/positioning that occured during the hinting process */
1104 FT_Pos old_width
, new_width
;
1105 FT_Pos old_advance
, new_advance
;
1106 FT_Pos old_lsb
, new_lsb
;
1107 AH_Edge
* edge1
= outline
->vert_edges
; /* leftmost edge */
1108 AH_Edge
* edge2
= edge1
+
1109 outline
->num_vedges
- 1; /* rightmost edge */
1112 old_width
= edge2
->opos
- edge1
->opos
;
1113 new_width
= edge2
->pos
- edge1
->pos
;
1115 old_advance
= hinter
->pp2
.x
;
1116 old_lsb
= edge1
->opos
;
1117 new_lsb
= edge1
->pos
;
1119 new_advance
= old_advance
+
1120 ( new_width
+ new_lsb
- old_width
- old_lsb
);
1122 hinter
->pp1
.x
= ( ( new_lsb
- old_lsb
) + 32 ) & -64;
1123 hinter
->pp2
.x
= ( ( edge2
->pos
+
1124 ( old_advance
- edge2
->opos
) ) + 32 ) & -64;
1127 /* good, we simply add the glyph to our loader's base */
1128 ah_loader_add( gloader
);
1131 case ft_glyph_format_composite
:
1133 FT_UInt nn
, num_subglyphs
= slot
->num_subglyphs
;
1134 FT_UInt num_base_subgs
, start_point
, start_contour
;
1135 FT_SubGlyph
* subglyph
;
1138 start_point
= gloader
->base
.outline
.n_points
;
1139 start_contour
= gloader
->base
.outline
.n_contours
;
1141 /* first of all, copy the subglyph descriptors in the glyph loader */
1142 error
= ah_loader_check_subglyphs( gloader
, num_subglyphs
);
1146 MEM_Copy( gloader
->current
.subglyphs
, slot
->subglyphs
,
1147 num_subglyphs
* sizeof ( FT_SubGlyph
) );
1149 gloader
->current
.num_subglyphs
= num_subglyphs
;
1150 num_base_subgs
= gloader
->base
.num_subglyphs
;
1152 /* now, read each subglyph independently */
1153 for ( nn
= 0; nn
< num_subglyphs
; nn
++ )
1157 FT_UInt num_points
, num_new_points
, num_base_points
;
1160 /* gloader.current.subglyphs can change during glyph loading due */
1161 /* to re-allocation -- we must recompute the current subglyph on */
1162 /* each iteration */
1163 subglyph
= gloader
->base
.subglyphs
+ num_base_subgs
+ nn
;
1168 num_base_points
= gloader
->base
.outline
.n_points
;
1170 error
= ah_hinter_load( hinter
, subglyph
->index
,
1171 load_flags
, depth
+ 1 );
1175 /* recompute subglyph pointer */
1176 subglyph
= gloader
->base
.subglyphs
+ num_base_subgs
+ nn
;
1178 if ( subglyph
->flags
& FT_SUBGLYPH_FLAG_USE_MY_METRICS
)
1189 num_points
= gloader
->base
.outline
.n_points
;
1190 num_new_points
= num_points
- num_base_points
;
1192 /* now perform the transform required for this subglyph */
1194 if ( subglyph
->flags
& ( FT_SUBGLYPH_FLAG_SCALE
|
1195 FT_SUBGLYPH_FLAG_XY_SCALE
|
1196 FT_SUBGLYPH_FLAG_2X2
) )
1198 FT_Vector
* cur
= gloader
->base
.outline
.points
+
1200 FT_Vector
* org
= gloader
->base
.extra_points
+
1202 FT_Vector
* limit
= cur
+ num_new_points
;
1205 for ( ; cur
< limit
; cur
++, org
++ )
1207 FT_Vector_Transform( cur
, &subglyph
->transform
);
1208 FT_Vector_Transform( org
, &subglyph
->transform
);
1214 if ( !( subglyph
->flags
& FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES
) )
1216 FT_Int k
= subglyph
->arg1
;
1217 FT_UInt l
= subglyph
->arg2
;
1222 if ( start_point
+ k
>= num_base_points
||
1223 l
>= (FT_UInt
)num_new_points
)
1225 error
= FT_Err_Invalid_Composite
;
1229 l
+= num_base_points
;
1231 /* for now, only use the current point coordinates */
1232 /* we may consider another approach in the near future */
1233 p1
= gloader
->base
.outline
.points
+ start_point
+ k
;
1234 p2
= gloader
->base
.outline
.points
+ start_point
+ l
;
1241 x
= FT_MulFix( subglyph
->arg1
, x_scale
);
1242 y
= FT_MulFix( subglyph
->arg2
, y_scale
);
1244 x
= ( x
+ 32 ) & -64;
1245 y
= ( y
+ 32 ) & -64;
1249 FT_Outline dummy
= gloader
->base
.outline
;
1252 dummy
.points
+= num_base_points
;
1253 dummy
.n_points
= num_new_points
;
1255 FT_Outline_Translate( &dummy
, x
, y
);
1262 /* we don't support other formats (yet?) */
1263 error
= FT_Err_Unimplemented_Feature
;
1272 /* we must translate our final outline by -pp1.x, and compute */
1273 /* the new metrics */
1274 if ( hinter
->pp1
.x
)
1275 FT_Outline_Translate( &gloader
->base
.outline
, -hinter
->pp1
.x
, 0 );
1277 FT_Outline_Get_CBox( &gloader
->base
.outline
, &bbox
);
1280 bbox
.xMax
= ( bbox
.xMax
+ 63 ) & -64;
1281 bbox
.yMax
= ( bbox
.yMax
+ 63 ) & -64;
1283 slot
->metrics
.width
= bbox
.xMax
- bbox
.xMin
;
1284 slot
->metrics
.height
= bbox
.yMax
- bbox
.yMin
;
1285 slot
->metrics
.horiBearingX
= bbox
.xMin
;
1286 slot
->metrics
.horiBearingY
= bbox
.yMax
;
1287 slot
->metrics
.horiAdvance
= hinter
->pp2
.x
- hinter
->pp1
.x
;
1288 /* XXX: TO DO - slot->linearHoriAdvance */
1290 /* now copy outline into glyph slot */
1291 ah_loader_rewind( slot
->loader
);
1292 error
= ah_loader_copy_points( slot
->loader
, gloader
);
1296 slot
->outline
= slot
->loader
->base
.outline
;
1297 slot
->format
= ft_glyph_format_outline
;
1305 /* load and hint a given glyph */
1306 FT_Error
ah_hinter_load_glyph( AH_Hinter
* hinter
,
1309 FT_UInt glyph_index
,
1312 FT_Face face
= slot
->face
;
1314 FT_Fixed x_scale
= size
->metrics
.x_scale
;
1315 FT_Fixed y_scale
= size
->metrics
.y_scale
;
1316 AH_Face_Globals
* face_globals
= FACE_GLOBALS( face
);
1319 /* first of all, we need to check that we're using the correct face and */
1320 /* global hints to load the glyph */
1321 if ( hinter
->face
!= face
|| hinter
->globals
!= face_globals
)
1323 hinter
->face
= face
;
1324 if ( !face_globals
)
1326 error
= ah_hinter_new_face_globals( hinter
, face
, 0 );
1330 hinter
->globals
= FACE_GLOBALS( face
);
1331 face_globals
= FACE_GLOBALS( face
);
1334 /* now, we must check the current character pixel size to see if we */
1335 /* need to rescale the global metrics */
1336 if ( face_globals
->x_scale
!= x_scale
||
1337 face_globals
->y_scale
!= y_scale
)
1338 ah_hinter_scale_globals( hinter
, x_scale
, y_scale
);
1340 load_flags
|= FT_LOAD_NO_SCALE
| FT_LOAD_NO_RECURSE
;
1342 ah_loader_rewind( hinter
->loader
);
1344 error
= ah_hinter_load( hinter
, glyph_index
, load_flags
, 0 );
1351 /* retrieve a face's autohint globals for client applications */
1352 void ah_hinter_get_global_hints( AH_Hinter
* hinter
,
1354 void** global_hints
,
1357 AH_Globals
* globals
= 0;
1358 FT_Memory memory
= hinter
->memory
;
1362 /* allocate new master globals */
1363 if ( ALLOC( globals
, sizeof ( *globals
) ) )
1366 /* compute face globals if needed */
1367 if ( !FACE_GLOBALS( face
) )
1369 error
= ah_hinter_new_face_globals( hinter
, face
, 0 );
1374 *globals
= FACE_GLOBALS( face
)->design
;
1375 *global_hints
= globals
;
1376 *global_len
= sizeof( *globals
);
1388 void ah_hinter_done_global_hints( AH_Hinter
* hinter
,
1389 void* global_hints
)
1391 FT_Memory memory
= hinter
->memory
;
1394 FREE( global_hints
);