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