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 /***************************************************************************/
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
26 #define FT_BOLD_THRESHOLD 0x0100
29 /*************************************************************************/
30 /*************************************************************************/
31 /**** ****/
32 /**** EXPERIMENTAL OBLIQUING SUPPORT ****/
33 /**** ****/
34 /*************************************************************************/
35 /*************************************************************************/
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;
44 FT_UNUSED( original );
45 /* we don't touch the advance width */
46 FT_UNUSED( advance );
50 /* For italic, simply apply a shear transform, with an angle */
51 /* of about 12 degrees. */
53 transform.xx = 0x10000L;
54 transform.yx = 0x00000L;
56 transform.xy = 0x06000L;
57 transform.yy = 0x10000L;
59 FT_Outline_Transform( outline, &transform );
61 return 0;
62 }
65 /*************************************************************************/
66 /*************************************************************************/
67 /**** ****/
68 /**** EXPERIMENTAL EMBOLDENING/OUTLINING SUPPORT ****/
69 /**** ****/
70 /*************************************************************************/
71 /*************************************************************************/
74 /* Compute the norm of a vector */
76 #ifdef FT_CONFIG_OPTION_OLD_CALCS
78 static FT_Pos
79 ft_norm( FT_Vector* vec )
80 {
81 FT_Int64 t1, t2;
84 MUL_64( vec->x, vec->x, t1 );
85 MUL_64( vec->y, vec->y, t2 );
86 ADD_64( t1, t2, t1 );
88 return (FT_Pos)SQRT_64( t1 );
89 }
91 #else /* FT_CONFIG_OPTION_OLD_CALCS */
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;
101 u = vec->x; if ( u < 0 ) u = -u;
102 v = vec->y; if ( v < 0 ) v = -v;
104 if ( u < v )
105 {
106 d = u;
107 u = v;
108 v = d;
109 }
111 /* check that we are not trying to normalize zero! */
112 if ( u == 0 )
113 return 0;
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;
120 H = hi * hi + ( med >> 15 );
121 med <<= 17;
122 L = lo * lo + med;
123 if ( L < med )
124 H++;
126 hi = (FT_ULong)v >> 16;
127 lo = (FT_ULong)v & 0xFFFF;
128 med = hi * lo;
130 H += hi * hi + ( med >> 15 );
131 med <<= 17;
132 L2 = lo * lo + med;
133 if ( L2 < med )
134 H++;
136 L += L2;
137 if ( L < L2 )
138 H++;
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 }
163 #endif /* FT_CONFIG_OPTION_OLD_CALCS */
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;
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;
181 first = 0;
182 for ( c = 0; c < outline->n_contours; c++ )
183 {
184 last = outline->contours[c];
186 if ( n == first )
187 prev = outline->points + last;
189 if ( n == last )
190 next = outline->points + first;
192 first = last + 1;
193 }
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 );
203 if ( product )
204 product = product > 0 ? 1 : -1;
206 return product;
207 }
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;
228 indices.xMin = -1;
229 indices.yMin = -1;
230 indices.xMax = -1;
231 indices.yMax = -1;
233 box.xMin = box.yMin = 32767;
234 box.xMax = box.yMax = -32768;
236 /* is it empty ? */
237 if ( outline->n_contours < 1 )
238 return 1;
240 last = outline->contours[outline->n_contours - 1];
242 for ( n = 0; n <= last; n++ )
243 {
244 FT_Pos x, y;
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 }
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 }
272 /* test orientation of the xmin */
273 n = ft_test_extrema( outline, indices.xMin );
274 if ( n )
275 goto Exit;
277 n = ft_test_extrema( outline, indices.yMin );
278 if ( n )
279 goto Exit;
281 n = ft_test_extrema( outline, indices.xMax );
282 if ( n )
283 goto Exit;
285 n = ft_test_extrema( outline, indices.yMax );
286 if ( !n )
287 n = 1;
289 Exit:
290 return n;
291 }
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;
306 FT_UNUSED( advance );
309 /* compute control distance */
310 distance = FT_MulFix( face->units_per_EM / 60,
311 face->size->metrics.y_scale );
313 orientation = ft_get_orientation( &original->outline );
315 points = original->outline.points;
317 first = 0;
318 for ( c = 0; c < outline->n_contours; c++ )
319 {
320 int last = outline->contours[c];
323 prev = points[last];
325 for ( n = first; n <= last; n++ )
326 {
327 FT_Pos norm, delta, d;
328 FT_Vector in, out;
331 cur = points[n];
332 if ( n < last ) next = points[n + 1];
333 else next = points[first];
335 /* compute the in and out vectors */
336 in.x = cur.x - prev.x;
337 in.y = cur.y - prev.y;
339 out.x = next.x - cur.x;
340 out.y = next.y - cur.y;
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 );
347 norm = ft_norm( &out );
348 v.x = orientation * FT_DivFix( out.y, norm );
349 v.y = orientation * -FT_DivFix( out.x, norm );
351 d = distance;
353 if ( ( outline->tags[n] & FT_Curve_Tag_On ) == 0 )
354 d *= 2;
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;
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 );
367 x = FT_MulFix( A, v.y ) - FT_MulFix( B, u.y );
368 y = FT_MulFix( B, u.x ) - FT_MulFix( A, v.x );
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;
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;
382 outline->points[n].x = x;
383 outline->points[n].y = y;
384 }
386 prev = cur;
387 }
389 first = last + 1;
390 }
392 if ( advance )
393 *advance = ( *advance + distance * 4 ) & -64;
395 return 0;
396 }
399 /* END */