The BIG graph update
[rrdtool.git] / libraries / freetype-2.0.5 / 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_SYNTHESIS_H
24
25
26 #define FT_BOLD_THRESHOLD  0x0100
27
28
29   /*************************************************************************/
30   /*************************************************************************/
31   /****                                                                 ****/
32   /****   EXPERIMENTAL OBLIQUING SUPPORT                                ****/
33   /****                                                                 ****/
34   /*************************************************************************/
35   /*************************************************************************/
36
37   FT_EXPORT_DEF( FT_Error )
38   FT_Outline_Oblique( FT_GlyphSlot  original,
39                       FT_Outline*   outline,
40                       FT_Pos*       advance )
41   {
42     FT_Matrix  transform;
43
44     FT_UNUSED( original );
45     /* we don't touch the advance width */
46     FT_UNUSED( advance );
47
48
49
50     /* For italic, simply apply a shear transform, with an angle */
51     /* of about 12 degrees.                                      */
52
53     transform.xx = 0x10000L;
54     transform.yx = 0x00000L;
55
56     transform.xy = 0x06000L;
57     transform.yy = 0x10000L;
58
59     FT_Outline_Transform( outline, &transform );
60
61     return 0;
62   }
63
64
65   /*************************************************************************/
66   /*************************************************************************/
67   /****                                                                 ****/
68   /****   EXPERIMENTAL EMBOLDENING/OUTLINING SUPPORT                    ****/
69   /****                                                                 ****/
70   /*************************************************************************/
71   /*************************************************************************/
72
73
74   /* Compute the norm of a vector */
75
76 #ifdef FT_CONFIG_OPTION_OLD_CALCS
77
78   static FT_Pos
79   ft_norm( FT_Vector*  vec )
80   {
81     FT_Int64  t1, t2;
82
83
84     MUL_64( vec->x, vec->x, t1 );
85     MUL_64( vec->y, vec->y, t2 );
86     ADD_64( t1, t2, t1 );
87
88     return (FT_Pos)SQRT_64( t1 );
89   }
90
91 #else /* FT_CONFIG_OPTION_OLD_CALCS */
92
93   static FT_Pos
94   ft_norm( FT_Vector*  vec )
95   {
96     FT_F26Dot6  u, v, d;
97     FT_Int      shift;
98     FT_ULong    H, L, L2, hi, lo, med;
99
100
101     u = vec->x; if ( u < 0 ) u = -u;
102     v = vec->y; if ( v < 0 ) v = -v;
103
104     if ( u < v )
105     {
106       d = u;
107       u = v;
108       v = d;
109     }
110
111     /* check that we are not trying to normalize zero! */
112     if ( u == 0 )
113       return 0;
114
115     /* compute (u*u + v*v) on 64 bits with two 32-bit registers [H:L] */
116     hi  = (FT_ULong)u >> 16;
117     lo  = (FT_ULong)u & 0xFFFF;
118     med = hi * lo;
119
120     H     = hi * hi + ( med >> 15 );
121     med <<= 17;
122     L     = lo * lo + med;
123     if ( L < med )
124       H++;
125
126     hi  = (FT_ULong)v >> 16;
127     lo  = (FT_ULong)v & 0xFFFF;
128     med = hi * lo;
129
130     H    += hi * hi + ( med >> 15 );
131     med <<= 17;
132     L2    = lo * lo + med;
133     if ( L2 < med )
134       H++;
135
136     L += L2;
137     if ( L < L2 )
138       H++;
139
140     /* if the value is smaller than 32 bits */
141     shift = 0;
142     if ( H == 0 )
143     {
144       while ( ( L & 0xC0000000UL ) == 0 )
145       {
146         L <<= 2;
147         shift++;
148       }
149       return ( FT_Sqrt32( L ) >> shift );
150     }
151     else
152     {
153       while ( H )
154       {
155         L   = ( L >> 2 ) | ( H << 30 );
156         H >>= 2;
157         shift++;
158       }
159       return ( FT_Sqrt32( L ) << shift );
160     }
161   }
162
163 #endif /* FT_CONFIG_OPTION_OLD_CALCS */
164
165
166   static int
167   ft_test_extrema( FT_Outline*  outline,
168                    int          n )
169   {
170     FT_Vector  *prev, *cur, *next;
171     FT_Pos      product;
172     FT_Int      c, first, last;
173
174
175     /* we need to compute the `previous' and `next' point */
176     /* for these extrema.                                 */
177     cur   = outline->points + n;
178     prev  = cur - 1;
179     next  = cur + 1;
180
181     first = 0;
182     for ( c = 0; c < outline->n_contours; c++ )
183     {
184       last  = outline->contours[c];
185
186       if ( n == first )
187         prev = outline->points + last;
188
189       if ( n == last )
190         next = outline->points + first;
191
192       first = last + 1;
193     }
194
195     product = FT_MulDiv( cur->x - prev->x,   /* in.x  */
196                          next->y - cur->y,   /* out.y */
197                          0x40 )
198               -
199               FT_MulDiv( cur->y - prev->y,   /* in.y  */
200                          next->x - cur->x,   /* out.x */
201                          0x40 );
202
203     if ( product )
204       product = product > 0 ? 1 : -1;
205
206     return product;
207   }
208
209
210   /* Compute the orientation of path filling.  It differs between TrueType */
211   /* and Type1 formats.  We could use the `ft_outline_reverse_fill' flag,  */
212   /* but it is better to re-compute it directly (it seems that this flag   */
213   /* isn't correctly set for some weird composite glyphs currently).       */
214   /*                                                                       */
215   /* We do this by computing bounding box points, and computing their      */
216   /* curvature.                                                            */
217   /*                                                                       */
218   /* The function returns either 1 or -1.                                  */
219   /*                                                                       */
220   static int
221   ft_get_orientation( FT_Outline*  outline )
222   {
223     FT_BBox  box;
224     FT_BBox  indices;
225     int      n, last;
226
227
228     indices.xMin = -1;
229     indices.yMin = -1;
230     indices.xMax = -1;
231     indices.yMax = -1;
232
233     box.xMin = box.yMin =  32767;
234     box.xMax = box.yMax = -32768;
235
236     /* is it empty ? */
237     if ( outline->n_contours < 1 )
238       return 1;
239
240     last = outline->contours[outline->n_contours - 1];
241
242     for ( n = 0; n <= last; n++ )
243     {
244       FT_Pos  x, y;
245
246
247       x = outline->points[n].x;
248       if ( x < box.xMin )
249       {
250         box.xMin     = x;
251         indices.xMin = n;
252       }
253       if ( x > box.xMax )
254       {
255         box.xMax     = x;
256         indices.xMax = n;
257       }
258
259       y = outline->points[n].y;
260       if ( y < box.yMin )
261       {
262         box.yMin     = y;
263         indices.yMin = n;
264       }
265       if ( y > box.yMax )
266       {
267         box.yMax     = y;
268         indices.yMax = n;
269       }
270     }
271
272     /* test orientation of the xmin */
273     n = ft_test_extrema( outline, indices.xMin );
274     if ( n )
275       goto Exit;
276
277     n = ft_test_extrema( outline, indices.yMin );
278     if ( n )
279       goto Exit;
280
281     n = ft_test_extrema( outline, indices.xMax );
282     if ( n )
283       goto Exit;
284
285     n = ft_test_extrema( outline, indices.yMax );
286     if ( !n )
287       n = 1;
288
289   Exit:
290     return n;
291   }
292
293
294   FT_EXPORT_DEF( FT_Error )
295   FT_Outline_Embolden( FT_GlyphSlot original,
296                        FT_Outline*  outline,
297                        FT_Pos*      advance )
298   {
299     FT_Vector   u, v;
300     FT_Vector*  points;
301     FT_Vector   cur, prev, next;
302     FT_Pos      distance;
303     FT_Face     face = FT_SLOT_FACE( original );
304     int         c, n, first, orientation;
305
306     FT_UNUSED( advance );
307
308
309     /* compute control distance */
310     distance = FT_MulFix( face->units_per_EM / 60,
311                           face->size->metrics.y_scale );
312
313     orientation = ft_get_orientation( &original->outline );
314
315     points = original->outline.points;
316
317     first = 0;
318     for ( c = 0; c < outline->n_contours; c++ )
319     {
320       int  last = outline->contours[c];
321
322
323       prev = points[last];
324
325       for ( n = first; n <= last; n++ )
326       {
327         FT_Pos     norm, delta, d;
328         FT_Vector  in, out;
329
330
331         cur = points[n];
332         if ( n < last ) next = points[n + 1];
333         else            next = points[first];
334
335         /* compute the in and out vectors */
336         in.x  = cur.x - prev.x;
337         in.y  = cur.y - prev.y;
338
339         out.x = next.x - cur.x;
340         out.y = next.y - cur.y;
341
342         /* compute U and V */
343         norm = ft_norm( &in );
344         u.x = orientation *  FT_DivFix( in.y, norm );
345         u.y = orientation * -FT_DivFix( in.x, norm );
346
347         norm = ft_norm( &out );
348         v.x = orientation *  FT_DivFix( out.y, norm );
349         v.y = orientation * -FT_DivFix( out.x, norm );
350
351         d = distance;
352
353         if ( ( outline->tags[n] & FT_Curve_Tag_On ) == 0 )
354           d *= 2;
355
356         /* Check discriminant for parallel vectors */
357         delta = FT_MulFix( u.x, v.y ) - FT_MulFix( u.y, v.x );
358         if ( delta > FT_BOLD_THRESHOLD || delta < -FT_BOLD_THRESHOLD )
359         {
360           /* Move point -- compute A and B */
361           FT_Pos  x, y, A, B;
362
363
364           A = d + FT_MulFix( cur.x, u.x ) + FT_MulFix( cur.y, u.y );
365           B = d + FT_MulFix( cur.x, v.x ) + FT_MulFix( cur.y, v.y );
366
367           x = FT_MulFix( A, v.y ) - FT_MulFix( B, u.y );
368           y = FT_MulFix( B, u.x ) - FT_MulFix( A, v.x );
369
370           outline->points[n].x = distance + FT_DivFix( x, delta );
371           outline->points[n].y = distance + FT_DivFix( y, delta );
372         }
373         else
374         {
375           /* Vectors are nearly parallel */
376           FT_Pos  x, y;
377
378
379           x = distance + cur.x + FT_MulFix( d, u.x + v.x ) / 2;
380           y = distance + cur.y + FT_MulFix( d, u.y + v.y ) / 2;
381
382           outline->points[n].x = x;
383           outline->points[n].y = y;
384         }
385
386         prev = cur;
387       }
388
389       first = last + 1;
390     }
391
392     if ( advance )
393       *advance = ( *advance + distance * 4 ) & -64;
394
395     return 0;
396   }
397
398
399 /* END */