update for HEAD-2003050101
[reactos.git] / lib / freetype / src / base / ftsynth.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ftsynth.c                                                              */
4 /*                                                                         */
5 /*    FreeType synthesizing code for emboldening and slanting (body).      */
6 /*                                                                         */
7 /*  Copyright 2000-2001 by                                                 */
8 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9 /*                                                                         */
10 /*  This file is part of the FreeType project, and may only be used,       */
11 /*  modified, and distributed under the terms of the FreeType project      */
12 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13 /*  this file you indicate that you have read the license and              */
14 /*  understand and accept it fully.                                        */
15 /*                                                                         */
16 /***************************************************************************/
17
18
19 #include <ft2build.h>
20 #include FT_INTERNAL_OBJECTS_H
21 #include FT_INTERNAL_CALC_H
22 #include FT_OUTLINE_H
23 #include FT_TRIGONOMETRY_H
24 #include FT_SYNTHESIS_H
25
26
27 #define FT_BOLD_THRESHOLD  0x0100
28
29
30   /*************************************************************************/
31   /*************************************************************************/
32   /****                                                                 ****/
33   /****   EXPERIMENTAL OBLIQUING SUPPORT                                ****/
34   /****                                                                 ****/
35   /*************************************************************************/
36   /*************************************************************************/
37
38   FT_EXPORT_DEF( void )
39   FT_GlyphSlot_Oblique( FT_GlyphSlot  slot )
40   {
41     FT_Matrix    transform;
42     FT_Outline*  outline = &slot->outline;
43
44
45     /* only oblique outline glyphs */
46     if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
47       return;
48
49     /* we don't touch the advance width */
50
51     /* For italic, simply apply a shear transform, with an angle */
52     /* of about 12 degrees.                                      */
53
54     transform.xx = 0x10000L;
55     transform.yx = 0x00000L;
56
57     transform.xy = 0x06000L;
58     transform.yy = 0x10000L;
59
60     FT_Outline_Transform( outline, &transform );
61   }
62
63
64   /*************************************************************************/
65   /*************************************************************************/
66   /****                                                                 ****/
67   /****   EXPERIMENTAL EMBOLDENING/OUTLINING SUPPORT                    ****/
68   /****                                                                 ****/
69   /*************************************************************************/
70   /*************************************************************************/
71
72
73
74   static int
75   ft_test_extrema( FT_Outline*  outline,
76                    int          n )
77   {
78     FT_Vector  *prev, *cur, *next;
79     FT_Pos      product;
80     FT_Int      c, first, last;
81
82
83     /* we need to compute the `previous' and `next' point */
84     /* for these extrema.                                 */
85     cur   = outline->points + n;
86     prev  = cur - 1;
87     next  = cur + 1;
88
89     first = 0;
90     for ( c = 0; c < outline->n_contours; c++ )
91     {
92       last  = outline->contours[c];
93
94       if ( n == first )
95         prev = outline->points + last;
96
97       if ( n == last )
98         next = outline->points + first;
99
100       first = last + 1;
101     }
102
103     product = FT_MulDiv( cur->x - prev->x,   /* in.x  */
104                          next->y - cur->y,   /* out.y */
105                          0x40 )
106               -
107               FT_MulDiv( cur->y - prev->y,   /* in.y  */
108                          next->x - cur->x,   /* out.x */
109                          0x40 );
110
111     if ( product )
112       product = product > 0 ? 1 : -1;
113
114     return product;
115   }
116
117
118   /* Compute the orientation of path filling.  It differs between TrueType */
119   /* and Type1 formats.  We could use the `FT_OUTLINE_REVERSE_FILL' flag,  */
120   /* but it is better to re-compute it directly (it seems that this flag   */
121   /* isn't correctly set for some weird composite glyphs currently).       */
122   /*                                                                       */
123   /* We do this by computing bounding box points, and computing their      */
124   /* curvature.                                                            */
125   /*                                                                       */
126   /* The function returns either 1 or -1.                                  */
127   /*                                                                       */
128   static int
129   ft_get_orientation( FT_Outline*  outline )
130   {
131     FT_BBox  box;
132     FT_BBox  indices;
133     int      n, last;
134
135
136     indices.xMin = -1;
137     indices.yMin = -1;
138     indices.xMax = -1;
139     indices.yMax = -1;
140
141     box.xMin = box.yMin =  32767;
142     box.xMax = box.yMax = -32768;
143
144     /* is it empty ? */
145     if ( outline->n_contours < 1 )
146       return 1;
147
148     last = outline->contours[outline->n_contours - 1];
149
150     for ( n = 0; n <= last; n++ )
151     {
152       FT_Pos  x, y;
153
154
155       x = outline->points[n].x;
156       if ( x < box.xMin )
157       {
158         box.xMin     = x;
159         indices.xMin = n;
160       }
161       if ( x > box.xMax )
162       {
163         box.xMax     = x;
164         indices.xMax = n;
165       }
166
167       y = outline->points[n].y;
168       if ( y < box.yMin )
169       {
170         box.yMin     = y;
171         indices.yMin = n;
172       }
173       if ( y > box.yMax )
174       {
175         box.yMax     = y;
176         indices.yMax = n;
177       }
178     }
179
180     /* test orientation of the xmin */
181     n = ft_test_extrema( outline, indices.xMin );
182     if ( n )
183       goto Exit;
184
185     n = ft_test_extrema( outline, indices.yMin );
186     if ( n )
187       goto Exit;
188
189     n = ft_test_extrema( outline, indices.xMax );
190     if ( n )
191       goto Exit;
192
193     n = ft_test_extrema( outline, indices.yMax );
194     if ( !n )
195       n = 1;
196
197   Exit:
198     return n;
199   }
200
201
202   FT_EXPORT_DEF( void )
203   FT_GlyphSlot_Embolden( FT_GlyphSlot  slot )
204   {
205     FT_Vector*   points;
206     FT_Vector    v_prev, v_first, v_next, v_cur;
207     FT_Pos       distance;
208     FT_Outline*  outline = &slot->outline;
209     FT_Face      face = FT_SLOT_FACE( slot );
210     FT_Angle     rotate, angle_in, angle_out;
211     FT_Int       c, n, first, orientation;
212
213
214     /* only embolden outline glyph images */
215     if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
216       return;
217
218     /* compute control distance */
219     distance = FT_MulFix( face->units_per_EM / 60,
220                           face->size->metrics.y_scale );
221
222     orientation = ft_get_orientation( outline );
223     rotate      = FT_ANGLE_PI2*orientation;
224
225     points = outline->points;
226
227     first = 0;
228     for ( c = 0; c < outline->n_contours; c++ )
229     {
230       int  last = outline->contours[c];
231
232
233       v_first = points[first];
234       v_prev  = points[last];
235       v_cur   = v_first;
236
237       for ( n = first; n <= last; n++ )
238       {
239         FT_Pos     d;
240         FT_Vector  in, out;
241         FT_Fixed   scale;
242         FT_Angle   angle_diff;
243
244
245         if ( n < last ) v_next = points[n + 1];
246         else            v_next = v_first;
247
248         /* compute the in and out vectors */
249         in.x  = v_cur.x - v_prev.x;
250         in.y  = v_cur.y - v_prev.y;
251
252         out.x = v_next.x - v_cur.x;
253         out.y = v_next.y - v_cur.y;
254
255         angle_in   = FT_Atan2( in.x, in.y );
256         angle_out  = FT_Atan2( out.x, out.y );
257         angle_diff = FT_Angle_Diff( angle_in, angle_out );
258         scale      = FT_Cos( angle_diff/2 );
259
260         if ( scale < 0x400L && scale > -0x400L )
261         {
262           if ( scale >= 0 )
263             scale = 0x400L;
264           else
265             scale = -0x400L;
266         }
267
268         d = FT_DivFix( distance, scale );
269
270         FT_Vector_From_Polar( &in, d, angle_in + angle_diff/2 - rotate );
271
272         outline->points[n].x = v_cur.x + distance + in.x;
273         outline->points[n].y = v_cur.y + distance + in.y;
274
275         v_prev = v_cur;
276         v_cur  = v_next;
277       }
278
279       first = last + 1;
280     }
281
282     slot->metrics.horiAdvance = ( slot->metrics.horiAdvance + distance*4 ) & -64;
283   }
284
285
286 /* END */