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 */ 287