PageRenderTime 81ms CodeModel.GetById 21ms app.highlight 50ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/freetype2/src/base/ftoutln.c

http://github.com/zpao/v8monkey
C | 1129 lines | 762 code | 283 blank | 84 comment | 175 complexity | baddae4a33ff460396acfb26b10b656f MD5 | raw file
   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 */