misc/libfreetype/src/base/ftoutln.c
changeset 5172 88f2e05288ba
equal deleted inserted replaced
5171:f9283dc4860d 5172:88f2e05288ba
       
     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 */