| 1 | /***************************************************************************/ | 
| 2 | /*                                                                         */ | 
| 3 | /*  ftoutln.c                                                              */ | 
| 4 | /*                                                                         */ | 
| 5 | /*    FreeType outline management (body).                                  */ | 
| 6 | /*                                                                         */ | 
| 7 | /*  Copyright 1996-2018 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 |   /*************************************************************************/ | 
| 20 |   /*                                                                       */ | 
| 21 |   /* All functions are declared in freetype.h.                             */ | 
| 22 |   /*                                                                       */ | 
| 23 |   /*************************************************************************/ | 
| 24 |  | 
| 25 |  | 
| 26 | #include <ft2build.h> | 
| 27 | #include FT_OUTLINE_H | 
| 28 | #include FT_INTERNAL_OBJECTS_H | 
| 29 | #include FT_INTERNAL_CALC_H | 
| 30 | #include FT_INTERNAL_DEBUG_H | 
| 31 | #include FT_TRIGONOMETRY_H | 
| 32 |  | 
| 33 |  | 
| 34 |   /*************************************************************************/ | 
| 35 |   /*                                                                       */ | 
| 36 |   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */ | 
| 37 |   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */ | 
| 38 |   /* messages during execution.                                            */ | 
| 39 |   /*                                                                       */ | 
| 40 | #undef  FT_COMPONENT | 
| 41 | #define FT_COMPONENT  trace_outline | 
| 42 |  | 
| 43 |  | 
| 44 |   static | 
| 45 |   const FT_Outline  null_outline = { 0, 0, NULL, NULL, NULL, 0 }; | 
| 46 |  | 
| 47 |  | 
| 48 |   /* documentation is in ftoutln.h */ | 
| 49 |  | 
| 50 |   FT_EXPORT_DEF( FT_Error ) | 
| 51 |   FT_Outline_Decompose( FT_Outline*              outline, | 
| 52 |                         const FT_Outline_Funcs*  func_interface, | 
| 53 |                         void*                    user ) | 
| 54 |   { | 
| 55 | #undef  SCALED | 
| 56 | #define SCALED( x )  ( ( (x) < 0 ? -( -(x) << shift )             \ | 
| 57 |                                  :  (  (x) << shift ) ) - delta ) | 
| 58 |  | 
| 59 |     FT_Vector   v_last; | 
| 60 |     FT_Vector   v_control; | 
| 61 |     FT_Vector   v_start; | 
| 62 |  | 
| 63 |     FT_Vector*  point; | 
| 64 |     FT_Vector*  limit; | 
| 65 |     char*       tags; | 
| 66 |  | 
| 67 |     FT_Error    error; | 
| 68 |  | 
| 69 |     FT_Int   n;         /* index of contour in outline     */ | 
| 70 |     FT_UInt  first;     /* index of first point in contour */ | 
| 71 |     FT_Int   tag;       /* current point's state           */ | 
| 72 |  | 
| 73 |     FT_Int   shift; | 
| 74 |     FT_Pos   delta; | 
| 75 |  | 
| 76 |  | 
| 77 |     if ( !outline ) | 
| 78 |       return FT_THROW( Invalid_Outline ); | 
| 79 |  | 
| 80 |     if ( !func_interface ) | 
| 81 |       return FT_THROW( Invalid_Argument ); | 
| 82 |  | 
| 83 |     shift = func_interface->shift; | 
| 84 |     delta = func_interface->delta; | 
| 85 |     first = 0; | 
| 86 |  | 
| 87 |     for ( n = 0; n < outline->n_contours; n++ ) | 
| 88 |     { | 
| 89 |       FT_Int  last;  /* index of last point in contour */ | 
| 90 |  | 
| 91 |  | 
| 92 |       FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n" , n )); | 
| 93 |  | 
| 94 |       last = outline->contours[n]; | 
| 95 |       if ( last < 0 ) | 
| 96 |         goto Invalid_Outline; | 
| 97 |       limit = outline->points + last; | 
| 98 |  | 
| 99 |       v_start   = outline->points[first]; | 
| 100 |       v_start.x = SCALED( v_start.x ); | 
| 101 |       v_start.y = SCALED( v_start.y ); | 
| 102 |  | 
| 103 |       v_last   = outline->points[last]; | 
| 104 |       v_last.x = SCALED( v_last.x ); | 
| 105 |       v_last.y = SCALED( v_last.y ); | 
| 106 |  | 
| 107 |       v_control = v_start; | 
| 108 |  | 
| 109 |       point = outline->points + first; | 
| 110 |       tags  = outline->tags   + first; | 
| 111 |       tag   = FT_CURVE_TAG( tags[0] ); | 
| 112 |  | 
| 113 |       /* A contour cannot start with a cubic control point! */ | 
| 114 |       if ( tag == FT_CURVE_TAG_CUBIC ) | 
| 115 |         goto Invalid_Outline; | 
| 116 |  | 
| 117 |       /* check first point to determine origin */ | 
| 118 |       if ( tag == FT_CURVE_TAG_CONIC ) | 
| 119 |       { | 
| 120 |         /* first point is conic control.  Yes, this happens. */ | 
| 121 |         if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) | 
| 122 |         { | 
| 123 |           /* start at last point if it is on the curve */ | 
| 124 |           v_start = v_last; | 
| 125 |           limit--; | 
| 126 |         } | 
| 127 |         else | 
| 128 |         { | 
| 129 |           /* if both first and last points are conic,         */ | 
| 130 |           /* start at their middle and record its position    */ | 
| 131 |           /* for closure                                      */ | 
| 132 |           v_start.x = ( v_start.x + v_last.x ) / 2; | 
| 133 |           v_start.y = ( v_start.y + v_last.y ) / 2; | 
| 134 |  | 
| 135 |        /* v_last = v_start; */ | 
| 136 |         } | 
| 137 |         point--; | 
| 138 |         tags--; | 
| 139 |       } | 
| 140 |  | 
| 141 |       FT_TRACE5(( "  move to (%.2f, %.2f)\n" , | 
| 142 |                   v_start.x / 64.0, v_start.y / 64.0 )); | 
| 143 |       error = func_interface->move_to( &v_start, user ); | 
| 144 |       if ( error ) | 
| 145 |         goto Exit; | 
| 146 |  | 
| 147 |       while ( point < limit ) | 
| 148 |       { | 
| 149 |         point++; | 
| 150 |         tags++; | 
| 151 |  | 
| 152 |         tag = FT_CURVE_TAG( tags[0] ); | 
| 153 |         switch ( tag ) | 
| 154 |         { | 
| 155 |         case FT_CURVE_TAG_ON:  /* emit a single line_to */ | 
| 156 |           { | 
| 157 |             FT_Vector  vec; | 
| 158 |  | 
| 159 |  | 
| 160 |             vec.x = SCALED( point->x ); | 
| 161 |             vec.y = SCALED( point->y ); | 
| 162 |  | 
| 163 |             FT_TRACE5(( "  line to (%.2f, %.2f)\n" , | 
| 164 |                         vec.x / 64.0, vec.y / 64.0 )); | 
| 165 |             error = func_interface->line_to( &vec, user ); | 
| 166 |             if ( error ) | 
| 167 |               goto Exit; | 
| 168 |             continue; | 
| 169 |           } | 
| 170 |  | 
| 171 |         case FT_CURVE_TAG_CONIC:  /* consume conic arcs */ | 
| 172 |           v_control.x = SCALED( point->x ); | 
| 173 |           v_control.y = SCALED( point->y ); | 
| 174 |  | 
| 175 |         Do_Conic: | 
| 176 |           if ( point < limit ) | 
| 177 |           { | 
| 178 |             FT_Vector  vec; | 
| 179 |             FT_Vector  v_middle; | 
| 180 |  | 
| 181 |  | 
| 182 |             point++; | 
| 183 |             tags++; | 
| 184 |             tag = FT_CURVE_TAG( tags[0] ); | 
| 185 |  | 
| 186 |             vec.x = SCALED( point->x ); | 
| 187 |             vec.y = SCALED( point->y ); | 
| 188 |  | 
| 189 |             if ( tag == FT_CURVE_TAG_ON ) | 
| 190 |             { | 
| 191 |               FT_TRACE5(( "  conic to (%.2f, %.2f)"  | 
| 192 |                           " with control (%.2f, %.2f)\n" , | 
| 193 |                           vec.x / 64.0, vec.y / 64.0, | 
| 194 |                           v_control.x / 64.0, v_control.y / 64.0 )); | 
| 195 |               error = func_interface->conic_to( &v_control, &vec, user ); | 
| 196 |               if ( error ) | 
| 197 |                 goto Exit; | 
| 198 |               continue; | 
| 199 |             } | 
| 200 |  | 
| 201 |             if ( tag != FT_CURVE_TAG_CONIC ) | 
| 202 |               goto Invalid_Outline; | 
| 203 |  | 
| 204 |             v_middle.x = ( v_control.x + vec.x ) / 2; | 
| 205 |             v_middle.y = ( v_control.y + vec.y ) / 2; | 
| 206 |  | 
| 207 |             FT_TRACE5(( "  conic to (%.2f, %.2f)"  | 
| 208 |                         " with control (%.2f, %.2f)\n" , | 
| 209 |                         v_middle.x / 64.0, v_middle.y / 64.0, | 
| 210 |                         v_control.x / 64.0, v_control.y / 64.0 )); | 
| 211 |             error = func_interface->conic_to( &v_control, &v_middle, user ); | 
| 212 |             if ( error ) | 
| 213 |               goto Exit; | 
| 214 |  | 
| 215 |             v_control = vec; | 
| 216 |             goto Do_Conic; | 
| 217 |           } | 
| 218 |  | 
| 219 |           FT_TRACE5(( "  conic to (%.2f, %.2f)"  | 
| 220 |                       " with control (%.2f, %.2f)\n" , | 
| 221 |                       v_start.x / 64.0, v_start.y / 64.0, | 
| 222 |                       v_control.x / 64.0, v_control.y / 64.0 )); | 
| 223 |           error = func_interface->conic_to( &v_control, &v_start, user ); | 
| 224 |           goto Close; | 
| 225 |  | 
| 226 |         default:  /* FT_CURVE_TAG_CUBIC */ | 
| 227 |           { | 
| 228 |             FT_Vector  vec1, vec2; | 
| 229 |  | 
| 230 |  | 
| 231 |             if ( point + 1 > limit                             || | 
| 232 |                  FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) | 
| 233 |               goto Invalid_Outline; | 
| 234 |  | 
| 235 |             point += 2; | 
| 236 |             tags  += 2; | 
| 237 |  | 
| 238 |             vec1.x = SCALED( point[-2].x ); | 
| 239 |             vec1.y = SCALED( point[-2].y ); | 
| 240 |  | 
| 241 |             vec2.x = SCALED( point[-1].x ); | 
| 242 |             vec2.y = SCALED( point[-1].y ); | 
| 243 |  | 
| 244 |             if ( point <= limit ) | 
| 245 |             { | 
| 246 |               FT_Vector  vec; | 
| 247 |  | 
| 248 |  | 
| 249 |               vec.x = SCALED( point->x ); | 
| 250 |               vec.y = SCALED( point->y ); | 
| 251 |  | 
| 252 |               FT_TRACE5(( "  cubic to (%.2f, %.2f)"  | 
| 253 |                           " with controls (%.2f, %.2f) and (%.2f, %.2f)\n" , | 
| 254 |                           vec.x / 64.0, vec.y / 64.0, | 
| 255 |                           vec1.x / 64.0, vec1.y / 64.0, | 
| 256 |                           vec2.x / 64.0, vec2.y / 64.0 )); | 
| 257 |               error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); | 
| 258 |               if ( error ) | 
| 259 |                 goto Exit; | 
| 260 |               continue; | 
| 261 |             } | 
| 262 |  | 
| 263 |             FT_TRACE5(( "  cubic to (%.2f, %.2f)"  | 
| 264 |                         " with controls (%.2f, %.2f) and (%.2f, %.2f)\n" , | 
| 265 |                         v_start.x / 64.0, v_start.y / 64.0, | 
| 266 |                         vec1.x / 64.0, vec1.y / 64.0, | 
| 267 |                         vec2.x / 64.0, vec2.y / 64.0 )); | 
| 268 |             error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); | 
| 269 |             goto Close; | 
| 270 |           } | 
| 271 |         } | 
| 272 |       } | 
| 273 |  | 
| 274 |       /* close the contour with a line segment */ | 
| 275 |       FT_TRACE5(( "  line to (%.2f, %.2f)\n" , | 
| 276 |                   v_start.x / 64.0, v_start.y / 64.0 )); | 
| 277 |       error = func_interface->line_to( &v_start, user ); | 
| 278 |  | 
| 279 |     Close: | 
| 280 |       if ( error ) | 
| 281 |         goto Exit; | 
| 282 |  | 
| 283 |       first = (FT_UInt)last + 1; | 
| 284 |     } | 
| 285 |  | 
| 286 |     FT_TRACE5(( "FT_Outline_Decompose: Done\n" , n )); | 
| 287 |     return FT_Err_Ok; | 
| 288 |  | 
| 289 |   Invalid_Outline: | 
| 290 |     error = FT_THROW( Invalid_Outline ); | 
| 291 |     /* fall through */ | 
| 292 |  | 
| 293 |   Exit: | 
| 294 |     FT_TRACE5(( "FT_Outline_Decompose: Error 0x%x\n" , error )); | 
| 295 |     return error; | 
| 296 |   } | 
| 297 |  | 
| 298 |  | 
| 299 |   FT_EXPORT_DEF( FT_Error ) | 
| 300 |   FT_Outline_New_Internal( FT_Memory    memory, | 
| 301 |                            FT_UInt      numPoints, | 
| 302 |                            FT_Int       numContours, | 
| 303 |                            FT_Outline  *anoutline ) | 
| 304 |   { | 
| 305 |     FT_Error  error; | 
| 306 |  | 
| 307 |  | 
| 308 |     if ( !anoutline || !memory ) | 
| 309 |       return FT_THROW( Invalid_Argument ); | 
| 310 |  | 
| 311 |     *anoutline = null_outline; | 
| 312 |  | 
| 313 |     if ( numContours < 0                  || | 
| 314 |          (FT_UInt)numContours > numPoints ) | 
| 315 |       return FT_THROW( Invalid_Argument ); | 
| 316 |  | 
| 317 |     if ( numPoints > FT_OUTLINE_POINTS_MAX ) | 
| 318 |       return FT_THROW( Array_Too_Large ); | 
| 319 |  | 
| 320 |     if ( FT_NEW_ARRAY( anoutline->points,   numPoints   ) || | 
| 321 |          FT_NEW_ARRAY( anoutline->tags,     numPoints   ) || | 
| 322 |          FT_NEW_ARRAY( anoutline->contours, numContours ) ) | 
| 323 |       goto Fail; | 
| 324 |  | 
| 325 |     anoutline->n_points    = (FT_Short)numPoints; | 
| 326 |     anoutline->n_contours  = (FT_Short)numContours; | 
| 327 |     anoutline->flags      |= FT_OUTLINE_OWNER; | 
| 328 |  | 
| 329 |     return FT_Err_Ok; | 
| 330 |  | 
| 331 |   Fail: | 
| 332 |     anoutline->flags |= FT_OUTLINE_OWNER; | 
| 333 |     FT_Outline_Done_Internal( memory, anoutline ); | 
| 334 |  | 
| 335 |     return error; | 
| 336 |   } | 
| 337 |  | 
| 338 |  | 
| 339 |   /* documentation is in ftoutln.h */ | 
| 340 |  | 
| 341 |   FT_EXPORT_DEF( FT_Error ) | 
| 342 |   FT_Outline_New( FT_Library   library, | 
| 343 |                   FT_UInt      numPoints, | 
| 344 |                   FT_Int       numContours, | 
| 345 |                   FT_Outline  *anoutline ) | 
| 346 |   { | 
| 347 |     if ( !library ) | 
| 348 |       return FT_THROW( Invalid_Library_Handle ); | 
| 349 |  | 
| 350 |     return FT_Outline_New_Internal( library->memory, numPoints, | 
| 351 |                                     numContours, anoutline ); | 
| 352 |   } | 
| 353 |  | 
| 354 |  | 
| 355 |   /* documentation is in ftoutln.h */ | 
| 356 |  | 
| 357 |   FT_EXPORT_DEF( FT_Error ) | 
| 358 |   FT_Outline_Check( FT_Outline*  outline ) | 
| 359 |   { | 
| 360 |     if ( outline ) | 
| 361 |     { | 
| 362 |       FT_Int  n_points   = outline->n_points; | 
| 363 |       FT_Int  n_contours = outline->n_contours; | 
| 364 |       FT_Int  end0, end; | 
| 365 |       FT_Int  n; | 
| 366 |  | 
| 367 |  | 
| 368 |       /* empty glyph? */ | 
| 369 |       if ( n_points == 0 && n_contours == 0 ) | 
| 370 |         return FT_Err_Ok; | 
| 371 |  | 
| 372 |       /* check point and contour counts */ | 
| 373 |       if ( n_points <= 0 || n_contours <= 0 ) | 
| 374 |         goto Bad; | 
| 375 |  | 
| 376 |       end0 = end = -1; | 
| 377 |       for ( n = 0; n < n_contours; n++ ) | 
| 378 |       { | 
| 379 |         end = outline->contours[n]; | 
| 380 |  | 
| 381 |         /* note that we don't accept empty contours */ | 
| 382 |         if ( end <= end0 || end >= n_points ) | 
| 383 |           goto Bad; | 
| 384 |  | 
| 385 |         end0 = end; | 
| 386 |       } | 
| 387 |  | 
| 388 |       if ( end != n_points - 1 ) | 
| 389 |         goto Bad; | 
| 390 |  | 
| 391 |       /* XXX: check the tags array */ | 
| 392 |       return FT_Err_Ok; | 
| 393 |     } | 
| 394 |  | 
| 395 |   Bad: | 
| 396 |     return FT_THROW( Invalid_Argument ); | 
| 397 |   } | 
| 398 |  | 
| 399 |  | 
| 400 |   /* documentation is in ftoutln.h */ | 
| 401 |  | 
| 402 |   FT_EXPORT_DEF( FT_Error ) | 
| 403 |   FT_Outline_Copy( const FT_Outline*  source, | 
| 404 |                    FT_Outline        *target ) | 
| 405 |   { | 
| 406 |     FT_Int  is_owner; | 
| 407 |  | 
| 408 |  | 
| 409 |     if ( !source || !target ) | 
| 410 |       return FT_THROW( Invalid_Outline ); | 
| 411 |  | 
| 412 |     if ( source->n_points   != target->n_points   || | 
| 413 |          source->n_contours != target->n_contours ) | 
| 414 |       return FT_THROW( Invalid_Argument ); | 
| 415 |  | 
| 416 |     if ( source == target ) | 
| 417 |       return FT_Err_Ok; | 
| 418 |  | 
| 419 |     if ( source->n_points ) | 
| 420 |     { | 
| 421 |       FT_ARRAY_COPY( target->points, source->points, source->n_points ); | 
| 422 |       FT_ARRAY_COPY( target->tags,   source->tags,   source->n_points ); | 
| 423 |     } | 
| 424 |  | 
| 425 |     if ( source->n_contours ) | 
| 426 |       FT_ARRAY_COPY( target->contours, source->contours, source->n_contours ); | 
| 427 |  | 
| 428 |     /* copy all flags, except the `FT_OUTLINE_OWNER' one */ | 
| 429 |     is_owner      = target->flags & FT_OUTLINE_OWNER; | 
| 430 |     target->flags = source->flags; | 
| 431 |  | 
| 432 |     target->flags &= ~FT_OUTLINE_OWNER; | 
| 433 |     target->flags |= is_owner; | 
| 434 |  | 
| 435 |     return FT_Err_Ok; | 
| 436 |   } | 
| 437 |  | 
| 438 |  | 
| 439 |   FT_EXPORT_DEF( FT_Error ) | 
| 440 |   FT_Outline_Done_Internal( FT_Memory    memory, | 
| 441 |                             FT_Outline*  outline ) | 
| 442 |   { | 
| 443 |     if ( !outline ) | 
| 444 |       return FT_THROW( Invalid_Outline ); | 
| 445 |  | 
| 446 |     if ( !memory ) | 
| 447 |       return FT_THROW( Invalid_Argument ); | 
| 448 |  | 
| 449 |     if ( outline->flags & FT_OUTLINE_OWNER ) | 
| 450 |     { | 
| 451 |       FT_FREE( outline->points   ); | 
| 452 |       FT_FREE( outline->tags     ); | 
| 453 |       FT_FREE( outline->contours ); | 
| 454 |     } | 
| 455 |     *outline = null_outline; | 
| 456 |  | 
| 457 |     return FT_Err_Ok; | 
| 458 |   } | 
| 459 |  | 
| 460 |  | 
| 461 |   /* documentation is in ftoutln.h */ | 
| 462 |  | 
| 463 |   FT_EXPORT_DEF( FT_Error ) | 
| 464 |   FT_Outline_Done( FT_Library   library, | 
| 465 |                    FT_Outline*  outline ) | 
| 466 |   { | 
| 467 |     /* check for valid `outline' in FT_Outline_Done_Internal() */ | 
| 468 |  | 
| 469 |     if ( !library ) | 
| 470 |       return FT_THROW( Invalid_Library_Handle ); | 
| 471 |  | 
| 472 |     return FT_Outline_Done_Internal( library->memory, outline ); | 
| 473 |   } | 
| 474 |  | 
| 475 |  | 
| 476 |   /* documentation is in ftoutln.h */ | 
| 477 |  | 
| 478 |   FT_EXPORT_DEF( void ) | 
| 479 |   FT_Outline_Get_CBox( const FT_Outline*  outline, | 
| 480 |                        FT_BBox           *acbox ) | 
| 481 |   { | 
| 482 |     FT_Pos  xMin, yMin, xMax, yMax; | 
| 483 |  | 
| 484 |  | 
| 485 |     if ( outline && acbox ) | 
| 486 |     { | 
| 487 |       if ( outline->n_points == 0 ) | 
| 488 |       { | 
| 489 |         xMin = 0; | 
| 490 |         yMin = 0; | 
| 491 |         xMax = 0; | 
| 492 |         yMax = 0; | 
| 493 |       } | 
| 494 |       else | 
| 495 |       { | 
| 496 |         FT_Vector*  vec   = outline->points; | 
| 497 |         FT_Vector*  limit = vec + outline->n_points; | 
| 498 |  | 
| 499 |  | 
| 500 |         xMin = xMax = vec->x; | 
| 501 |         yMin = yMax = vec->y; | 
| 502 |         vec++; | 
| 503 |  | 
| 504 |         for ( ; vec < limit; vec++ ) | 
| 505 |         { | 
| 506 |           FT_Pos  x, y; | 
| 507 |  | 
| 508 |  | 
| 509 |           x = vec->x; | 
| 510 |           if ( x < xMin ) xMin = x; | 
| 511 |           if ( x > xMax ) xMax = x; | 
| 512 |  | 
| 513 |           y = vec->y; | 
| 514 |           if ( y < yMin ) yMin = y; | 
| 515 |           if ( y > yMax ) yMax = y; | 
| 516 |         } | 
| 517 |       } | 
| 518 |       acbox->xMin = xMin; | 
| 519 |       acbox->xMax = xMax; | 
| 520 |       acbox->yMin = yMin; | 
| 521 |       acbox->yMax = yMax; | 
| 522 |     } | 
| 523 |   } | 
| 524 |  | 
| 525 |  | 
| 526 |   /* documentation is in ftoutln.h */ | 
| 527 |  | 
| 528 |   FT_EXPORT_DEF( void ) | 
| 529 |   FT_Outline_Translate( const FT_Outline*  outline, | 
| 530 |                         FT_Pos             xOffset, | 
| 531 |                         FT_Pos             yOffset ) | 
| 532 |   { | 
| 533 |     FT_UShort   n; | 
| 534 |     FT_Vector*  vec; | 
| 535 |  | 
| 536 |  | 
| 537 |     if ( !outline ) | 
| 538 |       return; | 
| 539 |  | 
| 540 |     vec = outline->points; | 
| 541 |  | 
| 542 |     for ( n = 0; n < outline->n_points; n++ ) | 
| 543 |     { | 
| 544 |       vec->x = ADD_LONG( vec->x, xOffset ); | 
| 545 |       vec->y = ADD_LONG( vec->y, yOffset ); | 
| 546 |       vec++; | 
| 547 |     } | 
| 548 |   } | 
| 549 |  | 
| 550 |  | 
| 551 |   /* documentation is in ftoutln.h */ | 
| 552 |  | 
| 553 |   FT_EXPORT_DEF( void ) | 
| 554 |   FT_Outline_Reverse( FT_Outline*  outline ) | 
| 555 |   { | 
| 556 |     FT_UShort  n; | 
| 557 |     FT_Int     first, last; | 
| 558 |  | 
| 559 |  | 
| 560 |     if ( !outline ) | 
| 561 |       return; | 
| 562 |  | 
| 563 |     first = 0; | 
| 564 |  | 
| 565 |     for ( n = 0; n < outline->n_contours; n++ ) | 
| 566 |     { | 
| 567 |       last  = outline->contours[n]; | 
| 568 |  | 
| 569 |       /* reverse point table */ | 
| 570 |       { | 
| 571 |         FT_Vector*  p = outline->points + first; | 
| 572 |         FT_Vector*  q = outline->points + last; | 
| 573 |         FT_Vector   swap; | 
| 574 |  | 
| 575 |  | 
| 576 |         while ( p < q ) | 
| 577 |         { | 
| 578 |           swap = *p; | 
| 579 |           *p   = *q; | 
| 580 |           *q   = swap; | 
| 581 |           p++; | 
| 582 |           q--; | 
| 583 |         } | 
| 584 |       } | 
| 585 |  | 
| 586 |       /* reverse tags table */ | 
| 587 |       { | 
| 588 |         char*  p = outline->tags + first; | 
| 589 |         char*  q = outline->tags + last; | 
| 590 |  | 
| 591 |  | 
| 592 |         while ( p < q ) | 
| 593 |         { | 
| 594 |           char  swap; | 
| 595 |  | 
| 596 |  | 
| 597 |           swap = *p; | 
| 598 |           *p   = *q; | 
| 599 |           *q   = swap; | 
| 600 |           p++; | 
| 601 |           q--; | 
| 602 |         } | 
| 603 |       } | 
| 604 |  | 
| 605 |       first = last + 1; | 
| 606 |     } | 
| 607 |  | 
| 608 |     outline->flags ^= FT_OUTLINE_REVERSE_FILL; | 
| 609 |   } | 
| 610 |  | 
| 611 |  | 
| 612 |   /* documentation is in ftoutln.h */ | 
| 613 |  | 
| 614 |   FT_EXPORT_DEF( FT_Error ) | 
| 615 |   FT_Outline_Render( FT_Library         library, | 
| 616 |                      FT_Outline*        outline, | 
| 617 |                      FT_Raster_Params*  params ) | 
| 618 |   { | 
| 619 |     FT_Error     error; | 
| 620 |     FT_Renderer  renderer; | 
| 621 |     FT_ListNode  node; | 
| 622 |  | 
| 623 |  | 
| 624 |     if ( !library ) | 
| 625 |       return FT_THROW( Invalid_Library_Handle ); | 
| 626 |  | 
| 627 |     if ( !outline ) | 
| 628 |       return FT_THROW( Invalid_Outline ); | 
| 629 |  | 
| 630 |     if ( !params ) | 
| 631 |       return FT_THROW( Invalid_Argument ); | 
| 632 |  | 
| 633 |     renderer = library->cur_renderer; | 
| 634 |     node     = library->renderers.head; | 
| 635 |  | 
| 636 |     params->source = (void*)outline; | 
| 637 |  | 
| 638 |     error = FT_ERR( Cannot_Render_Glyph ); | 
| 639 |     while ( renderer ) | 
| 640 |     { | 
| 641 |       error = renderer->raster_render( renderer->raster, params ); | 
| 642 |       if ( !error || FT_ERR_NEQ( error, Cannot_Render_Glyph ) ) | 
| 643 |         break; | 
| 644 |  | 
| 645 |       /* FT_Err_Cannot_Render_Glyph is returned if the render mode   */ | 
| 646 |       /* is unsupported by the current renderer for this glyph image */ | 
| 647 |       /* format                                                      */ | 
| 648 |  | 
| 649 |       /* now, look for another renderer that supports the same */ | 
| 650 |       /* format                                                */ | 
| 651 |       renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, | 
| 652 |                                      &node ); | 
| 653 |     } | 
| 654 |  | 
| 655 |     return error; | 
| 656 |   } | 
| 657 |  | 
| 658 |  | 
| 659 |   /* documentation is in ftoutln.h */ | 
| 660 |  | 
| 661 |   FT_EXPORT_DEF( FT_Error ) | 
| 662 |   FT_Outline_Get_Bitmap( FT_Library        library, | 
| 663 |                          FT_Outline*       outline, | 
| 664 |                          const FT_Bitmap  *abitmap ) | 
| 665 |   { | 
| 666 |     FT_Raster_Params  params; | 
| 667 |  | 
| 668 |  | 
| 669 |     if ( !abitmap ) | 
| 670 |       return FT_THROW( Invalid_Argument ); | 
| 671 |  | 
| 672 |     /* other checks are delayed to `FT_Outline_Render' */ | 
| 673 |  | 
| 674 |     params.target = abitmap; | 
| 675 |     params.flags  = 0; | 
| 676 |  | 
| 677 |     if ( abitmap->pixel_mode == FT_PIXEL_MODE_GRAY  || | 
| 678 |          abitmap->pixel_mode == FT_PIXEL_MODE_LCD   || | 
| 679 |          abitmap->pixel_mode == FT_PIXEL_MODE_LCD_V ) | 
| 680 |       params.flags |= FT_RASTER_FLAG_AA; | 
| 681 |  | 
| 682 |     return FT_Outline_Render( library, outline, ¶ms ); | 
| 683 |   } | 
| 684 |  | 
| 685 |  | 
| 686 |   /* documentation is in freetype.h */ | 
| 687 |  | 
| 688 |   FT_EXPORT_DEF( void ) | 
| 689 |   FT_Vector_Transform( FT_Vector*        vector, | 
| 690 |                        const FT_Matrix*  matrix ) | 
| 691 |   { | 
| 692 |     FT_Pos  xz, yz; | 
| 693 |  | 
| 694 |  | 
| 695 |     if ( !vector || !matrix ) | 
| 696 |       return; | 
| 697 |  | 
| 698 |     xz = FT_MulFix( vector->x, matrix->xx ) + | 
| 699 |          FT_MulFix( vector->y, matrix->xy ); | 
| 700 |  | 
| 701 |     yz = FT_MulFix( vector->x, matrix->yx ) + | 
| 702 |          FT_MulFix( vector->y, matrix->yy ); | 
| 703 |  | 
| 704 |     vector->x = xz; | 
| 705 |     vector->y = yz; | 
| 706 |   } | 
| 707 |  | 
| 708 |  | 
| 709 |   /* documentation is in ftoutln.h */ | 
| 710 |  | 
| 711 |   FT_EXPORT_DEF( void ) | 
| 712 |   FT_Outline_Transform( const FT_Outline*  outline, | 
| 713 |                         const FT_Matrix*   matrix ) | 
| 714 |   { | 
| 715 |     FT_Vector*  vec; | 
| 716 |     FT_Vector*  limit; | 
| 717 |  | 
| 718 |  | 
| 719 |     if ( !outline || !matrix ) | 
| 720 |       return; | 
| 721 |  | 
| 722 |     vec   = outline->points; | 
| 723 |     limit = vec + outline->n_points; | 
| 724 |  | 
| 725 |     for ( ; vec < limit; vec++ ) | 
| 726 |       FT_Vector_Transform( vec, matrix ); | 
| 727 |   } | 
| 728 |  | 
| 729 |  | 
| 730 | #if 0 | 
| 731 |  | 
| 732 | #define FT_OUTLINE_GET_CONTOUR( outline, c, first, last )  \ | 
| 733 |   do                                                       \ | 
| 734 |   {                                                        \ | 
| 735 |     (first) = ( c > 0 ) ? (outline)->points +              \ | 
| 736 |                             (outline)->contours[c - 1] + 1 \ | 
| 737 |                         : (outline)->points;               \ | 
| 738 |     (last) = (outline)->points + (outline)->contours[c];   \ | 
| 739 |   } while ( 0 ) | 
| 740 |  | 
| 741 |  | 
| 742 |   /* Is a point in some contour?                     */ | 
| 743 |   /*                                                 */ | 
| 744 |   /* We treat every point of the contour as if it    */ | 
| 745 |   /* it were ON.  That is, we allow false positives, */ | 
| 746 |   /* but disallow false negatives.  (XXX really?)    */ | 
| 747 |   static FT_Bool | 
| 748 |   ft_contour_has( FT_Outline*  outline, | 
| 749 |                   FT_Short     c, | 
| 750 |                   FT_Vector*   point ) | 
| 751 |   { | 
| 752 |     FT_Vector*  first; | 
| 753 |     FT_Vector*  last; | 
| 754 |     FT_Vector*  a; | 
| 755 |     FT_Vector*  b; | 
| 756 |     FT_UInt     n = 0; | 
| 757 |  | 
| 758 |  | 
| 759 |     FT_OUTLINE_GET_CONTOUR( outline, c, first, last ); | 
| 760 |  | 
| 761 |     for ( a = first; a <= last; a++ ) | 
| 762 |     { | 
| 763 |       FT_Pos  x; | 
| 764 |       FT_Int  intersect; | 
| 765 |  | 
| 766 |  | 
| 767 |       b = ( a == last ) ? first : a + 1; | 
| 768 |  | 
| 769 |       intersect = ( a->y - point->y ) ^ ( b->y - point->y ); | 
| 770 |  | 
| 771 |       /* a and b are on the same side */ | 
| 772 |       if ( intersect >= 0 ) | 
| 773 |       { | 
| 774 |         if ( intersect == 0 && a->y == point->y ) | 
| 775 |         { | 
| 776 |           if ( ( a->x <= point->x && b->x >= point->x ) || | 
| 777 |                ( a->x >= point->x && b->x <= point->x ) ) | 
| 778 |             return 1; | 
| 779 |         } | 
| 780 |  | 
| 781 |         continue; | 
| 782 |       } | 
| 783 |  | 
| 784 |       x = a->x + ( b->x - a->x ) * (point->y - a->y ) / ( b->y - a->y ); | 
| 785 |  | 
| 786 |       if ( x < point->x ) | 
| 787 |         n++; | 
| 788 |       else if ( x == point->x ) | 
| 789 |         return 1; | 
| 790 |     } | 
| 791 |  | 
| 792 |     return n & 1; | 
| 793 |   } | 
| 794 |  | 
| 795 |  | 
| 796 |   static FT_Bool | 
| 797 |   ft_contour_enclosed( FT_Outline*  outline, | 
| 798 |                        FT_UShort    c ) | 
| 799 |   { | 
| 800 |     FT_Vector*  first; | 
| 801 |     FT_Vector*  last; | 
| 802 |     FT_Short    i; | 
| 803 |  | 
| 804 |  | 
| 805 |     FT_OUTLINE_GET_CONTOUR( outline, c, first, last ); | 
| 806 |  | 
| 807 |     for ( i = 0; i < outline->n_contours; i++ ) | 
| 808 |     { | 
| 809 |       if ( i != c && ft_contour_has( outline, i, first ) ) | 
| 810 |       { | 
| 811 |         FT_Vector*  pt; | 
| 812 |  | 
| 813 |  | 
| 814 |         for ( pt = first + 1; pt <= last; pt++ ) | 
| 815 |           if ( !ft_contour_has( outline, i, pt ) ) | 
| 816 |             return 0; | 
| 817 |  | 
| 818 |         return 1; | 
| 819 |       } | 
| 820 |     } | 
| 821 |  | 
| 822 |     return 0; | 
| 823 |   } | 
| 824 |  | 
| 825 |  | 
| 826 |   /* This version differs from the public one in that each */ | 
| 827 |   /* part (contour not enclosed in another contour) of the */ | 
| 828 |   /* outline is checked for orientation.  This is          */ | 
| 829 |   /* necessary for some buggy CJK fonts.                   */ | 
| 830 |   static FT_Orientation | 
| 831 |   ft_outline_get_orientation( FT_Outline*  outline ) | 
| 832 |   { | 
| 833 |     FT_Short        i; | 
| 834 |     FT_Vector*      first; | 
| 835 |     FT_Vector*      last; | 
| 836 |     FT_Orientation  orient = FT_ORIENTATION_NONE; | 
| 837 |  | 
| 838 |  | 
| 839 |     first = outline->points; | 
| 840 |     for ( i = 0; i < outline->n_contours; i++, first = last + 1 ) | 
| 841 |     { | 
| 842 |       FT_Vector*  point; | 
| 843 |       FT_Vector*  xmin_point; | 
| 844 |       FT_Pos      xmin; | 
| 845 |  | 
| 846 |  | 
| 847 |       last = outline->points + outline->contours[i]; | 
| 848 |  | 
| 849 |       /* skip degenerate contours */ | 
| 850 |       if ( last < first + 2 ) | 
| 851 |         continue; | 
| 852 |  | 
| 853 |       if ( ft_contour_enclosed( outline, i ) ) | 
| 854 |         continue; | 
| 855 |  | 
| 856 |       xmin       = first->x; | 
| 857 |       xmin_point = first; | 
| 858 |  | 
| 859 |       for ( point = first + 1; point <= last; point++ ) | 
| 860 |       { | 
| 861 |         if ( point->x < xmin ) | 
| 862 |         { | 
| 863 |           xmin       = point->x; | 
| 864 |           xmin_point = point; | 
| 865 |         } | 
| 866 |       } | 
| 867 |  | 
| 868 |       /* check the orientation of the contour */ | 
| 869 |       { | 
| 870 |         FT_Vector*      prev; | 
| 871 |         FT_Vector*      next; | 
| 872 |         FT_Orientation  o; | 
| 873 |  | 
| 874 |  | 
| 875 |         prev = ( xmin_point == first ) ? last : xmin_point - 1; | 
| 876 |         next = ( xmin_point == last ) ? first : xmin_point + 1; | 
| 877 |  | 
| 878 |         if ( FT_Atan2( prev->x - xmin_point->x, prev->y - xmin_point->y ) > | 
| 879 |              FT_Atan2( next->x - xmin_point->x, next->y - xmin_point->y ) ) | 
| 880 |           o = FT_ORIENTATION_POSTSCRIPT; | 
| 881 |         else | 
| 882 |           o = FT_ORIENTATION_TRUETYPE; | 
| 883 |  | 
| 884 |         if ( orient == FT_ORIENTATION_NONE ) | 
| 885 |           orient = o; | 
| 886 |         else if ( orient != o ) | 
| 887 |           return FT_ORIENTATION_NONE; | 
| 888 |       } | 
| 889 |     } | 
| 890 |  | 
| 891 |     return orient; | 
| 892 |   } | 
| 893 |  | 
| 894 | #endif /* 0 */ | 
| 895 |  | 
| 896 |  | 
| 897 |   /* documentation is in ftoutln.h */ | 
| 898 |  | 
| 899 |   FT_EXPORT_DEF( FT_Error ) | 
| 900 |   FT_Outline_Embolden( FT_Outline*  outline, | 
| 901 |                        FT_Pos       strength ) | 
| 902 |   { | 
| 903 |     return FT_Outline_EmboldenXY( outline, strength, strength ); | 
| 904 |   } | 
| 905 |  | 
| 906 |  | 
| 907 |   /* documentation is in ftoutln.h */ | 
| 908 |  | 
| 909 |   FT_EXPORT_DEF( FT_Error ) | 
| 910 |   FT_Outline_EmboldenXY( FT_Outline*  outline, | 
| 911 |                          FT_Pos       xstrength, | 
| 912 |                          FT_Pos       ystrength ) | 
| 913 |   { | 
| 914 |     FT_Vector*  points; | 
| 915 |     FT_Int      c, first, last; | 
| 916 |     FT_Int      orientation; | 
| 917 |  | 
| 918 |  | 
| 919 |     if ( !outline ) | 
| 920 |       return FT_THROW( Invalid_Outline ); | 
| 921 |  | 
| 922 |     xstrength /= 2; | 
| 923 |     ystrength /= 2; | 
| 924 |     if ( xstrength == 0 && ystrength == 0 ) | 
| 925 |       return FT_Err_Ok; | 
| 926 |  | 
| 927 |     orientation = FT_Outline_Get_Orientation( outline ); | 
| 928 |     if ( orientation == FT_ORIENTATION_NONE ) | 
| 929 |     { | 
| 930 |       if ( outline->n_contours ) | 
| 931 |         return FT_THROW( Invalid_Argument ); | 
| 932 |       else | 
| 933 |         return FT_Err_Ok; | 
| 934 |     } | 
| 935 |  | 
| 936 |     points = outline->points; | 
| 937 |  | 
| 938 |     first = 0; | 
| 939 |     for ( c = 0; c < outline->n_contours; c++ ) | 
| 940 |     { | 
| 941 |       FT_Vector  in, out, anchor, shift; | 
| 942 |       FT_Fixed   l_in, l_out, l_anchor = 0, l, q, d; | 
| 943 |       FT_Int     i, j, k; | 
| 944 |  | 
| 945 |  | 
| 946 |       l_in = 0; | 
| 947 |       last = outline->contours[c]; | 
| 948 |  | 
| 949 |       /* pacify compiler */ | 
| 950 |       in.x = in.y = anchor.x = anchor.y = 0; | 
| 951 |  | 
| 952 |       /* Counter j cycles though the points; counter i advances only  */ | 
| 953 |       /* when points are moved; anchor k marks the first moved point. */ | 
| 954 |       for ( i = last, j = first, k = -1; | 
| 955 |             j != i && i != k; | 
| 956 |             j = j < last ? j + 1 : first ) | 
| 957 |       { | 
| 958 |         if ( j != k ) | 
| 959 |         { | 
| 960 |           out.x = points[j].x - points[i].x; | 
| 961 |           out.y = points[j].y - points[i].y; | 
| 962 |           l_out = (FT_Fixed)FT_Vector_NormLen( &out ); | 
| 963 |  | 
| 964 |           if ( l_out == 0 ) | 
| 965 |             continue; | 
| 966 |         } | 
| 967 |         else | 
| 968 |         { | 
| 969 |           out   = anchor; | 
| 970 |           l_out = l_anchor; | 
| 971 |         } | 
| 972 |  | 
| 973 |         if ( l_in != 0 ) | 
| 974 |         { | 
| 975 |           if ( k < 0 ) | 
| 976 |           { | 
| 977 |             k        = i; | 
| 978 |             anchor   = in; | 
| 979 |             l_anchor = l_in; | 
| 980 |           } | 
| 981 |  | 
| 982 |           d = FT_MulFix( in.x, out.x ) + FT_MulFix( in.y, out.y ); | 
| 983 |  | 
| 984 |           /* shift only if turn is less than ~160 degrees */ | 
| 985 |           if ( d > -0xF000L ) | 
| 986 |           { | 
| 987 |             d = d + 0x10000L; | 
| 988 |  | 
| 989 |             /* shift components along lateral bisector in proper orientation */ | 
| 990 |             shift.x = in.y + out.y; | 
| 991 |             shift.y = in.x + out.x; | 
| 992 |  | 
| 993 |             if ( orientation == FT_ORIENTATION_TRUETYPE ) | 
| 994 |               shift.x = -shift.x; | 
| 995 |             else | 
| 996 |               shift.y = -shift.y; | 
| 997 |  | 
| 998 |             /* restrict shift magnitude to better handle collapsing segments */ | 
| 999 |             q = FT_MulFix( out.x, in.y ) - FT_MulFix( out.y, in.x ); | 
| 1000 |             if ( orientation == FT_ORIENTATION_TRUETYPE ) | 
| 1001 |               q = -q; | 
| 1002 |  | 
| 1003 |             l = FT_MIN( l_in, l_out ); | 
| 1004 |  | 
| 1005 |             /* non-strict inequalities avoid divide-by-zero when q == l == 0 */ | 
| 1006 |             if ( FT_MulFix( xstrength, q ) <= FT_MulFix( l, d ) ) | 
| 1007 |               shift.x = FT_MulDiv( shift.x, xstrength, d ); | 
| 1008 |             else | 
| 1009 |               shift.x = FT_MulDiv( shift.x, l, q ); | 
| 1010 |  | 
| 1011 |  | 
| 1012 |             if ( FT_MulFix( ystrength, q ) <= FT_MulFix( l, d ) ) | 
| 1013 |               shift.y = FT_MulDiv( shift.y, ystrength, d ); | 
| 1014 |             else | 
| 1015 |               shift.y = FT_MulDiv( shift.y, l, q ); | 
| 1016 |           } | 
| 1017 |           else | 
| 1018 |             shift.x = shift.y = 0; | 
| 1019 |  | 
| 1020 |           for ( ; | 
| 1021 |                 i != j; | 
| 1022 |                 i = i < last ? i + 1 : first ) | 
| 1023 |           { | 
| 1024 |             points[i].x += xstrength + shift.x; | 
| 1025 |             points[i].y += ystrength + shift.y; | 
| 1026 |           } | 
| 1027 |         } | 
| 1028 |         else | 
| 1029 |           i = j; | 
| 1030 |  | 
| 1031 |         in   = out; | 
| 1032 |         l_in = l_out; | 
| 1033 |       } | 
| 1034 |  | 
| 1035 |       first = last + 1; | 
| 1036 |     } | 
| 1037 |  | 
| 1038 |     return FT_Err_Ok; | 
| 1039 |   } | 
| 1040 |  | 
| 1041 |  | 
| 1042 |   /* documentation is in ftoutln.h */ | 
| 1043 |  | 
| 1044 |   FT_EXPORT_DEF( FT_Orientation ) | 
| 1045 |   FT_Outline_Get_Orientation( FT_Outline*  outline ) | 
| 1046 |   { | 
| 1047 |     FT_BBox     cbox; | 
| 1048 |     FT_Int      xshift, yshift; | 
| 1049 |     FT_Vector*  points; | 
| 1050 |     FT_Vector   v_prev, v_cur; | 
| 1051 |     FT_Int      c, n, first; | 
| 1052 |     FT_Pos      area = 0; | 
| 1053 |  | 
| 1054 |  | 
| 1055 |     if ( !outline || outline->n_points <= 0 ) | 
| 1056 |       return FT_ORIENTATION_TRUETYPE; | 
| 1057 |  | 
| 1058 |     /* We use the nonzero winding rule to find the orientation.       */ | 
| 1059 |     /* Since glyph outlines behave much more `regular' than arbitrary */ | 
| 1060 |     /* cubic or quadratic curves, this test deals with the polygon    */ | 
| 1061 |     /* only that is spanned up by the control points.                 */ | 
| 1062 |  | 
| 1063 |     FT_Outline_Get_CBox( outline, &cbox ); | 
| 1064 |  | 
| 1065 |     /* Handle collapsed outlines to avoid undefined FT_MSB. */ | 
| 1066 |     if ( cbox.xMin == cbox.xMax || cbox.yMin == cbox.yMax ) | 
| 1067 |       return FT_ORIENTATION_NONE; | 
| 1068 |  | 
| 1069 |     xshift = FT_MSB( (FT_UInt32)( FT_ABS( cbox.xMax ) | | 
| 1070 |                                   FT_ABS( cbox.xMin ) ) ) - 14; | 
| 1071 |     xshift = FT_MAX( xshift, 0 ); | 
| 1072 |  | 
| 1073 |     yshift = FT_MSB( (FT_UInt32)( cbox.yMax - cbox.yMin ) ) - 14; | 
| 1074 |     yshift = FT_MAX( yshift, 0 ); | 
| 1075 |  | 
| 1076 |     points = outline->points; | 
| 1077 |  | 
| 1078 |     first = 0; | 
| 1079 |     for ( c = 0; c < outline->n_contours; c++ ) | 
| 1080 |     { | 
| 1081 |       FT_Int  last = outline->contours[c]; | 
| 1082 |  | 
| 1083 |  | 
| 1084 |       v_prev.x = points[last].x >> xshift; | 
| 1085 |       v_prev.y = points[last].y >> yshift; | 
| 1086 |  | 
| 1087 |       for ( n = first; n <= last; n++ ) | 
| 1088 |       { | 
| 1089 |         v_cur.x = points[n].x >> xshift; | 
| 1090 |         v_cur.y = points[n].y >> yshift; | 
| 1091 |  | 
| 1092 |         area = ADD_LONG( area, | 
| 1093 |                          ( v_cur.y - v_prev.y ) * ( v_cur.x + v_prev.x ) ); | 
| 1094 |  | 
| 1095 |         v_prev = v_cur; | 
| 1096 |       } | 
| 1097 |  | 
| 1098 |       first = last + 1; | 
| 1099 |     } | 
| 1100 |  | 
| 1101 |     if ( area > 0 ) | 
| 1102 |       return FT_ORIENTATION_POSTSCRIPT; | 
| 1103 |     else if ( area < 0 ) | 
| 1104 |       return FT_ORIENTATION_TRUETYPE; | 
| 1105 |     else | 
| 1106 |       return FT_ORIENTATION_NONE; | 
| 1107 |   } | 
| 1108 |  | 
| 1109 |  | 
| 1110 | /* END */ | 
| 1111 |  |