David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1 | /***************************************************************************/ |
| 2 | /* */ |
| 3 | /* ahglyph.c */ |
| 4 | /* */ |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 5 | /* Routines used to load and analyze a given glyph before hinting */ |
| 6 | /* (body). */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 7 | /* */ |
Werner Lemberg | 415235d | 2001-06-28 17:49:10 +0000 | [diff] [blame] | 8 | /* Copyright 2000-2001 Catharon Productions Inc. */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 9 | /* Author: David Turner */ |
| 10 | /* */ |
| 11 | /* This file is part of the Catharon Typography Project and shall only */ |
| 12 | /* be used, modified, and distributed under the terms of the Catharon */ |
| 13 | /* Open Source License that should come with this file under the name */ |
Werner Lemberg | c3dd151 | 2000-07-26 14:11:15 +0000 | [diff] [blame] | 14 | /* `CatharonLicense.txt'. By continuing to use, modify, or distribute */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 15 | /* this file you indicate that you have read the license and */ |
| 16 | /* understand and accept it fully. */ |
| 17 | /* */ |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 18 | /* Note that this license is compatible with the FreeType license. */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 19 | /* */ |
| 20 | /***************************************************************************/ |
| 21 | |
Werner Lemberg | cc069be | 2000-12-08 16:17:16 +0000 | [diff] [blame] | 22 | |
| 23 | #include <ft2build.h> |
David Turner | 8d3a401 | 2001-03-20 11:14:24 +0000 | [diff] [blame] | 24 | #include "ahglyph.h" |
| 25 | #include "ahangles.h" |
| 26 | #include "ahglobal.h" |
Werner Lemberg | 1f7f0e8 | 2001-06-06 17:30:41 +0000 | [diff] [blame] | 27 | #include "aherrors.h" |
Werner Lemberg | cc069be | 2000-12-08 16:17:16 +0000 | [diff] [blame] | 28 | |
| 29 | #include <stdio.h> |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 30 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 31 | |
David Turner | 66cb479 | 2001-05-14 14:04:23 +0000 | [diff] [blame] | 32 | #ifdef AH_DEBUG |
| 33 | |
Werner Lemberg | f814d0f | 2001-06-27 16:18:10 +0000 | [diff] [blame] | 34 | void |
| 35 | ah_dump_edges( AH_Outline* outline ) |
David Turner | 66cb479 | 2001-05-14 14:04:23 +0000 | [diff] [blame] | 36 | { |
| 37 | AH_Edge* edges; |
| 38 | AH_Edge* edge_limit; |
| 39 | AH_Segment* segments; |
| 40 | FT_Int dimension; |
| 41 | |
David Turner | 66cb479 | 2001-05-14 14:04:23 +0000 | [diff] [blame] | 42 | edges = outline->horz_edges; |
| 43 | edge_limit = edges + outline->num_hedges; |
| 44 | segments = outline->horz_segments; |
| 45 | |
| 46 | for ( dimension = 1; dimension >= 0; dimension-- ) |
| 47 | { |
| 48 | AH_Edge* edge; |
| 49 | |
| 50 | |
| 51 | printf ( "Table of %s edges:\n", |
| 52 | !dimension ? "vertical" : "horizontal" ); |
| 53 | printf ( " [ index | pos | dir | link |" |
| 54 | " serif | blue | opos | pos ]\n" ); |
| 55 | |
| 56 | for ( edge = edges; edge < edge_limit; edge++ ) |
| 57 | { |
| 58 | printf ( " [ %5d | %4d | %5s | %4d | %5d | %c | %5.2f | %5.2f ]\n", |
| 59 | edge - edges, |
| 60 | (int)edge->fpos, |
| 61 | edge->dir == ah_dir_up |
| 62 | ? "up" |
| 63 | : ( edge->dir == ah_dir_down |
| 64 | ? "down" |
| 65 | : ( edge->dir == ah_dir_left |
| 66 | ? "left" |
| 67 | : ( edge->dir == ah_dir_right |
| 68 | ? "right" |
| 69 | : "none" ) ) ), |
| 70 | edge->link ? ( edge->link - edges ) : -1, |
| 71 | edge->serif ? ( edge->serif - edges ) : -1, |
| 72 | edge->blue_edge ? 'y' : 'n', |
| 73 | edge->opos / 64.0, |
| 74 | edge->pos / 64.0 ); |
| 75 | } |
| 76 | |
| 77 | edges = outline->vert_edges; |
| 78 | edge_limit = edges + outline->num_vedges; |
| 79 | segments = outline->vert_segments; |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | |
| 84 | /* A function used to dump the array of linked segments */ |
Werner Lemberg | f814d0f | 2001-06-27 16:18:10 +0000 | [diff] [blame] | 85 | void |
| 86 | ah_dump_segments( AH_Outline* outline ) |
David Turner | 66cb479 | 2001-05-14 14:04:23 +0000 | [diff] [blame] | 87 | { |
| 88 | AH_Segment* segments; |
| 89 | AH_Segment* segment_limit; |
| 90 | AH_Point* points; |
| 91 | FT_Int dimension; |
| 92 | |
| 93 | |
| 94 | points = outline->points; |
| 95 | segments = outline->horz_segments; |
| 96 | segment_limit = segments + outline->num_hsegments; |
| 97 | |
| 98 | for ( dimension = 1; dimension >= 0; dimension-- ) |
| 99 | { |
| 100 | AH_Segment* seg; |
| 101 | |
| 102 | |
| 103 | printf ( "Table of %s segments:\n", |
| 104 | !dimension ? "vertical" : "horizontal" ); |
| 105 | printf ( " [ index | pos | dir | link | serif |" |
| 106 | " numl | first | start ]\n" ); |
| 107 | |
| 108 | for ( seg = segments; seg < segment_limit; seg++ ) |
| 109 | { |
| 110 | printf ( " [ %5d | %4d | %5s | %4d | %5d | %4d | %5d | %5d ]\n", |
| 111 | seg - segments, |
| 112 | (int)seg->pos, |
| 113 | seg->dir == ah_dir_up |
| 114 | ? "up" |
| 115 | : ( seg->dir == ah_dir_down |
| 116 | ? "down" |
| 117 | : ( seg->dir == ah_dir_left |
| 118 | ? "left" |
| 119 | : ( seg->dir == ah_dir_right |
| 120 | ? "right" |
| 121 | : "none" ) ) ), |
| 122 | seg->link ? (seg->link-segments) : -1, |
| 123 | seg->serif ? (seg->serif-segments) : -1, |
| 124 | (int)seg->num_linked, |
| 125 | seg->first - points, |
| 126 | seg->last - points ); |
| 127 | } |
| 128 | |
| 129 | segments = outline->vert_segments; |
| 130 | segment_limit = segments + outline->num_vsegments; |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | #endif /* AH_DEBUG */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 135 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 136 | |
| 137 | /* compute the direction value of a given vector.. */ |
Werner Lemberg | f814d0f | 2001-06-27 16:18:10 +0000 | [diff] [blame] | 138 | static AH_Direction |
| 139 | ah_compute_direction( FT_Pos dx, |
| 140 | FT_Pos dy ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 141 | { |
| 142 | AH_Direction dir; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 143 | FT_Pos ax = ABS( dx ); |
| 144 | FT_Pos ay = ABS( dy ); |
| 145 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 146 | |
| 147 | dir = ah_dir_none; |
| 148 | |
| 149 | /* test for vertical direction */ |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 150 | if ( ax * 12 < ay ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 151 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 152 | dir = dy > 0 ? ah_dir_up : ah_dir_down; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 153 | } |
| 154 | /* test for horizontal direction */ |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 155 | else if ( ay * 12 < ax ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 156 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 157 | dir = dx > 0 ? ah_dir_right : ah_dir_left; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 158 | } |
| 159 | |
| 160 | return dir; |
| 161 | } |
| 162 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 163 | |
David Turner | 666b11d | 2000-07-27 15:59:08 +0000 | [diff] [blame] | 164 | /* this function is used by ah_get_orientation (see below) to test */ |
Werner Lemberg | c703b1b | 2000-07-27 16:57:35 +0000 | [diff] [blame] | 165 | /* the fill direction of a given bbox extrema */ |
Werner Lemberg | f814d0f | 2001-06-27 16:18:10 +0000 | [diff] [blame] | 166 | static int |
| 167 | ah_test_extrema( FT_Outline* outline, |
| 168 | int n ) |
David Turner | 666b11d | 2000-07-27 15:59:08 +0000 | [diff] [blame] | 169 | { |
| 170 | FT_Vector *prev, *cur, *next; |
| 171 | FT_Pos product; |
| 172 | FT_Int first, last, c; |
| 173 | |
| 174 | |
| 175 | /* we need to compute the `previous' and `next' point */ |
Werner Lemberg | c703b1b | 2000-07-27 16:57:35 +0000 | [diff] [blame] | 176 | /* for these extrema */ |
| 177 | cur = outline->points + n; |
| 178 | prev = cur - 1; |
| 179 | next = cur + 1; |
David Turner | 666b11d | 2000-07-27 15:59:08 +0000 | [diff] [blame] | 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 ? 2 : 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 | /* */ |
Werner Lemberg | f814d0f | 2001-06-27 16:18:10 +0000 | [diff] [blame] | 220 | static int |
| 221 | ah_get_orientation( FT_Outline* outline ) |
David Turner | 666b11d | 2000-07-27 15:59:08 +0000 | [diff] [blame] | 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 | |
Werner Lemberg | cf24d51 | 2001-06-18 14:23:45 +0000 | [diff] [blame] | 233 | box.xMin = box.yMin = 32767L; |
| 234 | box.xMax = box.yMax = -32768L; |
David Turner | 666b11d | 2000-07-27 15:59:08 +0000 | [diff] [blame] | 235 | |
Werner Lemberg | c703b1b | 2000-07-27 16:57:35 +0000 | [diff] [blame] | 236 | /* is it empty? */ |
David Turner | 666b11d | 2000-07-27 15:59:08 +0000 | [diff] [blame] | 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 = ah_test_extrema( outline, indices.xMin ); |
Werner Lemberg | c703b1b | 2000-07-27 16:57:35 +0000 | [diff] [blame] | 274 | if ( n ) |
| 275 | goto Exit; |
Werner Lemberg | e4b32a5 | 2000-10-31 20:42:18 +0000 | [diff] [blame] | 276 | |
David Turner | 666b11d | 2000-07-27 15:59:08 +0000 | [diff] [blame] | 277 | n = ah_test_extrema( outline, indices.yMin ); |
Werner Lemberg | c703b1b | 2000-07-27 16:57:35 +0000 | [diff] [blame] | 278 | if ( n ) |
| 279 | goto Exit; |
Werner Lemberg | e4b32a5 | 2000-10-31 20:42:18 +0000 | [diff] [blame] | 280 | |
David Turner | 666b11d | 2000-07-27 15:59:08 +0000 | [diff] [blame] | 281 | n = ah_test_extrema( outline, indices.xMax ); |
Werner Lemberg | c703b1b | 2000-07-27 16:57:35 +0000 | [diff] [blame] | 282 | if ( n ) |
| 283 | goto Exit; |
Werner Lemberg | e4b32a5 | 2000-10-31 20:42:18 +0000 | [diff] [blame] | 284 | |
David Turner | 666b11d | 2000-07-27 15:59:08 +0000 | [diff] [blame] | 285 | n = ah_test_extrema( outline, indices.yMax ); |
Werner Lemberg | c703b1b | 2000-07-27 16:57:35 +0000 | [diff] [blame] | 286 | if ( !n ) |
David Turner | 666b11d | 2000-07-27 15:59:08 +0000 | [diff] [blame] | 287 | n = 1; |
| 288 | |
| 289 | Exit: |
Werner Lemberg | e4b32a5 | 2000-10-31 20:42:18 +0000 | [diff] [blame] | 290 | return n; |
David Turner | 666b11d | 2000-07-27 15:59:08 +0000 | [diff] [blame] | 291 | } |
| 292 | |
| 293 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 294 | /*************************************************************************/ |
| 295 | /* */ |
| 296 | /* <Function> */ |
| 297 | /* ah_outline_new */ |
| 298 | /* */ |
| 299 | /* <Description> */ |
| 300 | /* Creates a new and empty AH_Outline object. */ |
| 301 | /* */ |
David Turner | bc82f1b | 2002-03-01 02:26:22 +0000 | [diff] [blame] | 302 | FT_LOCAL_DEF( FT_Error ) |
Werner Lemberg | f814d0f | 2001-06-27 16:18:10 +0000 | [diff] [blame] | 303 | ah_outline_new( FT_Memory memory, |
| 304 | AH_Outline** aoutline ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 305 | { |
| 306 | FT_Error error; |
| 307 | AH_Outline* outline; |
| 308 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 309 | |
David Turner | e459d74 | 2002-03-22 13:52:37 +0000 | [diff] [blame^] | 310 | if ( !FT_NEW( outline ) ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 311 | { |
| 312 | outline->memory = memory; |
| 313 | *aoutline = outline; |
| 314 | } |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 315 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 316 | return error; |
| 317 | } |
| 318 | |
| 319 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 320 | /*************************************************************************/ |
| 321 | /* */ |
| 322 | /* <Function> */ |
| 323 | /* ah_outline_done */ |
| 324 | /* */ |
| 325 | /* <Description> */ |
| 326 | /* Destroys a given AH_Outline object. */ |
| 327 | /* */ |
David Turner | bc82f1b | 2002-03-01 02:26:22 +0000 | [diff] [blame] | 328 | FT_LOCAL_DEF( void ) |
Werner Lemberg | f814d0f | 2001-06-27 16:18:10 +0000 | [diff] [blame] | 329 | ah_outline_done( AH_Outline* outline ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 330 | { |
| 331 | FT_Memory memory = outline->memory; |
| 332 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 333 | |
David Turner | e459d74 | 2002-03-22 13:52:37 +0000 | [diff] [blame^] | 334 | FT_FREE( outline->horz_edges ); |
| 335 | FT_FREE( outline->horz_segments ); |
| 336 | FT_FREE( outline->contours ); |
| 337 | FT_FREE( outline->points ); |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 338 | |
David Turner | e459d74 | 2002-03-22 13:52:37 +0000 | [diff] [blame^] | 339 | FT_FREE( outline ); |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 340 | } |
| 341 | |
| 342 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 343 | /*************************************************************************/ |
| 344 | /* */ |
| 345 | /* <Function> */ |
| 346 | /* ah_outline_save */ |
| 347 | /* */ |
| 348 | /* <Description> */ |
| 349 | /* Saves the content of a given AH_Outline object into a face's glyph */ |
| 350 | /* slot. */ |
| 351 | /* */ |
David Turner | bc82f1b | 2002-03-01 02:26:22 +0000 | [diff] [blame] | 352 | FT_LOCAL_DEF( void ) |
Werner Lemberg | f814d0f | 2001-06-27 16:18:10 +0000 | [diff] [blame] | 353 | ah_outline_save( AH_Outline* outline, |
David Turner | 4d57024 | 2002-02-24 02:59:24 +0000 | [diff] [blame] | 354 | AH_Loader gloader ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 355 | { |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 356 | AH_Point* point = outline->points; |
| 357 | AH_Point* point_limit = point + outline->num_points; |
| 358 | FT_Vector* vec = gloader->current.outline.points; |
| 359 | char* tag = gloader->current.outline.tags; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 360 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 361 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 362 | /* we assume that the glyph loader has already been checked for storage */ |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 363 | for ( ; point < point_limit; point++, vec++, tag++ ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 364 | { |
| 365 | vec->x = point->x; |
| 366 | vec->y = point->y; |
| 367 | |
David Turner | b92479b | 2001-10-29 10:45:57 +0000 | [diff] [blame] | 368 | if ( point->flags & ah_flag_conic ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 369 | tag[0] = FT_Curve_Tag_Conic; |
David Turner | b92479b | 2001-10-29 10:45:57 +0000 | [diff] [blame] | 370 | else if ( point->flags & ah_flag_cubic ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 371 | tag[0] = FT_Curve_Tag_Cubic; |
| 372 | else |
| 373 | tag[0] = FT_Curve_Tag_On; |
| 374 | } |
| 375 | } |
| 376 | |
| 377 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 378 | /*************************************************************************/ |
| 379 | /* */ |
| 380 | /* <Function> */ |
| 381 | /* ah_outline_load */ |
| 382 | /* */ |
| 383 | /* <Description> */ |
| 384 | /* Loads an unscaled outline from a glyph slot into an AH_Outline */ |
| 385 | /* object. */ |
| 386 | /* */ |
David Turner | bc82f1b | 2002-03-01 02:26:22 +0000 | [diff] [blame] | 387 | FT_LOCAL_DEF( FT_Error ) |
Werner Lemberg | f814d0f | 2001-06-27 16:18:10 +0000 | [diff] [blame] | 388 | ah_outline_load( AH_Outline* outline, |
| 389 | FT_Face face ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 390 | { |
| 391 | FT_Memory memory = outline->memory; |
Werner Lemberg | 1f7f0e8 | 2001-06-06 17:30:41 +0000 | [diff] [blame] | 392 | FT_Error error = AH_Err_Ok; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 393 | FT_Outline* source = &face->glyph->outline; |
| 394 | FT_Int num_points = source->n_points; |
| 395 | FT_Int num_contours = source->n_contours; |
| 396 | AH_Point* points; |
| 397 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 398 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 399 | /* check arguments */ |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 400 | if ( !face || |
| 401 | !face->size || |
| 402 | face->glyph->format != ft_glyph_format_outline ) |
Werner Lemberg | 1f7f0e8 | 2001-06-06 17:30:41 +0000 | [diff] [blame] | 403 | return AH_Err_Invalid_Argument; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 404 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 405 | /* first of all, reallocate the contours array if necessary */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 406 | if ( num_contours > outline->max_contours ) |
| 407 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 408 | FT_Int new_contours = ( num_contours + 3 ) & -4; |
| 409 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 410 | |
David Turner | e459d74 | 2002-03-22 13:52:37 +0000 | [diff] [blame^] | 411 | if ( FT_RENEW_ARRAY( outline->contours, |
| 412 | outline->max_contours, |
| 413 | new_contours ) ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 414 | goto Exit; |
| 415 | |
| 416 | outline->max_contours = new_contours; |
| 417 | } |
| 418 | |
Werner Lemberg | 58b17f9 | 2000-07-27 23:29:08 +0000 | [diff] [blame] | 419 | /* then, reallocate the points, segments & edges arrays if needed -- */ |
| 420 | /* note that we reserved two additional point positions, used to */ |
| 421 | /* hint metrics appropriately */ |
| 422 | /* */ |
| 423 | if ( num_points + 2 > outline->max_points ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 424 | { |
Werner Lemberg | 58b17f9 | 2000-07-27 23:29:08 +0000 | [diff] [blame] | 425 | FT_Int news = ( num_points + 2 + 7 ) & -8; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 426 | FT_Int max = outline->max_points; |
| 427 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 428 | |
David Turner | e459d74 | 2002-03-22 13:52:37 +0000 | [diff] [blame^] | 429 | if ( FT_RENEW_ARRAY( outline->points, max, news ) || |
| 430 | FT_RENEW_ARRAY( outline->horz_edges, max * 2, news * 2 ) || |
| 431 | FT_RENEW_ARRAY( outline->horz_segments, max * 2, news * 2 ) ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 432 | goto Exit; |
| 433 | |
| 434 | /* readjust some pointers */ |
David Turner | f00a4de | 2000-10-03 22:03:09 +0000 | [diff] [blame] | 435 | outline->vert_edges = outline->horz_edges + news; |
| 436 | outline->vert_segments = outline->horz_segments + news; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 437 | outline->max_points = news; |
| 438 | } |
| 439 | |
| 440 | outline->num_points = num_points; |
| 441 | outline->num_contours = num_contours; |
| 442 | |
| 443 | outline->num_hedges = 0; |
| 444 | outline->num_vedges = 0; |
| 445 | outline->num_hsegments = 0; |
| 446 | outline->num_vsegments = 0; |
| 447 | |
Werner Lemberg | c703b1b | 2000-07-27 16:57:35 +0000 | [diff] [blame] | 448 | /* We can't rely on the value of `FT_Outline.flags' to know the fill */ |
| 449 | /* direction used for a glyph, given that some fonts are broken (e.g. */ |
| 450 | /* the Arphic ones). We thus recompute it each time we need to. */ |
| 451 | /* */ |
David Turner | 666b11d | 2000-07-27 15:59:08 +0000 | [diff] [blame] | 452 | outline->vert_major_dir = ah_dir_up; |
| 453 | outline->horz_major_dir = ah_dir_left; |
| 454 | |
| 455 | if ( ah_get_orientation( source ) > 1 ) |
| 456 | { |
| 457 | outline->vert_major_dir = ah_dir_down; |
| 458 | outline->horz_major_dir = ah_dir_right; |
Werner Lemberg | e4b32a5 | 2000-10-31 20:42:18 +0000 | [diff] [blame] | 459 | } |
Werner Lemberg | c703b1b | 2000-07-27 16:57:35 +0000 | [diff] [blame] | 460 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 461 | outline->x_scale = face->size->metrics.x_scale; |
| 462 | outline->y_scale = face->size->metrics.y_scale; |
| 463 | |
| 464 | points = outline->points; |
Werner Lemberg | c703b1b | 2000-07-27 16:57:35 +0000 | [diff] [blame] | 465 | if ( outline->num_points == 0 ) |
David Turner | 666b11d | 2000-07-27 15:59:08 +0000 | [diff] [blame] | 466 | goto Exit; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 467 | |
| 468 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 469 | /* do one thing at a time -- it is easier to understand, and */ |
| 470 | /* the code is clearer */ |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 471 | AH_Point* point; |
| 472 | AH_Point* point_limit = points + outline->num_points; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 473 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 474 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 475 | /* compute coordinates */ |
| 476 | { |
| 477 | FT_Vector* vec = source->points; |
| 478 | FT_Fixed x_scale = outline->x_scale; |
| 479 | FT_Fixed y_scale = outline->y_scale; |
| 480 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 481 | |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 482 | for ( point = points; point < point_limit; vec++, point++ ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 483 | { |
| 484 | point->fx = vec->x; |
| 485 | point->fy = vec->y; |
| 486 | point->ox = point->x = FT_MulFix( vec->x, x_scale ); |
| 487 | point->oy = point->y = FT_MulFix( vec->y, y_scale ); |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 488 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 489 | point->flags = 0; |
| 490 | } |
| 491 | } |
| 492 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 493 | /* compute Bezier flags */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 494 | { |
| 495 | char* tag = source->tags; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 496 | |
| 497 | |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 498 | for ( point = points; point < point_limit; point++, tag++ ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 499 | { |
| 500 | switch ( FT_CURVE_TAG( *tag ) ) |
| 501 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 502 | case FT_Curve_Tag_Conic: |
David Turner | b92479b | 2001-10-29 10:45:57 +0000 | [diff] [blame] | 503 | point->flags = ah_flag_conic; break; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 504 | case FT_Curve_Tag_Cubic: |
David Turner | b92479b | 2001-10-29 10:45:57 +0000 | [diff] [blame] | 505 | point->flags = ah_flag_cubic; break; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 506 | default: |
| 507 | ; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 508 | } |
| 509 | } |
| 510 | } |
| 511 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 512 | /* compute `next' and `prev' */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 513 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 514 | FT_Int contour_index; |
| 515 | AH_Point* prev; |
| 516 | AH_Point* first; |
| 517 | AH_Point* end; |
| 518 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 519 | |
| 520 | contour_index = 0; |
| 521 | |
| 522 | first = points; |
| 523 | end = points + source->contours[0]; |
| 524 | prev = end; |
| 525 | |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 526 | for ( point = points; point < point_limit; point++ ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 527 | { |
| 528 | point->prev = prev; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 529 | if ( point < end ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 530 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 531 | point->next = point + 1; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 532 | prev = point; |
| 533 | } |
| 534 | else |
| 535 | { |
| 536 | point->next = first; |
| 537 | contour_index++; |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 538 | if ( point + 1 < point_limit ) |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 539 | { |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 540 | end = points + source->contours[contour_index]; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 541 | first = point + 1; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 542 | prev = end; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 543 | } |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 544 | } |
| 545 | } |
| 546 | } |
| 547 | |
| 548 | /* set-up the contours array */ |
| 549 | { |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 550 | AH_Point** contour = outline->contours; |
| 551 | AH_Point** contour_limit = contour + outline->num_contours; |
| 552 | short* end = source->contours; |
Werner Lemberg | 0d9165e | 2002-03-07 21:59:59 +0000 | [diff] [blame] | 553 | short idx = 0; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 554 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 555 | |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 556 | for ( ; contour < contour_limit; contour++, end++ ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 557 | { |
Werner Lemberg | 0d9165e | 2002-03-07 21:59:59 +0000 | [diff] [blame] | 558 | contour[0] = points + idx; |
| 559 | idx = (short)( end[0] + 1 ); |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 560 | } |
| 561 | } |
| 562 | |
| 563 | /* compute directions of in & out vectors */ |
| 564 | { |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 565 | for ( point = points; point < point_limit; point++ ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 566 | { |
| 567 | AH_Point* prev; |
| 568 | AH_Point* next; |
David Turner | b92479b | 2001-10-29 10:45:57 +0000 | [diff] [blame] | 569 | FT_Vector ivec, ovec; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 570 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 571 | |
David Turner | b92479b | 2001-10-29 10:45:57 +0000 | [diff] [blame] | 572 | prev = point->prev; |
| 573 | ivec.x = point->fx - prev->fx; |
| 574 | ivec.y = point->fy - prev->fy; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 575 | |
David Turner | b92479b | 2001-10-29 10:45:57 +0000 | [diff] [blame] | 576 | point->in_dir = ah_compute_direction( ivec.x, ivec.y ); |
| 577 | |
| 578 | next = point->next; |
| 579 | ovec.x = next->fx - point->fx; |
| 580 | ovec.y = next->fy - point->fy; |
| 581 | |
| 582 | point->out_dir = ah_compute_direction( ovec.x, ovec.y ); |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 583 | |
| 584 | #ifndef AH_OPTION_NO_WEAK_INTERPOLATION |
David Turner | b92479b | 2001-10-29 10:45:57 +0000 | [diff] [blame] | 585 | if ( point->flags & (ah_flag_conic | ah_flag_cubic) ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 586 | { |
David Turner | b92479b | 2001-10-29 10:45:57 +0000 | [diff] [blame] | 587 | Is_Weak_Point: |
| 588 | point->flags |= ah_flag_weak_interpolation; |
| 589 | } |
| 590 | else if ( point->out_dir == point->in_dir ) |
| 591 | { |
| 592 | AH_Angle angle_in, angle_out, delta; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 593 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 594 | |
David Turner | b92479b | 2001-10-29 10:45:57 +0000 | [diff] [blame] | 595 | if ( point->out_dir != ah_dir_none ) |
| 596 | goto Is_Weak_Point; |
Werner Lemberg | c3b2160 | 2001-12-05 01:22:05 +0000 | [diff] [blame] | 597 | |
David Turner | b92479b | 2001-10-29 10:45:57 +0000 | [diff] [blame] | 598 | angle_in = ah_angle( &ivec ); |
| 599 | angle_out = ah_angle( &ovec ); |
| 600 | delta = angle_in - angle_out; |
Werner Lemberg | c3b2160 | 2001-12-05 01:22:05 +0000 | [diff] [blame] | 601 | |
David Turner | b92479b | 2001-10-29 10:45:57 +0000 | [diff] [blame] | 602 | if ( delta > AH_PI ) |
| 603 | delta = AH_2PI - delta; |
| 604 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 605 | if ( delta < 0 ) |
| 606 | delta = -delta; |
David Turner | b92479b | 2001-10-29 10:45:57 +0000 | [diff] [blame] | 607 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 608 | if ( delta < 2 ) |
David Turner | b92479b | 2001-10-29 10:45:57 +0000 | [diff] [blame] | 609 | goto Is_Weak_Point; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 610 | } |
David Turner | b92479b | 2001-10-29 10:45:57 +0000 | [diff] [blame] | 611 | else if ( point->in_dir == -point->out_dir ) |
| 612 | goto Is_Weak_Point; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 613 | #endif |
| 614 | } |
| 615 | } |
| 616 | } |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 617 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 618 | Exit: |
| 619 | return error; |
| 620 | } |
| 621 | |
| 622 | |
David Turner | bc82f1b | 2002-03-01 02:26:22 +0000 | [diff] [blame] | 623 | FT_LOCAL_DEF( void ) |
Werner Lemberg | f814d0f | 2001-06-27 16:18:10 +0000 | [diff] [blame] | 624 | ah_setup_uv( AH_Outline* outline, |
| 625 | AH_UV source ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 626 | { |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 627 | AH_Point* point = outline->points; |
| 628 | AH_Point* point_limit = point + outline->num_points; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 629 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 630 | |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 631 | for ( ; point < point_limit; point++ ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 632 | { |
| 633 | FT_Pos u, v; |
| 634 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 635 | |
| 636 | switch ( source ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 637 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 638 | case ah_uv_fxy: |
| 639 | u = point->fx; |
| 640 | v = point->fy; |
| 641 | break; |
| 642 | case ah_uv_fyx: |
| 643 | u = point->fy; |
| 644 | v = point->fx; |
| 645 | break; |
| 646 | case ah_uv_oxy: |
| 647 | u = point->ox; |
| 648 | v = point->oy; |
| 649 | break; |
| 650 | case ah_uv_oyx: |
| 651 | u = point->oy; |
| 652 | v = point->ox; |
| 653 | break; |
| 654 | case ah_uv_yx: |
| 655 | u = point->y; |
| 656 | v = point->x; |
| 657 | break; |
| 658 | case ah_uv_ox: |
| 659 | u = point->x; |
| 660 | v = point->ox; |
| 661 | break; |
| 662 | case ah_uv_oy: |
| 663 | u = point->y; |
| 664 | v = point->oy; |
| 665 | break; |
| 666 | default: |
| 667 | u = point->x; |
| 668 | v = point->y; |
| 669 | break; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 670 | } |
| 671 | point->u = u; |
| 672 | point->v = v; |
| 673 | } |
| 674 | } |
| 675 | |
| 676 | |
David Turner | bc82f1b | 2002-03-01 02:26:22 +0000 | [diff] [blame] | 677 | FT_LOCAL_DEF( void ) |
Werner Lemberg | f814d0f | 2001-06-27 16:18:10 +0000 | [diff] [blame] | 678 | ah_outline_compute_segments( AH_Outline* outline ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 679 | { |
| 680 | int dimension; |
| 681 | AH_Segment* segments; |
| 682 | FT_Int* p_num_segments; |
| 683 | AH_Direction segment_dir; |
| 684 | AH_Direction major_dir; |
| 685 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 686 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 687 | segments = outline->horz_segments; |
| 688 | p_num_segments = &outline->num_hsegments; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 689 | major_dir = ah_dir_right; /* This value must be positive! */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 690 | segment_dir = major_dir; |
| 691 | |
| 692 | /* set up (u,v) in each point */ |
| 693 | ah_setup_uv( outline, ah_uv_fyx ); |
| 694 | |
| 695 | for ( dimension = 1; dimension >= 0; dimension-- ) |
| 696 | { |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 697 | AH_Point** contour = outline->contours; |
| 698 | AH_Point** contour_limit = contour + outline->num_contours; |
| 699 | AH_Segment* segment = segments; |
| 700 | FT_Int num_segments = 0; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 701 | |
| 702 | #ifdef AH_HINT_METRICS |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 703 | AH_Point* min_point = 0; |
| 704 | AH_Point* max_point = 0; |
| 705 | FT_Pos min_coord = 32000; |
| 706 | FT_Pos max_coord = -32000; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 707 | #endif |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 708 | |
| 709 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 710 | /* do each contour separately */ |
| 711 | for ( ; contour < contour_limit; contour++ ) |
| 712 | { |
| 713 | AH_Point* point = contour[0]; |
| 714 | AH_Point* last = point->prev; |
| 715 | int on_edge = 0; |
| 716 | FT_Pos min_pos = +32000; /* minimum segment pos != min_coord */ |
| 717 | FT_Pos max_pos = -32000; /* maximum segment pos != max_coord */ |
| 718 | FT_Bool passed; |
| 719 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 720 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 721 | #ifdef AH_HINT_METRICS |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 722 | if ( point->u < min_coord ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 723 | { |
| 724 | min_coord = point->u; |
| 725 | min_point = point; |
| 726 | } |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 727 | if ( point->u > max_coord ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 728 | { |
| 729 | max_coord = point->u; |
| 730 | max_point = point; |
| 731 | } |
| 732 | #endif |
| 733 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 734 | if ( point == last ) /* skip singletons -- just in case? */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 735 | continue; |
| 736 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 737 | if ( ABS( last->out_dir ) == major_dir && |
| 738 | ABS( point->out_dir ) == major_dir ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 739 | { |
| 740 | /* we are already on an edge, try to locate its start */ |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 741 | last = point; |
| 742 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 743 | for (;;) |
| 744 | { |
| 745 | point = point->prev; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 746 | if ( ABS( point->out_dir ) != major_dir ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 747 | { |
| 748 | point = point->next; |
| 749 | break; |
| 750 | } |
| 751 | if ( point == last ) |
| 752 | break; |
| 753 | } |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 754 | } |
| 755 | |
| 756 | last = point; |
| 757 | passed = 0; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 758 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 759 | for (;;) |
| 760 | { |
| 761 | FT_Pos u, v; |
| 762 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 763 | |
| 764 | if ( on_edge ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 765 | { |
| 766 | u = point->u; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 767 | if ( u < min_pos ) |
| 768 | min_pos = u; |
| 769 | if ( u > max_pos ) |
| 770 | max_pos = u; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 771 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 772 | if ( point->out_dir != segment_dir || point == last ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 773 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 774 | /* we are just leaving an edge; record a new segment! */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 775 | segment->last = point; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 776 | segment->pos = ( min_pos + max_pos ) >> 1; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 777 | |
| 778 | /* a segment is round if either its first or last point */ |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 779 | /* is a control point */ |
| 780 | if ( ( segment->first->flags | point->flags ) & |
David Turner | b92479b | 2001-10-29 10:45:57 +0000 | [diff] [blame] | 781 | ah_flag_control ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 782 | segment->flags |= ah_edge_round; |
| 783 | |
| 784 | /* compute segment size */ |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 785 | min_pos = max_pos = point->v; |
| 786 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 787 | v = segment->first->v; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 788 | if ( v < min_pos ) |
| 789 | min_pos = v; |
| 790 | if ( v > max_pos ) |
| 791 | max_pos = v; |
| 792 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 793 | segment->min_coord = min_pos; |
| 794 | segment->max_coord = max_pos; |
| 795 | |
| 796 | on_edge = 0; |
| 797 | num_segments++; |
| 798 | segment++; |
| 799 | /* fallthrough */ |
| 800 | } |
| 801 | } |
| 802 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 803 | /* now exit if we are at the start/end point */ |
| 804 | if ( point == last ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 805 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 806 | if ( passed ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 807 | break; |
| 808 | passed = 1; |
| 809 | } |
| 810 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 811 | if ( !on_edge && ABS( point->out_dir ) == major_dir ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 812 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 813 | /* this is the start of a new segment! */ |
| 814 | segment_dir = point->out_dir; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 815 | |
| 816 | /* clear all segment fields */ |
David Turner | e459d74 | 2002-03-22 13:52:37 +0000 | [diff] [blame^] | 817 | FT_MEM_SET( segment, 0, sizeof ( *segment ) ); |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 818 | |
| 819 | segment->dir = segment_dir; |
| 820 | segment->flags = ah_edge_normal; |
| 821 | min_pos = max_pos = point->u; |
| 822 | segment->first = point; |
| 823 | segment->last = point; |
| 824 | segment->contour = contour; |
| 825 | on_edge = 1; |
| 826 | |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 827 | #ifdef AH_HINT_METRICS |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 828 | if ( point == max_point ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 829 | max_point = 0; |
| 830 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 831 | if ( point == min_point ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 832 | min_point = 0; |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 833 | #endif |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 834 | } |
| 835 | |
| 836 | point = point->next; |
| 837 | } |
| 838 | |
| 839 | } /* contours */ |
| 840 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 841 | #ifdef AH_HINT_METRICS |
| 842 | /* we need to ensure that there are edges on the left-most and */ |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 843 | /* right-most points of the glyph in order to hint the metrics; */ |
| 844 | /* we do this by inserting fake segments when needed */ |
| 845 | if ( dimension == 0 ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 846 | { |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 847 | AH_Point* point = outline->points; |
| 848 | AH_Point* point_limit = point + outline->num_points; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 849 | |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 850 | FT_Pos min_pos = 32000; |
| 851 | FT_Pos max_pos = -32000; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 852 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 853 | |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 854 | min_point = 0; |
| 855 | max_point = 0; |
| 856 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 857 | /* compute minimum and maximum points */ |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 858 | for ( ; point < point_limit; point++ ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 859 | { |
| 860 | FT_Pos x = point->fx; |
| 861 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 862 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 863 | if ( x < min_pos ) |
| 864 | { |
| 865 | min_pos = x; |
| 866 | min_point = point; |
| 867 | } |
| 868 | if ( x > max_pos ) |
| 869 | { |
| 870 | max_pos = x; |
| 871 | max_point = point; |
| 872 | } |
| 873 | } |
| 874 | |
| 875 | /* insert minimum segment */ |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 876 | if ( min_point ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 877 | { |
| 878 | /* clear all segment fields */ |
David Turner | e459d74 | 2002-03-22 13:52:37 +0000 | [diff] [blame^] | 879 | FT_MEM_SET( segment, 0, sizeof ( *segment ) ); |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 880 | |
| 881 | segment->dir = segment_dir; |
| 882 | segment->flags = ah_edge_normal; |
| 883 | segment->first = min_point; |
| 884 | segment->last = min_point; |
| 885 | segment->pos = min_pos; |
| 886 | |
| 887 | num_segments++; |
| 888 | segment++; |
| 889 | } |
| 890 | |
| 891 | /* insert maximum segment */ |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 892 | if ( max_point ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 893 | { |
| 894 | /* clear all segment fields */ |
David Turner | e459d74 | 2002-03-22 13:52:37 +0000 | [diff] [blame^] | 895 | FT_MEM_SET( segment, 0, sizeof ( *segment ) ); |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 896 | |
| 897 | segment->dir = segment_dir; |
| 898 | segment->flags = ah_edge_normal; |
| 899 | segment->first = max_point; |
| 900 | segment->last = max_point; |
| 901 | segment->pos = max_pos; |
| 902 | |
| 903 | num_segments++; |
| 904 | segment++; |
| 905 | } |
| 906 | } |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 907 | #endif /* AH_HINT_METRICS */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 908 | |
| 909 | *p_num_segments = num_segments; |
| 910 | |
| 911 | segments = outline->vert_segments; |
| 912 | major_dir = ah_dir_up; |
| 913 | p_num_segments = &outline->num_vsegments; |
| 914 | ah_setup_uv( outline, ah_uv_fxy ); |
| 915 | } |
| 916 | } |
| 917 | |
| 918 | |
David Turner | bc82f1b | 2002-03-01 02:26:22 +0000 | [diff] [blame] | 919 | FT_LOCAL_DEF( void ) |
Werner Lemberg | f814d0f | 2001-06-27 16:18:10 +0000 | [diff] [blame] | 920 | ah_outline_link_segments( AH_Outline* outline ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 921 | { |
| 922 | AH_Segment* segments; |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 923 | AH_Segment* segment_limit; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 924 | int dimension; |
| 925 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 926 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 927 | ah_setup_uv( outline, ah_uv_fyx ); |
| 928 | |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 929 | segments = outline->horz_segments; |
| 930 | segment_limit = segments + outline->num_hsegments; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 931 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 932 | for ( dimension = 1; dimension >= 0; dimension-- ) |
| 933 | { |
| 934 | AH_Segment* seg1; |
| 935 | AH_Segment* seg2; |
| 936 | |
| 937 | /* now compare each segment to the others */ |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 938 | for ( seg1 = segments; seg1 < segment_limit; seg1++ ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 939 | { |
David Turner | 9d7e5e8 | 2001-10-29 17:22:12 +0000 | [diff] [blame] | 940 | FT_Pos best_score; |
| 941 | AH_Segment* best_segment; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 942 | |
| 943 | /* the fake segments are introduced to hint the metrics -- */ |
| 944 | /* we must never link them to anything */ |
| 945 | if ( seg1->first == seg1->last ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 946 | continue; |
| 947 | |
David Turner | 9d7e5e8 | 2001-10-29 17:22:12 +0000 | [diff] [blame] | 948 | best_segment = seg1->link; |
| 949 | if ( best_segment ) |
| 950 | best_score = seg1->score; |
| 951 | else |
| 952 | best_score = 32000; |
Werner Lemberg | c3b2160 | 2001-12-05 01:22:05 +0000 | [diff] [blame] | 953 | |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 954 | for ( seg2 = segments; seg2 < segment_limit; seg2++ ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 955 | if ( seg1 != seg2 && seg1->dir + seg2->dir == 0 ) |
| 956 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 957 | FT_Pos pos1 = seg1->pos; |
| 958 | FT_Pos pos2 = seg2->pos; |
| 959 | FT_Bool is_dir; |
| 960 | FT_Bool is_pos; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 961 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 962 | |
| 963 | /* check that the segments are correctly oriented and */ |
| 964 | /* positioned to form a black distance */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 965 | |
David Turner | 8edbcab | 2001-06-19 08:28:24 +0000 | [diff] [blame] | 966 | is_dir = (FT_Bool)( seg1->dir == outline->horz_major_dir || |
| 967 | seg1->dir == outline->vert_major_dir ); |
Werner Lemberg | 8eb0353 | 2001-06-19 23:03:41 +0000 | [diff] [blame] | 968 | is_pos = (FT_Bool)( pos1 > pos2 ); |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 969 | |
| 970 | if ( pos1 == pos2 || !(is_dir ^ is_pos) ) |
| 971 | continue; |
| 972 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 973 | { |
| 974 | FT_Pos min = seg1->min_coord; |
| 975 | FT_Pos max = seg1->max_coord; |
David Turner | 9d7e5e8 | 2001-10-29 17:22:12 +0000 | [diff] [blame] | 976 | FT_Pos len, dist, score; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 977 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 978 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 979 | if ( min < seg2->min_coord ) |
| 980 | min = seg2->min_coord; |
| 981 | |
David Turner | 9d7e5e8 | 2001-10-29 17:22:12 +0000 | [diff] [blame] | 982 | if ( max > seg2->max_coord ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 983 | max = seg2->max_coord; |
| 984 | |
| 985 | len = max - min; |
David Turner | 9d7e5e8 | 2001-10-29 17:22:12 +0000 | [diff] [blame] | 986 | dist = seg2->pos - seg1->pos; |
| 987 | if ( dist < 0 ) |
| 988 | dist = -dist; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 989 | |
David Turner | 9d7e5e8 | 2001-10-29 17:22:12 +0000 | [diff] [blame] | 990 | if ( len < 8 ) |
David Turner | adf07a9 | 2001-10-30 23:51:24 +0000 | [diff] [blame] | 991 | score = 300*8 + dist - len*3; |
David Turner | 9d7e5e8 | 2001-10-29 17:22:12 +0000 | [diff] [blame] | 992 | else |
| 993 | score = dist + 300/len; |
| 994 | |
| 995 | if ( score < best_score ) |
| 996 | { |
| 997 | best_score = score; |
| 998 | best_segment = seg2; |
| 999 | } |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1000 | } |
| 1001 | } |
| 1002 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1003 | if ( best_segment ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1004 | { |
| 1005 | seg1->link = best_segment; |
| 1006 | seg1->score = best_score; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1007 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1008 | best_segment->num_linked++; |
| 1009 | } |
| 1010 | |
| 1011 | |
| 1012 | } /* edges 1 */ |
| 1013 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1014 | /* now, compute the `serif' segments */ |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 1015 | for ( seg1 = segments; seg1 < segment_limit; seg1++ ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1016 | { |
| 1017 | seg2 = seg1->link; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1018 | |
| 1019 | if ( seg2 && seg2->link != seg1 ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1020 | { |
| 1021 | seg1->link = 0; |
| 1022 | seg1->serif = seg2->link; |
| 1023 | } |
| 1024 | } |
| 1025 | |
| 1026 | ah_setup_uv( outline, ah_uv_fxy ); |
| 1027 | |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 1028 | segments = outline->vert_segments; |
| 1029 | segment_limit = segments + outline->num_vsegments; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1030 | } |
| 1031 | } |
| 1032 | |
| 1033 | |
Werner Lemberg | f814d0f | 2001-06-27 16:18:10 +0000 | [diff] [blame] | 1034 | static void |
| 1035 | ah_outline_compute_edges( AH_Outline* outline ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1036 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1037 | AH_Edge* edges; |
| 1038 | AH_Segment* segments; |
| 1039 | AH_Segment* segment_limit; |
| 1040 | AH_Direction up_dir; |
| 1041 | FT_Int* p_num_edges; |
| 1042 | FT_Int dimension; |
| 1043 | FT_Fixed scale; |
| 1044 | FT_Pos edge_distance_threshold; |
| 1045 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1046 | |
| 1047 | edges = outline->horz_edges; |
| 1048 | segments = outline->horz_segments; |
| 1049 | segment_limit = segments + outline->num_hsegments; |
| 1050 | p_num_edges = &outline->num_hedges; |
| 1051 | up_dir = ah_dir_right; |
| 1052 | scale = outline->y_scale; |
| 1053 | |
| 1054 | for ( dimension = 1; dimension >= 0; dimension-- ) |
| 1055 | { |
| 1056 | AH_Edge* edge; |
| 1057 | AH_Edge* edge_limit; /* really == edge + num_edges */ |
| 1058 | AH_Segment* seg; |
| 1059 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1060 | |
| 1061 | /*********************************************************************/ |
| 1062 | /* */ |
| 1063 | /* We will begin by generating a sorted table of edges for the */ |
| 1064 | /* current direction. To do so, we simply scan each segment and try */ |
| 1065 | /* to find an edge in our table that corresponds to its position. */ |
| 1066 | /* */ |
| 1067 | /* If no edge is found, we create and insert a new edge in the */ |
| 1068 | /* sorted table. Otherwise, we simply add the segment to the edge's */ |
| 1069 | /* list which will be processed in the second step to compute the */ |
| 1070 | /* edge's properties. */ |
| 1071 | /* */ |
| 1072 | /* Note that the edges table is sorted along the segment/edge */ |
| 1073 | /* position. */ |
| 1074 | /* */ |
| 1075 | /*********************************************************************/ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1076 | |
| 1077 | edge_distance_threshold = FT_MulFix( outline->edge_distance_threshold, |
| 1078 | scale ); |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1079 | if ( edge_distance_threshold > 64 / 4 ) |
| 1080 | edge_distance_threshold = 64 / 4; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1081 | |
| 1082 | edge_limit = edges; |
| 1083 | for ( seg = segments; seg < segment_limit; seg++ ) |
| 1084 | { |
| 1085 | AH_Edge* found = 0; |
| 1086 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1087 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1088 | /* look for an edge corresponding to the segment */ |
| 1089 | for ( edge = edges; edge < edge_limit; edge++ ) |
| 1090 | { |
| 1091 | FT_Pos dist; |
| 1092 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1093 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1094 | dist = seg->pos - edge->fpos; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1095 | if ( dist < 0 ) |
| 1096 | dist = -dist; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1097 | |
| 1098 | dist = FT_MulFix( dist, scale ); |
| 1099 | if ( dist < edge_distance_threshold ) |
| 1100 | { |
| 1101 | found = edge; |
| 1102 | break; |
| 1103 | } |
| 1104 | } |
| 1105 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1106 | if ( !found ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1107 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1108 | /* insert a new edge in the list and */ |
| 1109 | /* sort according to the position */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1110 | while ( edge > edges && edge[-1].fpos > seg->pos ) |
| 1111 | { |
| 1112 | edge[0] = edge[-1]; |
| 1113 | edge--; |
| 1114 | } |
| 1115 | edge_limit++; |
| 1116 | |
| 1117 | /* clear all edge fields */ |
David Turner | e459d74 | 2002-03-22 13:52:37 +0000 | [diff] [blame^] | 1118 | FT_MEM_SET( edge, 0, sizeof ( *edge ) ); |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1119 | |
| 1120 | /* add the segment to the new edge's list */ |
| 1121 | edge->first = seg; |
| 1122 | edge->last = seg; |
| 1123 | edge->fpos = seg->pos; |
| 1124 | edge->opos = edge->pos = FT_MulFix( seg->pos, scale ); |
| 1125 | seg->edge_next = seg; |
| 1126 | } |
| 1127 | else |
| 1128 | { |
| 1129 | /* if an edge was found, simply add the segment to the edge's */ |
| 1130 | /* list */ |
| 1131 | seg->edge_next = edge->first; |
| 1132 | edge->last->edge_next = seg; |
| 1133 | edge->last = seg; |
| 1134 | } |
| 1135 | } |
| 1136 | |
Werner Lemberg | 914b289 | 2001-03-10 17:07:42 +0000 | [diff] [blame] | 1137 | *p_num_edges = (FT_Int)( edge_limit - edges ); |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1138 | |
| 1139 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1140 | /*********************************************************************/ |
| 1141 | /* */ |
| 1142 | /* Good, we will now compute each edge's properties according to */ |
| 1143 | /* segments found on its position. Basically, these are: */ |
| 1144 | /* */ |
| 1145 | /* - edge's main direction */ |
| 1146 | /* - stem edge, serif edge or both (which defaults to stem then) */ |
| 1147 | /* - rounded edge, straigth or both (which defaults to straight) */ |
| 1148 | /* - link for edge */ |
| 1149 | /* */ |
| 1150 | /*********************************************************************/ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1151 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1152 | /* first of all, set the `edge' field in each segment -- this is */ |
| 1153 | /* required in order to compute edge links */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1154 | for ( edge = edges; edge < edge_limit; edge++ ) |
| 1155 | { |
| 1156 | seg = edge->first; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1157 | if ( seg ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1158 | do |
| 1159 | { |
| 1160 | seg->edge = edge; |
| 1161 | seg = seg->edge_next; |
| 1162 | } |
| 1163 | while ( seg != edge->first ); |
| 1164 | } |
| 1165 | |
| 1166 | /* now, compute each edge properties */ |
| 1167 | for ( edge = edges; edge < edge_limit; edge++ ) |
| 1168 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1169 | int is_round = 0; /* does it contain round segments? */ |
| 1170 | int is_straight = 0; /* does it contain straight segments? */ |
| 1171 | int ups = 0; /* number of upwards segments */ |
| 1172 | int downs = 0; /* number of downwards segments */ |
| 1173 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1174 | |
| 1175 | seg = edge->first; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1176 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1177 | do |
| 1178 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1179 | FT_Bool is_serif; |
| 1180 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1181 | |
| 1182 | /* check for roundness of segment */ |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1183 | if ( seg->flags & ah_edge_round ) |
| 1184 | is_round++; |
| 1185 | else |
| 1186 | is_straight++; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1187 | |
| 1188 | /* check for segment direction */ |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1189 | if ( seg->dir == up_dir ) |
| 1190 | ups += seg->max_coord-seg->min_coord; |
| 1191 | else |
| 1192 | downs += seg->max_coord-seg->min_coord; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1193 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1194 | /* check for links -- if seg->serif is set, then seg->link must */ |
| 1195 | /* be ignored */ |
Werner Lemberg | 8eb0353 | 2001-06-19 23:03:41 +0000 | [diff] [blame] | 1196 | is_serif = (FT_Bool)( seg->serif && seg->serif->edge != edge ); |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1197 | |
| 1198 | if ( seg->link || is_serif ) |
| 1199 | { |
| 1200 | AH_Edge* edge2; |
| 1201 | AH_Segment* seg2; |
| 1202 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1203 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1204 | edge2 = edge->link; |
| 1205 | seg2 = seg->link; |
| 1206 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1207 | if ( is_serif ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1208 | { |
| 1209 | seg2 = seg->serif; |
| 1210 | edge2 = edge->serif; |
| 1211 | } |
| 1212 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1213 | if ( edge2 ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1214 | { |
| 1215 | FT_Pos edge_delta; |
| 1216 | FT_Pos seg_delta; |
| 1217 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1218 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1219 | edge_delta = edge->fpos - edge2->fpos; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1220 | if ( edge_delta < 0 ) |
| 1221 | edge_delta = -edge_delta; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1222 | |
| 1223 | seg_delta = seg->pos - seg2->pos; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1224 | if ( seg_delta < 0 ) |
| 1225 | seg_delta = -seg_delta; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1226 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1227 | if ( seg_delta < edge_delta ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1228 | edge2 = seg2->edge; |
| 1229 | } |
| 1230 | else |
| 1231 | edge2 = seg2->edge; |
| 1232 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1233 | if ( is_serif ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1234 | edge->serif = edge2; |
| 1235 | else |
| 1236 | edge->link = edge2; |
| 1237 | } |
| 1238 | |
| 1239 | seg = seg->edge_next; |
| 1240 | |
| 1241 | } while ( seg != edge->first ); |
| 1242 | |
| 1243 | /* set the round/straight flags */ |
| 1244 | edge->flags = ah_edge_normal; |
| 1245 | |
David Turner | 66cb479 | 2001-05-14 14:04:23 +0000 | [diff] [blame] | 1246 | if ( is_round > 0 && is_round >= is_straight ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1247 | edge->flags |= ah_edge_round; |
| 1248 | |
| 1249 | /* set the edge's main direction */ |
| 1250 | edge->dir = ah_dir_none; |
| 1251 | |
| 1252 | if ( ups > downs ) |
| 1253 | edge->dir = up_dir; |
| 1254 | |
| 1255 | else if ( ups < downs ) |
| 1256 | edge->dir = - up_dir; |
| 1257 | |
| 1258 | else if ( ups == downs ) |
| 1259 | edge->dir = 0; /* both up and down !! */ |
| 1260 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1261 | /* gets rid of serifs if link is set */ |
| 1262 | /* XXX: This gets rid of many unpleasant artefacts! */ |
| 1263 | /* Example: the `c' in cour.pfa at size 13 */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1264 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1265 | if ( edge->serif && edge->link ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1266 | edge->serif = 0; |
| 1267 | } |
| 1268 | |
| 1269 | edges = outline->vert_edges; |
| 1270 | segments = outline->vert_segments; |
| 1271 | segment_limit = segments + outline->num_vsegments; |
| 1272 | p_num_edges = &outline->num_vedges; |
| 1273 | up_dir = ah_dir_up; |
| 1274 | scale = outline->x_scale; |
| 1275 | } |
| 1276 | } |
| 1277 | |
| 1278 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1279 | /*************************************************************************/ |
| 1280 | /* */ |
| 1281 | /* <Function> */ |
| 1282 | /* ah_outline_detect_features */ |
| 1283 | /* */ |
| 1284 | /* <Description> */ |
| 1285 | /* Performs feature detection on a given AH_Outline object. */ |
| 1286 | /* */ |
David Turner | bc82f1b | 2002-03-01 02:26:22 +0000 | [diff] [blame] | 1287 | FT_LOCAL_DEF( void ) |
Werner Lemberg | f814d0f | 2001-06-27 16:18:10 +0000 | [diff] [blame] | 1288 | ah_outline_detect_features( AH_Outline* outline ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1289 | { |
| 1290 | ah_outline_compute_segments( outline ); |
| 1291 | ah_outline_link_segments ( outline ); |
| 1292 | ah_outline_compute_edges ( outline ); |
| 1293 | } |
| 1294 | |
| 1295 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1296 | /*************************************************************************/ |
| 1297 | /* */ |
| 1298 | /* <Function> */ |
| 1299 | /* ah_outline_compute_blue_edges */ |
| 1300 | /* */ |
| 1301 | /* <Description> */ |
| 1302 | /* Computes the `blue edges' in a given outline (i.e. those that must */ |
| 1303 | /* be snapped to a blue zone edge (top or bottom). */ |
| 1304 | /* */ |
David Turner | bc82f1b | 2002-03-01 02:26:22 +0000 | [diff] [blame] | 1305 | FT_LOCAL_DEF( void ) |
Werner Lemberg | f814d0f | 2001-06-27 16:18:10 +0000 | [diff] [blame] | 1306 | ah_outline_compute_blue_edges( AH_Outline* outline, |
| 1307 | AH_Face_Globals* face_globals ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1308 | { |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 1309 | AH_Edge* edge = outline->horz_edges; |
| 1310 | AH_Edge* edge_limit = edge + outline->num_hedges; |
| 1311 | AH_Globals* globals = &face_globals->design; |
| 1312 | FT_Fixed y_scale = outline->y_scale; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1313 | |
Werner Lemberg | 1f7f0e8 | 2001-06-06 17:30:41 +0000 | [diff] [blame] | 1314 | FT_Bool blue_active[ah_blue_max]; |
David Turner | 66cb479 | 2001-05-14 14:04:23 +0000 | [diff] [blame] | 1315 | |
| 1316 | |
| 1317 | /* compute which blue zones are active, i.e. have their scaled */ |
| 1318 | /* size < 3/4 pixels */ |
| 1319 | { |
| 1320 | AH_Blue blue; |
| 1321 | FT_Bool check = 0; |
| 1322 | |
Werner Lemberg | 1f7f0e8 | 2001-06-06 17:30:41 +0000 | [diff] [blame] | 1323 | |
David Turner | 66cb479 | 2001-05-14 14:04:23 +0000 | [diff] [blame] | 1324 | for ( blue = ah_blue_capital_top; blue < ah_blue_max; blue++ ) |
| 1325 | { |
| 1326 | FT_Pos ref, shoot, dist; |
| 1327 | |
Werner Lemberg | 1f7f0e8 | 2001-06-06 17:30:41 +0000 | [diff] [blame] | 1328 | |
David Turner | 66cb479 | 2001-05-14 14:04:23 +0000 | [diff] [blame] | 1329 | ref = globals->blue_refs[blue]; |
| 1330 | shoot = globals->blue_shoots[blue]; |
| 1331 | dist = ref-shoot; |
Werner Lemberg | 1f7f0e8 | 2001-06-06 17:30:41 +0000 | [diff] [blame] | 1332 | if ( dist < 0 ) |
David Turner | 66cb479 | 2001-05-14 14:04:23 +0000 | [diff] [blame] | 1333 | dist = -dist; |
| 1334 | |
| 1335 | blue_active[blue] = 0; |
| 1336 | |
| 1337 | if ( FT_MulFix( dist, y_scale ) < 48 ) |
| 1338 | { |
| 1339 | blue_active[blue] = 1; |
| 1340 | check = 1; |
| 1341 | } |
| 1342 | } |
| 1343 | |
| 1344 | /* return immediately if no blue zone is active */ |
Werner Lemberg | 1f7f0e8 | 2001-06-06 17:30:41 +0000 | [diff] [blame] | 1345 | if ( !check ) |
David Turner | 66cb479 | 2001-05-14 14:04:23 +0000 | [diff] [blame] | 1346 | return; |
| 1347 | } |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1348 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1349 | /* compute for each horizontal edge, which blue zone is closer */ |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 1350 | for ( ; edge < edge_limit; edge++ ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1351 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1352 | AH_Blue blue; |
| 1353 | FT_Pos* best_blue = 0; |
| 1354 | FT_Pos best_dist; /* initial threshold */ |
| 1355 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1356 | |
| 1357 | /* compute the initial threshold as a fraction of the EM size */ |
| 1358 | best_dist = FT_MulFix( face_globals->face->units_per_EM / 40, y_scale ); |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1359 | if ( best_dist > 64 / 4 ) |
| 1360 | best_dist = 64 / 4; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1361 | |
Werner Lemberg | c3dd151 | 2000-07-26 14:11:15 +0000 | [diff] [blame] | 1362 | for ( blue = ah_blue_capital_top; blue < ah_blue_max; blue++ ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1363 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1364 | /* if it is a top zone, check for right edges -- if it is a bottom */ |
| 1365 | /* zone, check for left edges */ |
| 1366 | /* */ |
| 1367 | /* of course, that's for TrueType XXX */ |
Werner Lemberg | 8eb0353 | 2001-06-19 23:03:41 +0000 | [diff] [blame] | 1368 | FT_Bool is_top_blue = |
| 1369 | FT_BOOL( AH_IS_TOP_BLUE( blue ) ); |
| 1370 | FT_Bool is_major_dir = |
| 1371 | FT_BOOL( edge->dir == outline->horz_major_dir ); |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1372 | |
David Turner | 66cb479 | 2001-05-14 14:04:23 +0000 | [diff] [blame] | 1373 | if ( !blue_active[blue] ) |
| 1374 | continue; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1375 | |
| 1376 | /* if it is a top zone, the edge must be against the major */ |
| 1377 | /* direction; if it is a bottom zone, it must be in the major */ |
| 1378 | /* direction */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1379 | if ( is_top_blue ^ is_major_dir ) |
| 1380 | { |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1381 | FT_Pos dist; |
| 1382 | FT_Pos* blue_pos = globals->blue_refs + blue; |
| 1383 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1384 | |
| 1385 | /* first of all, compare it to the reference position */ |
| 1386 | dist = edge->fpos - *blue_pos; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1387 | if ( dist < 0 ) |
| 1388 | dist = -dist; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1389 | |
| 1390 | dist = FT_MulFix( dist, y_scale ); |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1391 | if ( dist < best_dist ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1392 | { |
| 1393 | best_dist = dist; |
| 1394 | best_blue = blue_pos; |
| 1395 | } |
| 1396 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1397 | /* now, compare it to the overshoot position if the edge is */ |
| 1398 | /* rounded, and if the edge is over the reference position of a */ |
| 1399 | /* top zone, or under the reference position of a bottom zone */ |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1400 | if ( edge->flags & ah_edge_round && dist != 0 ) |
| 1401 | { |
David Turner | 8edbcab | 2001-06-19 08:28:24 +0000 | [diff] [blame] | 1402 | FT_Bool is_under_ref = FT_BOOL( edge->fpos < *blue_pos ); |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1403 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1404 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1405 | if ( is_top_blue ^ is_under_ref ) |
| 1406 | { |
| 1407 | blue_pos = globals->blue_shoots + blue; |
| 1408 | dist = edge->fpos - *blue_pos; |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1409 | if ( dist < 0 ) |
| 1410 | dist = -dist; |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1411 | |
| 1412 | dist = FT_MulFix( dist, y_scale ); |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1413 | if ( dist < best_dist ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1414 | { |
| 1415 | best_dist = dist; |
| 1416 | best_blue = blue_pos; |
| 1417 | } |
| 1418 | } |
| 1419 | } |
| 1420 | } |
| 1421 | } |
| 1422 | |
Werner Lemberg | db578ae | 2000-07-23 21:27:52 +0000 | [diff] [blame] | 1423 | if ( best_blue ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1424 | edge->blue_edge = best_blue; |
| 1425 | } |
| 1426 | } |
| 1427 | |
| 1428 | |
Werner Lemberg | c3dd151 | 2000-07-26 14:11:15 +0000 | [diff] [blame] | 1429 | /*************************************************************************/ |
| 1430 | /* */ |
| 1431 | /* <Function> */ |
| 1432 | /* ah_outline_scale_blue_edges */ |
| 1433 | /* */ |
| 1434 | /* <Description> */ |
| 1435 | /* This functions must be called before hinting in order to re-adjust */ |
| 1436 | /* the contents of the detected edges (basically change the `blue */ |
| 1437 | /* edge' pointer from `design units' to `scaled ones'). */ |
| 1438 | /* */ |
David Turner | bc82f1b | 2002-03-01 02:26:22 +0000 | [diff] [blame] | 1439 | FT_LOCAL_DEF( void ) |
Werner Lemberg | f814d0f | 2001-06-27 16:18:10 +0000 | [diff] [blame] | 1440 | ah_outline_scale_blue_edges( AH_Outline* outline, |
| 1441 | AH_Face_Globals* globals ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1442 | { |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 1443 | AH_Edge* edge = outline->horz_edges; |
| 1444 | AH_Edge* edge_limit = edge + outline->num_hedges; |
Werner Lemberg | c3dd151 | 2000-07-26 14:11:15 +0000 | [diff] [blame] | 1445 | FT_Int delta; |
| 1446 | |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1447 | |
| 1448 | delta = globals->scaled.blue_refs - globals->design.blue_refs; |
Werner Lemberg | c3dd151 | 2000-07-26 14:11:15 +0000 | [diff] [blame] | 1449 | |
Werner Lemberg | e72c9fe | 2000-07-31 18:59:02 +0000 | [diff] [blame] | 1450 | for ( ; edge < edge_limit; edge++ ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1451 | { |
Werner Lemberg | c3dd151 | 2000-07-26 14:11:15 +0000 | [diff] [blame] | 1452 | if ( edge->blue_edge ) |
David Turner | 3469d0d | 2000-07-19 20:02:14 +0000 | [diff] [blame] | 1453 | edge->blue_edge += delta; |
| 1454 | } |
| 1455 | } |
| 1456 | |
| 1457 | |
Werner Lemberg | c3dd151 | 2000-07-26 14:11:15 +0000 | [diff] [blame] | 1458 | /* END */ |