ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

ftstroke.c
Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  ftstroke.c                                                             */
00004 /*                                                                         */
00005 /*    FreeType path stroker (body).                                        */
00006 /*                                                                         */
00007 /*  Copyright 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010 by            */
00008 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00009 /*                                                                         */
00010 /*  This file is part of the FreeType project, and may only be used,       */
00011 /*  modified, and distributed under the terms of the FreeType project      */
00012 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00013 /*  this file you indicate that you have read the license and              */
00014 /*  understand and accept it fully.                                        */
00015 /*                                                                         */
00016 /***************************************************************************/
00017 
00018 
00019 #include <ft2build.h>
00020 #include FT_STROKER_H
00021 #include FT_TRIGONOMETRY_H
00022 #include FT_OUTLINE_H
00023 #include FT_INTERNAL_MEMORY_H
00024 #include FT_INTERNAL_DEBUG_H
00025 #include FT_INTERNAL_OBJECTS_H
00026 
00027 
00028   /* documentation is in ftstroke.h */
00029 
00030   FT_EXPORT_DEF( FT_StrokerBorder )
00031   FT_Outline_GetInsideBorder( FT_Outline*  outline )
00032   {
00033     FT_Orientation  o = FT_Outline_Get_Orientation( outline );
00034 
00035 
00036     return o == FT_ORIENTATION_TRUETYPE ? FT_STROKER_BORDER_RIGHT
00037                                         : FT_STROKER_BORDER_LEFT ;
00038   }
00039 
00040 
00041   /* documentation is in ftstroke.h */
00042 
00043   FT_EXPORT_DEF( FT_StrokerBorder )
00044   FT_Outline_GetOutsideBorder( FT_Outline*  outline )
00045   {
00046     FT_Orientation  o = FT_Outline_Get_Orientation( outline );
00047 
00048 
00049     return o == FT_ORIENTATION_TRUETYPE ? FT_STROKER_BORDER_LEFT
00050                                         : FT_STROKER_BORDER_RIGHT ;
00051   }
00052 
00053 
00054  /***************************************************************************/
00055  /***************************************************************************/
00056  /*****                                                                 *****/
00057  /*****                       BEZIER COMPUTATIONS                       *****/
00058  /*****                                                                 *****/
00059  /***************************************************************************/
00060  /***************************************************************************/
00061 
00062 #define FT_SMALL_CONIC_THRESHOLD  ( FT_ANGLE_PI / 6 )
00063 #define FT_SMALL_CUBIC_THRESHOLD  ( FT_ANGLE_PI / 6 )
00064 #define FT_EPSILON  2
00065 
00066 #define FT_IS_SMALL( x )  ( (x) > -FT_EPSILON && (x) < FT_EPSILON )
00067 
00068 
00069   static FT_Pos
00070   ft_pos_abs( FT_Pos  x )
00071   {
00072     return x >= 0 ? x : -x ;
00073   }
00074 
00075 
00076   static void
00077   ft_conic_split( FT_Vector*  base )
00078   {
00079     FT_Pos  a, b;
00080 
00081 
00082     base[4].x = base[2].x;
00083     b = base[1].x;
00084     a = base[3].x = ( base[2].x + b ) / 2;
00085     b = base[1].x = ( base[0].x + b ) / 2;
00086     base[2].x = ( a + b ) / 2;
00087 
00088     base[4].y = base[2].y;
00089     b = base[1].y;
00090     a = base[3].y = ( base[2].y + b ) / 2;
00091     b = base[1].y = ( base[0].y + b ) / 2;
00092     base[2].y = ( a + b ) / 2;
00093   }
00094 
00095 
00096   static FT_Bool
00097   ft_conic_is_small_enough( FT_Vector*  base,
00098                             FT_Angle   *angle_in,
00099                             FT_Angle   *angle_out )
00100   {
00101     FT_Vector  d1, d2;
00102     FT_Angle   theta;
00103     FT_Int     close1, close2;
00104 
00105 
00106     d1.x = base[1].x - base[2].x;
00107     d1.y = base[1].y - base[2].y;
00108     d2.x = base[0].x - base[1].x;
00109     d2.y = base[0].y - base[1].y;
00110 
00111     close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y );
00112     close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y );
00113 
00114     if ( close1 )
00115     {
00116       if ( close2 )
00117         *angle_in = *angle_out = 0;
00118       else
00119         *angle_in = *angle_out = FT_Atan2( d2.x, d2.y );
00120     }
00121     else if ( close2 )
00122     {
00123       *angle_in = *angle_out = FT_Atan2( d1.x, d1.y );
00124     }
00125     else
00126     {
00127       *angle_in  = FT_Atan2( d1.x, d1.y );
00128       *angle_out = FT_Atan2( d2.x, d2.y );
00129     }
00130 
00131     theta = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_out ) );
00132 
00133     return FT_BOOL( theta < FT_SMALL_CONIC_THRESHOLD );
00134   }
00135 
00136 
00137   static void
00138   ft_cubic_split( FT_Vector*  base )
00139   {
00140     FT_Pos  a, b, c, d;
00141 
00142 
00143     base[6].x = base[3].x;
00144     c = base[1].x;
00145     d = base[2].x;
00146     base[1].x = a = ( base[0].x + c ) / 2;
00147     base[5].x = b = ( base[3].x + d ) / 2;
00148     c = ( c + d ) / 2;
00149     base[2].x = a = ( a + c ) / 2;
00150     base[4].x = b = ( b + c ) / 2;
00151     base[3].x = ( a + b ) / 2;
00152 
00153     base[6].y = base[3].y;
00154     c = base[1].y;
00155     d = base[2].y;
00156     base[1].y = a = ( base[0].y + c ) / 2;
00157     base[5].y = b = ( base[3].y + d ) / 2;
00158     c = ( c + d ) / 2;
00159     base[2].y = a = ( a + c ) / 2;
00160     base[4].y = b = ( b + c ) / 2;
00161     base[3].y = ( a + b ) / 2;
00162   }
00163 
00164 
00165   static FT_Bool
00166   ft_cubic_is_small_enough( FT_Vector*  base,
00167                             FT_Angle   *angle_in,
00168                             FT_Angle   *angle_mid,
00169                             FT_Angle   *angle_out )
00170   {
00171     FT_Vector  d1, d2, d3;
00172     FT_Angle   theta1, theta2;
00173     FT_Int     close1, close2, close3;
00174 
00175 
00176     d1.x = base[2].x - base[3].x;
00177     d1.y = base[2].y - base[3].y;
00178     d2.x = base[1].x - base[2].x;
00179     d2.y = base[1].y - base[2].y;
00180     d3.x = base[0].x - base[1].x;
00181     d3.y = base[0].y - base[1].y;
00182 
00183     close1 = FT_IS_SMALL( d1.x ) && FT_IS_SMALL( d1.y );
00184     close2 = FT_IS_SMALL( d2.x ) && FT_IS_SMALL( d2.y );
00185     close3 = FT_IS_SMALL( d3.x ) && FT_IS_SMALL( d3.y );
00186 
00187     if ( close1 || close3 )
00188     {
00189       if ( close2 )
00190       {
00191         /* basically a point */
00192         *angle_in = *angle_out = *angle_mid = 0;
00193       }
00194       else if ( close1 )
00195       {
00196         *angle_in  = *angle_mid = FT_Atan2( d2.x, d2.y );
00197         *angle_out = FT_Atan2( d3.x, d3.y );
00198       }
00199       else  /* close2 */
00200       {
00201         *angle_in  = FT_Atan2( d1.x, d1.y );
00202         *angle_mid = *angle_out = FT_Atan2( d2.x, d2.y );
00203       }
00204     }
00205     else if ( close2 )
00206     {
00207       *angle_in  = *angle_mid = FT_Atan2( d1.x, d1.y );
00208       *angle_out = FT_Atan2( d3.x, d3.y );
00209     }
00210     else
00211     {
00212       *angle_in  = FT_Atan2( d1.x, d1.y );
00213       *angle_mid = FT_Atan2( d2.x, d2.y );
00214       *angle_out = FT_Atan2( d3.x, d3.y );
00215     }
00216 
00217     theta1 = ft_pos_abs( FT_Angle_Diff( *angle_in,  *angle_mid ) );
00218     theta2 = ft_pos_abs( FT_Angle_Diff( *angle_mid, *angle_out ) );
00219 
00220     return FT_BOOL( theta1 < FT_SMALL_CUBIC_THRESHOLD &&
00221                     theta2 < FT_SMALL_CUBIC_THRESHOLD );
00222   }
00223 
00224 
00225  /***************************************************************************/
00226  /***************************************************************************/
00227  /*****                                                                 *****/
00228  /*****                       STROKE BORDERS                            *****/
00229  /*****                                                                 *****/
00230  /***************************************************************************/
00231  /***************************************************************************/
00232 
00233   typedef enum  FT_StrokeTags_
00234   {
00235     FT_STROKE_TAG_ON    = 1,   /* on-curve point  */
00236     FT_STROKE_TAG_CUBIC = 2,   /* cubic off-point */
00237     FT_STROKE_TAG_BEGIN = 4,   /* sub-path start  */
00238     FT_STROKE_TAG_END   = 8    /* sub-path end    */
00239 
00240   } FT_StrokeTags;
00241 
00242 #define  FT_STROKE_TAG_BEGIN_END  (FT_STROKE_TAG_BEGIN|FT_STROKE_TAG_END)
00243 
00244   typedef struct  FT_StrokeBorderRec_
00245   {
00246     FT_UInt     num_points;
00247     FT_UInt     max_points;
00248     FT_Vector*  points;
00249     FT_Byte*    tags;
00250     FT_Bool     movable;
00251     FT_Int      start;    /* index of current sub-path start point */
00252     FT_Memory   memory;
00253     FT_Bool     valid;
00254 
00255   } FT_StrokeBorderRec, *FT_StrokeBorder;
00256 
00257 
00258   static FT_Error
00259   ft_stroke_border_grow( FT_StrokeBorder  border,
00260                          FT_UInt          new_points )
00261   {
00262     FT_UInt   old_max = border->max_points;
00263     FT_UInt   new_max = border->num_points + new_points;
00264     FT_Error  error   = FT_Err_Ok;
00265 
00266 
00267     if ( new_max > old_max )
00268     {
00269       FT_UInt    cur_max = old_max;
00270       FT_Memory  memory  = border->memory;
00271 
00272 
00273       while ( cur_max < new_max )
00274         cur_max += ( cur_max >> 1 ) + 16;
00275 
00276       if ( FT_RENEW_ARRAY( border->points, old_max, cur_max ) ||
00277            FT_RENEW_ARRAY( border->tags,   old_max, cur_max ) )
00278         goto Exit;
00279 
00280       border->max_points = cur_max;
00281     }
00282 
00283   Exit:
00284     return error;
00285   }
00286 
00287 
00288   static void
00289   ft_stroke_border_close( FT_StrokeBorder  border,
00290                           FT_Bool          reverse )
00291   {
00292     FT_UInt  start = border->start;
00293     FT_UInt  count = border->num_points;
00294 
00295 
00296     FT_ASSERT( border->start >= 0 );
00297 
00298     /* don't record empty paths! */
00299     if ( count <= start + 1U )
00300       border->num_points = start;
00301     else
00302     {
00303       /* copy the last point to the start of this sub-path, since */
00304       /* it contains the `adjusted' starting coordinates          */
00305       border->num_points    = --count;
00306       border->points[start] = border->points[count];
00307 
00308       if ( reverse )
00309       {
00310         /* reverse the points */
00311         {
00312           FT_Vector*  vec1 = border->points + start + 1;
00313           FT_Vector*  vec2 = border->points + count - 1;
00314 
00315 
00316           for ( ; vec1 < vec2; vec1++, vec2-- )
00317           {
00318             FT_Vector  tmp;
00319 
00320 
00321             tmp   = *vec1;
00322             *vec1 = *vec2;
00323             *vec2 = tmp;
00324           }
00325         }
00326 
00327         /* then the tags */
00328         {
00329           FT_Byte*  tag1 = border->tags + start + 1;
00330           FT_Byte*  tag2 = border->tags + count - 1;
00331 
00332 
00333           for ( ; tag1 < tag2; tag1++, tag2-- )
00334           {
00335             FT_Byte  tmp;
00336 
00337 
00338             tmp   = *tag1;
00339             *tag1 = *tag2;
00340             *tag2 = tmp;
00341           }
00342         }
00343       }
00344 
00345       border->tags[start    ] |= FT_STROKE_TAG_BEGIN;
00346       border->tags[count - 1] |= FT_STROKE_TAG_END;
00347     }
00348 
00349     border->start   = -1;
00350     border->movable = FALSE;
00351   }
00352 
00353 
00354   static FT_Error
00355   ft_stroke_border_lineto( FT_StrokeBorder  border,
00356                            FT_Vector*       to,
00357                            FT_Bool          movable )
00358   {
00359     FT_Error  error = FT_Err_Ok;
00360 
00361 
00362     FT_ASSERT( border->start >= 0 );
00363 
00364     if ( border->movable )
00365     {
00366       /* move last point */
00367       border->points[border->num_points - 1] = *to;
00368     }
00369     else
00370     {
00371       /* add one point */
00372       error = ft_stroke_border_grow( border, 1 );
00373       if ( !error )
00374       {
00375         FT_Vector*  vec = border->points + border->num_points;
00376         FT_Byte*    tag = border->tags   + border->num_points;
00377 
00378 
00379         vec[0] = *to;
00380         tag[0] = FT_STROKE_TAG_ON;
00381 
00382         border->num_points += 1;
00383       }
00384     }
00385     border->movable = movable;
00386     return error;
00387   }
00388 
00389 
00390   static FT_Error
00391   ft_stroke_border_conicto( FT_StrokeBorder  border,
00392                             FT_Vector*       control,
00393                             FT_Vector*       to )
00394   {
00395     FT_Error  error;
00396 
00397 
00398     FT_ASSERT( border->start >= 0 );
00399 
00400     error = ft_stroke_border_grow( border, 2 );
00401     if ( !error )
00402     {
00403       FT_Vector*  vec = border->points + border->num_points;
00404       FT_Byte*    tag = border->tags   + border->num_points;
00405 
00406       vec[0] = *control;
00407       vec[1] = *to;
00408 
00409       tag[0] = 0;
00410       tag[1] = FT_STROKE_TAG_ON;
00411 
00412       border->num_points += 2;
00413     }
00414     border->movable = FALSE;
00415     return error;
00416   }
00417 
00418 
00419   static FT_Error
00420   ft_stroke_border_cubicto( FT_StrokeBorder  border,
00421                             FT_Vector*       control1,
00422                             FT_Vector*       control2,
00423                             FT_Vector*       to )
00424   {
00425     FT_Error  error;
00426 
00427 
00428     FT_ASSERT( border->start >= 0 );
00429 
00430     error = ft_stroke_border_grow( border, 3 );
00431     if ( !error )
00432     {
00433       FT_Vector*  vec = border->points + border->num_points;
00434       FT_Byte*    tag = border->tags   + border->num_points;
00435 
00436 
00437       vec[0] = *control1;
00438       vec[1] = *control2;
00439       vec[2] = *to;
00440 
00441       tag[0] = FT_STROKE_TAG_CUBIC;
00442       tag[1] = FT_STROKE_TAG_CUBIC;
00443       tag[2] = FT_STROKE_TAG_ON;
00444 
00445       border->num_points += 3;
00446     }
00447     border->movable = FALSE;
00448     return error;
00449   }
00450 
00451 
00452 #define FT_ARC_CUBIC_ANGLE  ( FT_ANGLE_PI / 2 )
00453 
00454 
00455   static FT_Error
00456   ft_stroke_border_arcto( FT_StrokeBorder  border,
00457                           FT_Vector*       center,
00458                           FT_Fixed         radius,
00459                           FT_Angle         angle_start,
00460                           FT_Angle         angle_diff )
00461   {
00462     FT_Angle   total, angle, step, rotate, next, theta;
00463     FT_Vector  a, b, a2, b2;
00464     FT_Fixed   length;
00465     FT_Error   error = FT_Err_Ok;
00466 
00467 
00468     /* compute start point */
00469     FT_Vector_From_Polar( &a, radius, angle_start );
00470     a.x += center->x;
00471     a.y += center->y;
00472 
00473     total  = angle_diff;
00474     angle  = angle_start;
00475     rotate = ( angle_diff >= 0 ) ? FT_ANGLE_PI2 : -FT_ANGLE_PI2;
00476 
00477     while ( total != 0 )
00478     {
00479       step = total;
00480       if ( step > FT_ARC_CUBIC_ANGLE )
00481         step = FT_ARC_CUBIC_ANGLE;
00482 
00483       else if ( step < -FT_ARC_CUBIC_ANGLE )
00484         step = -FT_ARC_CUBIC_ANGLE;
00485 
00486       next  = angle + step;
00487       theta = step;
00488       if ( theta < 0 )
00489         theta = -theta;
00490 
00491       theta >>= 1;
00492 
00493       /* compute end point */
00494       FT_Vector_From_Polar( &b, radius, next );
00495       b.x += center->x;
00496       b.y += center->y;
00497 
00498       /* compute first and second control points */
00499       length = FT_MulDiv( radius, FT_Sin( theta ) * 4,
00500                           ( 0x10000L + FT_Cos( theta ) ) * 3 );
00501 
00502       FT_Vector_From_Polar( &a2, length, angle + rotate );
00503       a2.x += a.x;
00504       a2.y += a.y;
00505 
00506       FT_Vector_From_Polar( &b2, length, next - rotate );
00507       b2.x += b.x;
00508       b2.y += b.y;
00509 
00510       /* add cubic arc */
00511       error = ft_stroke_border_cubicto( border, &a2, &b2, &b );
00512       if ( error )
00513         break;
00514 
00515       /* process the rest of the arc ?? */
00516       a      = b;
00517       total -= step;
00518       angle  = next;
00519     }
00520 
00521     return error;
00522   }
00523 
00524 
00525   static FT_Error
00526   ft_stroke_border_moveto( FT_StrokeBorder  border,
00527                            FT_Vector*       to )
00528   {
00529     /* close current open path if any ? */
00530     if ( border->start >= 0 )
00531       ft_stroke_border_close( border, FALSE );
00532 
00533     border->start   = border->num_points;
00534     border->movable = FALSE;
00535 
00536     return ft_stroke_border_lineto( border, to, FALSE );
00537   }
00538 
00539 
00540   static void
00541   ft_stroke_border_init( FT_StrokeBorder  border,
00542                          FT_Memory        memory )
00543   {
00544     border->memory = memory;
00545     border->points = NULL;
00546     border->tags   = NULL;
00547 
00548     border->num_points = 0;
00549     border->max_points = 0;
00550     border->start      = -1;
00551     border->valid      = FALSE;
00552   }
00553 
00554 
00555   static void
00556   ft_stroke_border_reset( FT_StrokeBorder  border )
00557   {
00558     border->num_points = 0;
00559     border->start      = -1;
00560     border->valid      = FALSE;
00561   }
00562 
00563 
00564   static void
00565   ft_stroke_border_done( FT_StrokeBorder  border )
00566   {
00567     FT_Memory  memory = border->memory;
00568 
00569 
00570     FT_FREE( border->points );
00571     FT_FREE( border->tags );
00572 
00573     border->num_points = 0;
00574     border->max_points = 0;
00575     border->start      = -1;
00576     border->valid      = FALSE;
00577   }
00578 
00579 
00580   static FT_Error
00581   ft_stroke_border_get_counts( FT_StrokeBorder  border,
00582                                FT_UInt         *anum_points,
00583                                FT_UInt         *anum_contours )
00584   {
00585     FT_Error  error        = FT_Err_Ok;
00586     FT_UInt   num_points   = 0;
00587     FT_UInt   num_contours = 0;
00588 
00589     FT_UInt     count      = border->num_points;
00590     FT_Vector*  point      = border->points;
00591     FT_Byte*    tags       = border->tags;
00592     FT_Int      in_contour = 0;
00593 
00594 
00595     for ( ; count > 0; count--, num_points++, point++, tags++ )
00596     {
00597       if ( tags[0] & FT_STROKE_TAG_BEGIN )
00598       {
00599         if ( in_contour != 0 )
00600           goto Fail;
00601 
00602         in_contour = 1;
00603       }
00604       else if ( in_contour == 0 )
00605         goto Fail;
00606 
00607       if ( tags[0] & FT_STROKE_TAG_END )
00608       {
00609         in_contour = 0;
00610         num_contours++;
00611       }
00612     }
00613 
00614     if ( in_contour != 0 )
00615       goto Fail;
00616 
00617     border->valid = TRUE;
00618 
00619   Exit:
00620     *anum_points   = num_points;
00621     *anum_contours = num_contours;
00622     return error;
00623 
00624   Fail:
00625     num_points   = 0;
00626     num_contours = 0;
00627     goto Exit;
00628   }
00629 
00630 
00631   static void
00632   ft_stroke_border_export( FT_StrokeBorder  border,
00633                            FT_Outline*      outline )
00634   {
00635     /* copy point locations */
00636     FT_ARRAY_COPY( outline->points + outline->n_points,
00637                    border->points,
00638                    border->num_points );
00639 
00640     /* copy tags */
00641     {
00642       FT_UInt   count = border->num_points;
00643       FT_Byte*  read  = border->tags;
00644       FT_Byte*  write = (FT_Byte*)outline->tags + outline->n_points;
00645 
00646 
00647       for ( ; count > 0; count--, read++, write++ )
00648       {
00649         if ( *read & FT_STROKE_TAG_ON )
00650           *write = FT_CURVE_TAG_ON;
00651         else if ( *read & FT_STROKE_TAG_CUBIC )
00652           *write = FT_CURVE_TAG_CUBIC;
00653         else
00654           *write = FT_CURVE_TAG_CONIC;
00655       }
00656     }
00657 
00658     /* copy contours */
00659     {
00660       FT_UInt    count = border->num_points;
00661       FT_Byte*   tags  = border->tags;
00662       FT_Short*  write = outline->contours + outline->n_contours;
00663       FT_Short   idx   = (FT_Short)outline->n_points;
00664 
00665 
00666       for ( ; count > 0; count--, tags++, idx++ )
00667       {
00668         if ( *tags & FT_STROKE_TAG_END )
00669         {
00670           *write++ = idx;
00671           outline->n_contours++;
00672         }
00673       }
00674     }
00675 
00676     outline->n_points  = (short)( outline->n_points + border->num_points );
00677 
00678     FT_ASSERT( FT_Outline_Check( outline ) == 0 );
00679   }
00680 
00681 
00682  /***************************************************************************/
00683  /***************************************************************************/
00684  /*****                                                                 *****/
00685  /*****                           STROKER                               *****/
00686  /*****                                                                 *****/
00687  /***************************************************************************/
00688  /***************************************************************************/
00689 
00690 #define FT_SIDE_TO_ROTATE( s )   ( FT_ANGLE_PI2 - (s) * FT_ANGLE_PI )
00691 
00692   typedef struct  FT_StrokerRec_
00693   {
00694     FT_Angle             angle_in;
00695     FT_Angle             angle_out;
00696     FT_Vector            center;
00697     FT_Bool              first_point;
00698     FT_Bool              subpath_open;
00699     FT_Angle             subpath_angle;
00700     FT_Vector            subpath_start;
00701 
00702     FT_Stroker_LineCap   line_cap;
00703     FT_Stroker_LineJoin  line_join;
00704     FT_Fixed             miter_limit;
00705     FT_Fixed             radius;
00706 
00707     FT_Bool              valid;
00708     FT_StrokeBorderRec   borders[2];
00709     FT_Library           library;
00710 
00711   } FT_StrokerRec;
00712 
00713 
00714   /* documentation is in ftstroke.h */
00715 
00716   FT_EXPORT_DEF( FT_Error )
00717   FT_Stroker_New( FT_Library   library,
00718                   FT_Stroker  *astroker )
00719   {
00720     FT_Error    error;
00721     FT_Memory   memory;
00722     FT_Stroker  stroker;
00723 
00724 
00725     if ( !library )
00726       return FT_Err_Invalid_Argument;
00727 
00728     memory = library->memory;
00729 
00730     if ( !FT_NEW( stroker ) )
00731     {
00732       stroker->library = library;
00733 
00734       ft_stroke_border_init( &stroker->borders[0], memory );
00735       ft_stroke_border_init( &stroker->borders[1], memory );
00736     }
00737     *astroker = stroker;
00738     return error;
00739   }
00740 
00741 
00742   /* documentation is in ftstroke.h */
00743 
00744   FT_EXPORT_DEF( void )
00745   FT_Stroker_Set( FT_Stroker           stroker,
00746                   FT_Fixed             radius,
00747                   FT_Stroker_LineCap   line_cap,
00748                   FT_Stroker_LineJoin  line_join,
00749                   FT_Fixed             miter_limit )
00750   {
00751     stroker->radius      = radius;
00752     stroker->line_cap    = line_cap;
00753     stroker->line_join   = line_join;
00754     stroker->miter_limit = miter_limit;
00755 
00756     FT_Stroker_Rewind( stroker );
00757   }
00758 
00759 
00760   /* documentation is in ftstroke.h */
00761 
00762   FT_EXPORT_DEF( void )
00763   FT_Stroker_Rewind( FT_Stroker  stroker )
00764   {
00765     if ( stroker )
00766     {
00767       ft_stroke_border_reset( &stroker->borders[0] );
00768       ft_stroke_border_reset( &stroker->borders[1] );
00769     }
00770   }
00771 
00772 
00773   /* documentation is in ftstroke.h */
00774 
00775   FT_EXPORT_DEF( void )
00776   FT_Stroker_Done( FT_Stroker  stroker )
00777   {
00778     if ( stroker )
00779     {
00780       FT_Memory  memory = stroker->library->memory;
00781 
00782 
00783       ft_stroke_border_done( &stroker->borders[0] );
00784       ft_stroke_border_done( &stroker->borders[1] );
00785 
00786       stroker->library = NULL;
00787       FT_FREE( stroker );
00788     }
00789   }
00790 
00791 
00792   /* creates a circular arc at a corner or cap */
00793   static FT_Error
00794   ft_stroker_arcto( FT_Stroker  stroker,
00795                     FT_Int      side )
00796   {
00797     FT_Angle         total, rotate;
00798     FT_Fixed         radius = stroker->radius;
00799     FT_Error         error  = FT_Err_Ok;
00800     FT_StrokeBorder  border = stroker->borders + side;
00801 
00802 
00803     rotate = FT_SIDE_TO_ROTATE( side );
00804 
00805     total = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
00806     if ( total == FT_ANGLE_PI )
00807       total = -rotate * 2;
00808 
00809     error = ft_stroke_border_arcto( border,
00810                                     &stroker->center,
00811                                     radius,
00812                                     stroker->angle_in + rotate,
00813                                     total );
00814     border->movable = FALSE;
00815     return error;
00816   }
00817 
00818 
00819   /* adds a cap at the end of an opened path */
00820   static FT_Error
00821   ft_stroker_cap( FT_Stroker  stroker,
00822                   FT_Angle    angle,
00823                   FT_Int      side )
00824   {
00825     FT_Error  error = FT_Err_Ok;
00826 
00827 
00828     if ( stroker->line_cap == FT_STROKER_LINECAP_ROUND )
00829     {
00830       /* add a round cap */
00831       stroker->angle_in  = angle;
00832       stroker->angle_out = angle + FT_ANGLE_PI;
00833       error = ft_stroker_arcto( stroker, side );
00834     }
00835     else if ( stroker->line_cap == FT_STROKER_LINECAP_SQUARE )
00836     {
00837       /* add a square cap */
00838       FT_Vector        delta, delta2;
00839       FT_Angle         rotate = FT_SIDE_TO_ROTATE( side );
00840       FT_Fixed         radius = stroker->radius;
00841       FT_StrokeBorder  border = stroker->borders + side;
00842 
00843 
00844       FT_Vector_From_Polar( &delta2, radius, angle + rotate );
00845       FT_Vector_From_Polar( &delta,  radius, angle );
00846 
00847       delta.x += stroker->center.x + delta2.x;
00848       delta.y += stroker->center.y + delta2.y;
00849 
00850       error = ft_stroke_border_lineto( border, &delta, FALSE );
00851       if ( error )
00852         goto Exit;
00853 
00854       FT_Vector_From_Polar( &delta2, radius, angle - rotate );
00855       FT_Vector_From_Polar( &delta,  radius, angle );
00856 
00857       delta.x += delta2.x + stroker->center.x;
00858       delta.y += delta2.y + stroker->center.y;
00859 
00860       error = ft_stroke_border_lineto( border, &delta, FALSE );
00861     }
00862     else if ( stroker->line_cap == FT_STROKER_LINECAP_BUTT )
00863     {
00864       /* add a butt ending */
00865       FT_Vector        delta;
00866       FT_Angle         rotate = FT_SIDE_TO_ROTATE( side );
00867       FT_Fixed         radius = stroker->radius;
00868       FT_StrokeBorder  border = stroker->borders + side;
00869 
00870 
00871       FT_Vector_From_Polar( &delta, radius, angle + rotate );
00872 
00873       delta.x += stroker->center.x;
00874       delta.y += stroker->center.y;
00875 
00876       error = ft_stroke_border_lineto( border, &delta, FALSE );
00877       if ( error )
00878         goto Exit;
00879 
00880       FT_Vector_From_Polar( &delta, radius, angle - rotate );
00881 
00882       delta.x += stroker->center.x;
00883       delta.y += stroker->center.y;
00884 
00885       error = ft_stroke_border_lineto( border, &delta, FALSE );   
00886     }
00887 
00888   Exit:
00889     return error;
00890   }
00891 
00892 
00893   /* process an inside corner, i.e. compute intersection */
00894   static FT_Error
00895   ft_stroker_inside( FT_Stroker  stroker,
00896                      FT_Int      side)
00897   {
00898     FT_StrokeBorder  border = stroker->borders + side;
00899     FT_Angle         phi, theta, rotate;
00900     FT_Fixed         length, thcos, sigma;
00901     FT_Vector        delta;
00902     FT_Error         error = FT_Err_Ok;
00903 
00904 
00905     rotate = FT_SIDE_TO_ROTATE( side );
00906 
00907     /* compute median angle */
00908     theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
00909     if ( theta == FT_ANGLE_PI )
00910       theta = rotate;
00911     else
00912       theta = theta / 2;
00913 
00914     phi = stroker->angle_in + theta;
00915 
00916     thcos = FT_Cos( theta );
00917     sigma = FT_MulFix( stroker->miter_limit, thcos );
00918 
00919     /* TODO: find better criterion to switch off the optimization */
00920     if ( sigma < 0x10000L )
00921     {
00922       FT_Vector_From_Polar( &delta, stroker->radius,
00923                             stroker->angle_out + rotate );
00924       delta.x += stroker->center.x;
00925       delta.y += stroker->center.y;
00926       border->movable = FALSE;
00927     }
00928     else
00929     {
00930       length = FT_DivFix( stroker->radius, thcos );
00931 
00932       FT_Vector_From_Polar( &delta, length, phi + rotate );
00933       delta.x += stroker->center.x;
00934       delta.y += stroker->center.y;
00935     }
00936 
00937     error = ft_stroke_border_lineto( border, &delta, FALSE );
00938 
00939     return error;
00940   }
00941 
00942 
00943   /* process an outside corner, i.e. compute bevel/miter/round */
00944   static FT_Error
00945   ft_stroker_outside( FT_Stroker  stroker,
00946                       FT_Int      side )
00947   {
00948     FT_StrokeBorder  border = stroker->borders + side;
00949     FT_Error         error;
00950     FT_Angle         rotate;
00951 
00952 
00953     if ( stroker->line_join == FT_STROKER_LINEJOIN_ROUND )
00954       error = ft_stroker_arcto( stroker, side );
00955     else
00956     {
00957       /* this is a mitered or beveled corner */
00958       FT_Fixed  sigma, radius = stroker->radius;
00959       FT_Angle  theta, phi;
00960       FT_Fixed  thcos;
00961       FT_Bool   miter;
00962 
00963 
00964       rotate = FT_SIDE_TO_ROTATE( side );
00965       miter  = FT_BOOL( stroker->line_join == FT_STROKER_LINEJOIN_MITER );
00966 
00967       theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
00968       if ( theta == FT_ANGLE_PI )
00969       {
00970         theta = rotate;
00971         phi   = stroker->angle_in;
00972       }
00973       else
00974       {
00975         theta = theta / 2;
00976         phi   = stroker->angle_in + theta + rotate;
00977       }
00978 
00979       thcos = FT_Cos( theta );
00980       sigma = FT_MulFix( stroker->miter_limit, thcos );
00981 
00982       /* FT_Sin(x) = 0 for x <= 57 */
00983       if ( sigma >= 0x10000L || ft_pos_abs( theta ) <= 57 )
00984         miter = FALSE;
00985 
00986       if ( miter )  /* this is a miter (broken angle) */
00987       {
00988         FT_Vector  middle, delta;
00989         FT_Fixed   length;
00990 
00991 
00992         /* compute middle point */
00993         FT_Vector_From_Polar( &middle,
00994                               FT_MulFix( radius, stroker->miter_limit ),
00995                               phi );
00996         middle.x += stroker->center.x;
00997         middle.y += stroker->center.y;
00998 
00999         /* compute first angle point */
01000         length = FT_MulFix( radius,
01001                             FT_DivFix( 0x10000L - sigma,
01002                                        ft_pos_abs( FT_Sin( theta ) ) ) );
01003 
01004         FT_Vector_From_Polar( &delta, length, phi + rotate );
01005         delta.x += middle.x;
01006         delta.y += middle.y;
01007 
01008         error = ft_stroke_border_lineto( border, &delta, FALSE );
01009         if ( error )
01010           goto Exit;
01011 
01012         /* compute second angle point */
01013         FT_Vector_From_Polar( &delta, length, phi - rotate );
01014         delta.x += middle.x;
01015         delta.y += middle.y;
01016 
01017         error = ft_stroke_border_lineto( border, &delta, FALSE );
01018         if ( error )
01019           goto Exit;
01020 
01021         /* finally, add a movable end point */
01022         FT_Vector_From_Polar( &delta, radius, stroker->angle_out + rotate );
01023         delta.x += stroker->center.x;
01024         delta.y += stroker->center.y;
01025 
01026         error = ft_stroke_border_lineto( border, &delta, TRUE );
01027       }
01028 
01029       else /* this is a bevel (intersection) */
01030       {
01031         FT_Fixed   length;
01032         FT_Vector  delta;
01033 
01034 
01035         length = FT_DivFix( stroker->radius, thcos );
01036 
01037         FT_Vector_From_Polar( &delta, length, phi );
01038         delta.x += stroker->center.x;
01039         delta.y += stroker->center.y;
01040 
01041         error = ft_stroke_border_lineto( border, &delta, FALSE );
01042         if ( error )
01043           goto Exit;
01044 
01045         /* now add end point */
01046         FT_Vector_From_Polar( &delta, stroker->radius,
01047                               stroker->angle_out + rotate );
01048         delta.x += stroker->center.x;
01049         delta.y += stroker->center.y;
01050 
01051         error = ft_stroke_border_lineto( border, &delta, TRUE );
01052       }
01053     }
01054 
01055   Exit:
01056     return error;
01057   }
01058 
01059 
01060   static FT_Error
01061   ft_stroker_process_corner( FT_Stroker  stroker )
01062   {
01063     FT_Error  error = FT_Err_Ok;
01064     FT_Angle  turn;
01065     FT_Int    inside_side;
01066 
01067 
01068     turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
01069 
01070     /* no specific corner processing is required if the turn is 0 */
01071     if ( turn == 0 )
01072       goto Exit;
01073 
01074     /* when we turn to the right, the inside side is 0 */
01075     inside_side = 0;
01076 
01077     /* otherwise, the inside side is 1 */
01078     if ( turn < 0 )
01079       inside_side = 1;
01080 
01081     /* process the inside side */
01082     error = ft_stroker_inside( stroker, inside_side );
01083     if ( error )
01084       goto Exit;
01085 
01086     /* process the outside side */
01087     error = ft_stroker_outside( stroker, 1 - inside_side );
01088 
01089   Exit:
01090     return error;
01091   }
01092 
01093 
01094   /* add two points to the left and right borders corresponding to the */
01095   /* start of the subpath                                              */
01096   static FT_Error
01097   ft_stroker_subpath_start( FT_Stroker  stroker,
01098                             FT_Angle    start_angle )
01099   {
01100     FT_Vector        delta;
01101     FT_Vector        point;
01102     FT_Error         error;
01103     FT_StrokeBorder  border;
01104 
01105 
01106     FT_Vector_From_Polar( &delta, stroker->radius,
01107                           start_angle + FT_ANGLE_PI2 );
01108 
01109     point.x = stroker->center.x + delta.x;
01110     point.y = stroker->center.y + delta.y;
01111 
01112     border = stroker->borders;
01113     error = ft_stroke_border_moveto( border, &point );
01114     if ( error )
01115       goto Exit;
01116 
01117     point.x = stroker->center.x - delta.x;
01118     point.y = stroker->center.y - delta.y;
01119 
01120     border++;
01121     error = ft_stroke_border_moveto( border, &point );
01122 
01123     /* save angle for last cap */
01124     stroker->subpath_angle = start_angle;
01125     stroker->first_point   = FALSE;
01126 
01127   Exit:
01128     return error;
01129   }
01130 
01131 
01132   /* documentation is in ftstroke.h */
01133 
01134   FT_EXPORT_DEF( FT_Error )
01135   FT_Stroker_LineTo( FT_Stroker  stroker,
01136                      FT_Vector*  to )
01137   {
01138     FT_Error         error = FT_Err_Ok;
01139     FT_StrokeBorder  border;
01140     FT_Vector        delta;
01141     FT_Angle         angle;
01142     FT_Int           side;
01143 
01144     delta.x = to->x - stroker->center.x;
01145     delta.y = to->y - stroker->center.y;
01146 
01147     angle = FT_Atan2( delta.x, delta.y );
01148     FT_Vector_From_Polar( &delta, stroker->radius, angle + FT_ANGLE_PI2 );
01149 
01150     /* process corner if necessary */
01151     if ( stroker->first_point )
01152     {
01153       /* This is the first segment of a subpath.  We need to     */
01154       /* add a point to each border at their respective starting */
01155       /* point locations.                                        */
01156       error = ft_stroker_subpath_start( stroker, angle );
01157       if ( error )
01158         goto Exit;
01159     }
01160     else
01161     {
01162       /* process the current corner */
01163       stroker->angle_out = angle;
01164       error = ft_stroker_process_corner( stroker );
01165       if ( error )
01166         goto Exit;
01167     }
01168 
01169     /* now add a line segment to both the `inside' and `outside' paths */
01170 
01171     for ( border = stroker->borders, side = 1; side >= 0; side--, border++ )
01172     {
01173       FT_Vector  point;
01174 
01175 
01176       point.x = to->x + delta.x;
01177       point.y = to->y + delta.y;
01178 
01179       error = ft_stroke_border_lineto( border, &point, TRUE );
01180       if ( error )
01181         goto Exit;
01182 
01183       delta.x = -delta.x;
01184       delta.y = -delta.y;
01185     }
01186 
01187     stroker->angle_in = angle;
01188     stroker->center   = *to;
01189 
01190   Exit:
01191     return error;
01192   }
01193 
01194 
01195   /* documentation is in ftstroke.h */
01196 
01197   FT_EXPORT_DEF( FT_Error )
01198   FT_Stroker_ConicTo( FT_Stroker  stroker,
01199                       FT_Vector*  control,
01200                       FT_Vector*  to )
01201   {
01202     FT_Error    error = FT_Err_Ok;
01203     FT_Vector   bez_stack[34];
01204     FT_Vector*  arc;
01205     FT_Vector*  limit = bez_stack + 30;
01206     FT_Angle    start_angle;
01207     FT_Bool     first_arc = TRUE;
01208 
01209 
01210     arc    = bez_stack;
01211     arc[0] = *to;
01212     arc[1] = *control;
01213     arc[2] = stroker->center;
01214 
01215     while ( arc >= bez_stack )
01216     {
01217       FT_Angle  angle_in, angle_out;
01218 
01219 
01220       angle_in = angle_out = 0;  /* remove compiler warnings */
01221 
01222       if ( arc < limit                                             &&
01223            !ft_conic_is_small_enough( arc, &angle_in, &angle_out ) )
01224       {
01225         ft_conic_split( arc );
01226         arc += 2;
01227         continue;
01228       }
01229 
01230       if ( first_arc )
01231       {
01232         first_arc = FALSE;
01233 
01234         start_angle = angle_in;
01235 
01236         /* process corner if necessary */
01237         if ( stroker->first_point )
01238           error = ft_stroker_subpath_start( stroker, start_angle );
01239         else
01240         {
01241           stroker->angle_out = start_angle;
01242           error = ft_stroker_process_corner( stroker );
01243         }
01244       }
01245 
01246       /* the arc's angle is small enough; we can add it directly to each */
01247       /* border                                                          */
01248       {
01249         FT_Vector  ctrl, end;
01250         FT_Angle   theta, phi, rotate;
01251         FT_Fixed   length;
01252         FT_Int     side;
01253 
01254 
01255         theta  = FT_Angle_Diff( angle_in, angle_out ) / 2;
01256         phi    = angle_in + theta;
01257         length = FT_DivFix( stroker->radius, FT_Cos( theta ) );
01258 
01259         for ( side = 0; side <= 1; side++ )
01260         {
01261           rotate = FT_SIDE_TO_ROTATE( side );
01262 
01263           /* compute control point */
01264           FT_Vector_From_Polar( &ctrl, length, phi + rotate );
01265           ctrl.x += arc[1].x;
01266           ctrl.y += arc[1].y;
01267 
01268           /* compute end point */
01269           FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
01270           end.x += arc[0].x;
01271           end.y += arc[0].y;
01272 
01273           error = ft_stroke_border_conicto( stroker->borders + side,
01274                                             &ctrl, &end );
01275           if ( error )
01276             goto Exit;
01277         }
01278       }
01279 
01280       arc -= 2;
01281 
01282       if ( arc < bez_stack )
01283         stroker->angle_in = angle_out;
01284     }
01285 
01286     stroker->center = *to;
01287 
01288   Exit:
01289     return error;
01290   }
01291 
01292 
01293   /* documentation is in ftstroke.h */
01294 
01295   FT_EXPORT_DEF( FT_Error )
01296   FT_Stroker_CubicTo( FT_Stroker  stroker,
01297                       FT_Vector*  control1,
01298                       FT_Vector*  control2,
01299                       FT_Vector*  to )
01300   {
01301     FT_Error    error = FT_Err_Ok;
01302     FT_Vector   bez_stack[37];
01303     FT_Vector*  arc;
01304     FT_Vector*  limit = bez_stack + 32;
01305     FT_Angle    start_angle;
01306     FT_Bool     first_arc = TRUE;
01307 
01308 
01309     arc    = bez_stack;
01310     arc[0] = *to;
01311     arc[1] = *control2;
01312     arc[2] = *control1;
01313     arc[3] = stroker->center;
01314 
01315     while ( arc >= bez_stack )
01316     {
01317       FT_Angle  angle_in, angle_mid, angle_out;
01318 
01319 
01320       /* remove compiler warnings */
01321       angle_in = angle_out = angle_mid = 0;
01322 
01323       if ( arc < limit                                         &&
01324            !ft_cubic_is_small_enough( arc, &angle_in,
01325                                       &angle_mid, &angle_out ) )
01326       {
01327         ft_cubic_split( arc );
01328         arc += 3;
01329         continue;
01330       }
01331 
01332       if ( first_arc )
01333       {
01334         first_arc = FALSE;
01335 
01336         /* process corner if necessary */
01337         start_angle = angle_in;
01338 
01339         if ( stroker->first_point )
01340           error = ft_stroker_subpath_start( stroker, start_angle );
01341         else
01342         {
01343           stroker->angle_out = start_angle;
01344           error = ft_stroker_process_corner( stroker );
01345         }
01346         if ( error )
01347           goto Exit;
01348       }
01349 
01350       /* the arc's angle is small enough; we can add it directly to each */
01351       /* border                                                          */
01352       {
01353         FT_Vector  ctrl1, ctrl2, end;
01354         FT_Angle   theta1, phi1, theta2, phi2, rotate;
01355         FT_Fixed   length1, length2;
01356         FT_Int     side;
01357 
01358 
01359         theta1  = ft_pos_abs( angle_mid - angle_in ) / 2;
01360         theta2  = ft_pos_abs( angle_out - angle_mid ) / 2;
01361         phi1    = (angle_mid + angle_in ) / 2;
01362         phi2    = (angle_mid + angle_out ) / 2;
01363         length1 = FT_DivFix( stroker->radius, FT_Cos( theta1 ) );
01364         length2 = FT_DivFix( stroker->radius, FT_Cos( theta2 ) );
01365 
01366         for ( side = 0; side <= 1; side++ )
01367         {
01368           rotate = FT_SIDE_TO_ROTATE( side );
01369 
01370           /* compute control points */
01371           FT_Vector_From_Polar( &ctrl1, length1, phi1 + rotate );
01372           ctrl1.x += arc[2].x;
01373           ctrl1.y += arc[2].y;
01374 
01375           FT_Vector_From_Polar( &ctrl2, length2, phi2 + rotate );
01376           ctrl2.x += arc[1].x;
01377           ctrl2.y += arc[1].y;
01378 
01379           /* compute end point */
01380           FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
01381           end.x += arc[0].x;
01382           end.y += arc[0].y;
01383 
01384           error = ft_stroke_border_cubicto( stroker->borders + side,
01385                                             &ctrl1, &ctrl2, &end );
01386           if ( error )
01387             goto Exit;
01388         }
01389       }
01390 
01391       arc -= 3;
01392       if ( arc < bez_stack )
01393         stroker->angle_in = angle_out;
01394     }
01395 
01396     stroker->center = *to;
01397 
01398   Exit:
01399     return error;
01400   }
01401 
01402 
01403   /* documentation is in ftstroke.h */
01404 
01405   FT_EXPORT_DEF( FT_Error )
01406   FT_Stroker_BeginSubPath( FT_Stroker  stroker,
01407                            FT_Vector*  to,
01408                            FT_Bool     open )
01409   {
01410     /* We cannot process the first point, because there is not enough      */
01411     /* information regarding its corner/cap.  The latter will be processed */
01412     /* in the `FT_Stroker_EndSubPath' routine.                             */
01413     /*                                                                     */
01414     stroker->first_point  = TRUE;
01415     stroker->center       = *to;
01416     stroker->subpath_open = open;
01417 
01418     /* record the subpath start point for each border */
01419     stroker->subpath_start = *to;
01420 
01421     return FT_Err_Ok;
01422   }
01423 
01424 
01425   static FT_Error
01426   ft_stroker_add_reverse_left( FT_Stroker  stroker,
01427                                FT_Bool     open )
01428   {
01429     FT_StrokeBorder  right = stroker->borders + 0;
01430     FT_StrokeBorder  left  = stroker->borders + 1;
01431     FT_Int           new_points;
01432     FT_Error         error = FT_Err_Ok;
01433 
01434 
01435     FT_ASSERT( left->start >= 0 );
01436 
01437     new_points = left->num_points - left->start;
01438     if ( new_points > 0 )
01439     {
01440       error = ft_stroke_border_grow( right, (FT_UInt)new_points );
01441       if ( error )
01442         goto Exit;
01443 
01444       {
01445         FT_Vector*  dst_point = right->points + right->num_points;
01446         FT_Byte*    dst_tag   = right->tags   + right->num_points;
01447         FT_Vector*  src_point = left->points  + left->num_points - 1;
01448         FT_Byte*    src_tag   = left->tags    + left->num_points - 1;
01449 
01450         while ( src_point >= left->points + left->start )
01451         {
01452           *dst_point = *src_point;
01453           *dst_tag   = *src_tag;
01454 
01455           if ( open )
01456             dst_tag[0] &= ~FT_STROKE_TAG_BEGIN_END;
01457           else
01458           {
01459             FT_Byte  ttag = (FT_Byte)( dst_tag[0] & FT_STROKE_TAG_BEGIN_END );
01460 
01461 
01462             /* switch begin/end tags if necessary */
01463             if ( ttag == FT_STROKE_TAG_BEGIN ||
01464                  ttag == FT_STROKE_TAG_END   )
01465               dst_tag[0] ^= FT_STROKE_TAG_BEGIN_END;
01466 
01467           }
01468 
01469           src_point--;
01470           src_tag--;
01471           dst_point++;
01472           dst_tag++;
01473         }
01474       }
01475 
01476       left->num_points   = left->start;
01477       right->num_points += new_points;
01478 
01479       right->movable = FALSE;
01480       left->movable  = FALSE;
01481     }
01482 
01483   Exit:
01484     return error;
01485   }
01486 
01487 
01488   /* documentation is in ftstroke.h */
01489 
01490   /* there's a lot of magic in this function! */
01491   FT_EXPORT_DEF( FT_Error )
01492   FT_Stroker_EndSubPath( FT_Stroker  stroker )
01493   {
01494     FT_Error  error = FT_Err_Ok;
01495 
01496 
01497     if ( stroker->subpath_open )
01498     {
01499       FT_StrokeBorder  right = stroker->borders;
01500 
01501       /* All right, this is an opened path, we need to add a cap between */
01502       /* right & left, add the reverse of left, then add a final cap     */
01503       /* between left & right.                                           */
01504       error = ft_stroker_cap( stroker, stroker->angle_in, 0 );
01505       if ( error )
01506         goto Exit;
01507 
01508       /* add reversed points from `left' to `right' */
01509       error = ft_stroker_add_reverse_left( stroker, TRUE );
01510       if ( error )
01511         goto Exit;
01512 
01513       /* now add the final cap */
01514       stroker->center = stroker->subpath_start;
01515       error = ft_stroker_cap( stroker,
01516                               stroker->subpath_angle + FT_ANGLE_PI, 0 );
01517       if ( error )
01518         goto Exit;
01519 
01520       /* Now end the right subpath accordingly.  The left one is */
01521       /* rewind and doesn't need further processing.             */
01522       ft_stroke_border_close( right, FALSE );
01523     }
01524     else
01525     {
01526       FT_Angle  turn;
01527       FT_Int    inside_side;
01528 
01529       /* close the path if needed */
01530       if ( stroker->center.x != stroker->subpath_start.x ||
01531            stroker->center.y != stroker->subpath_start.y )
01532       {
01533         error = FT_Stroker_LineTo( stroker, &stroker->subpath_start );
01534         if ( error )
01535           goto Exit;
01536       }
01537 
01538       /* process the corner */
01539       stroker->angle_out = stroker->subpath_angle;
01540       turn               = FT_Angle_Diff( stroker->angle_in,
01541                                           stroker->angle_out );
01542 
01543       /* no specific corner processing is required if the turn is 0 */
01544       if ( turn != 0 )
01545       {
01546         /* when we turn to the right, the inside side is 0 */
01547         inside_side = 0;
01548 
01549         /* otherwise, the inside side is 1 */
01550         if ( turn < 0 )
01551           inside_side = 1;
01552 
01553         error = ft_stroker_inside( stroker, inside_side );
01554         if ( error )
01555           goto Exit;
01556 
01557         /* process the outside side */
01558         error = ft_stroker_outside( stroker, 1 - inside_side );
01559         if ( error )
01560           goto Exit;
01561       }
01562 
01563       /* then end our two subpaths */
01564       ft_stroke_border_close( stroker->borders + 0, TRUE );
01565       ft_stroke_border_close( stroker->borders + 1, FALSE );
01566     }
01567 
01568   Exit:
01569     return error;
01570   }
01571 
01572 
01573   /* documentation is in ftstroke.h */
01574 
01575   FT_EXPORT_DEF( FT_Error )
01576   FT_Stroker_GetBorderCounts( FT_Stroker        stroker,
01577                               FT_StrokerBorder  border,
01578                               FT_UInt          *anum_points,
01579                               FT_UInt          *anum_contours )
01580   {
01581     FT_UInt   num_points = 0, num_contours = 0;
01582     FT_Error  error;
01583 
01584 
01585     if ( !stroker || border > 1 )
01586     {
01587       error = FT_Err_Invalid_Argument;
01588       goto Exit;
01589     }
01590 
01591     error = ft_stroke_border_get_counts( stroker->borders + border,
01592                                          &num_points, &num_contours );
01593   Exit:
01594     if ( anum_points )
01595       *anum_points = num_points;
01596 
01597     if ( anum_contours )
01598       *anum_contours = num_contours;
01599 
01600     return error;
01601   }
01602 
01603 
01604   /* documentation is in ftstroke.h */
01605 
01606   FT_EXPORT_DEF( FT_Error )
01607   FT_Stroker_GetCounts( FT_Stroker  stroker,
01608                         FT_UInt    *anum_points,
01609                         FT_UInt    *anum_contours )
01610   {
01611     FT_UInt   count1, count2, num_points   = 0;
01612     FT_UInt   count3, count4, num_contours = 0;
01613     FT_Error  error;
01614 
01615 
01616     error = ft_stroke_border_get_counts( stroker->borders + 0,
01617                                          &count1, &count2 );
01618     if ( error )
01619       goto Exit;
01620 
01621     error = ft_stroke_border_get_counts( stroker->borders + 1,
01622                                          &count3, &count4 );
01623     if ( error )
01624       goto Exit;
01625 
01626     num_points   = count1 + count3;
01627     num_contours = count2 + count4;
01628 
01629   Exit:
01630     *anum_points   = num_points;
01631     *anum_contours = num_contours;
01632     return error;
01633   }
01634 
01635 
01636   /* documentation is in ftstroke.h */
01637 
01638   FT_EXPORT_DEF( void )
01639   FT_Stroker_ExportBorder( FT_Stroker        stroker,
01640                            FT_StrokerBorder  border,
01641                            FT_Outline*       outline )
01642   {
01643     if ( border == FT_STROKER_BORDER_LEFT  ||
01644          border == FT_STROKER_BORDER_RIGHT )
01645     {
01646       FT_StrokeBorder  sborder = & stroker->borders[border];
01647 
01648 
01649       if ( sborder->valid )
01650         ft_stroke_border_export( sborder, outline );
01651     }
01652   }
01653 
01654 
01655   /* documentation is in ftstroke.h */
01656 
01657   FT_EXPORT_DEF( void )
01658   FT_Stroker_Export( FT_Stroker   stroker,
01659                      FT_Outline*  outline )
01660   {
01661     FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_LEFT, outline );
01662     FT_Stroker_ExportBorder( stroker, FT_STROKER_BORDER_RIGHT, outline );
01663   }
01664 
01665 
01666   /* documentation is in ftstroke.h */
01667 
01668   /*
01669    *  The following is very similar to FT_Outline_Decompose, except
01670    *  that we do support opened paths, and do not scale the outline.
01671    */
01672   FT_EXPORT_DEF( FT_Error )
01673   FT_Stroker_ParseOutline( FT_Stroker   stroker,
01674                            FT_Outline*  outline,
01675                            FT_Bool      opened )
01676   {
01677     FT_Vector   v_last;
01678     FT_Vector   v_control;
01679     FT_Vector   v_start;
01680 
01681     FT_Vector*  point;
01682     FT_Vector*  limit;
01683     char*       tags;
01684 
01685     FT_Error    error;
01686 
01687     FT_Int   n;         /* index of contour in outline     */
01688     FT_UInt  first;     /* index of first point in contour */
01689     FT_Int   tag;       /* current point's state           */
01690 
01691 
01692     if ( !outline || !stroker )
01693       return FT_Err_Invalid_Argument;
01694 
01695     FT_Stroker_Rewind( stroker );
01696 
01697     first = 0;
01698 
01699     for ( n = 0; n < outline->n_contours; n++ )
01700     {
01701       FT_UInt  last;  /* index of last point in contour */
01702 
01703 
01704       last  = outline->contours[n];
01705       limit = outline->points + last;
01706 
01707       /* skip empty points; we don't stroke these */
01708       if ( last <= first )
01709       {
01710         first = last + 1;
01711         continue;
01712       }
01713 
01714       v_start = outline->points[first];
01715       v_last  = outline->points[last];
01716 
01717       v_control = v_start;
01718 
01719       point = outline->points + first;
01720       tags  = outline->tags   + first;
01721       tag   = FT_CURVE_TAG( tags[0] );
01722 
01723       /* A contour cannot start with a cubic control point! */
01724       if ( tag == FT_CURVE_TAG_CUBIC )
01725         goto Invalid_Outline;
01726 
01727       /* check first point to determine origin */
01728       if ( tag == FT_CURVE_TAG_CONIC )
01729       {
01730         /* First point is conic control.  Yes, this happens. */
01731         if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
01732         {
01733           /* start at last point if it is on the curve */
01734           v_start = v_last;
01735           limit--;
01736         }
01737         else
01738         {
01739           /* if both first and last points are conic, */
01740           /* start at their middle                    */
01741           v_start.x = ( v_start.x + v_last.x ) / 2;
01742           v_start.y = ( v_start.y + v_last.y ) / 2;
01743         }
01744         point--;
01745         tags--;
01746       }
01747 
01748       error = FT_Stroker_BeginSubPath( stroker, &v_start, opened );
01749       if ( error )
01750         goto Exit;
01751 
01752       while ( point < limit )
01753       {
01754         point++;
01755         tags++;
01756 
01757         tag = FT_CURVE_TAG( tags[0] );
01758         switch ( tag )
01759         {
01760         case FT_CURVE_TAG_ON:  /* emit a single line_to */
01761           {
01762             FT_Vector  vec;
01763 
01764 
01765             vec.x = point->x;
01766             vec.y = point->y;
01767 
01768             error = FT_Stroker_LineTo( stroker, &vec );
01769             if ( error )
01770               goto Exit;
01771             continue;
01772           }
01773 
01774         case FT_CURVE_TAG_CONIC:  /* consume conic arcs */
01775           v_control.x = point->x;
01776           v_control.y = point->y;
01777 
01778         Do_Conic:
01779           if ( point < limit )
01780           {
01781             FT_Vector  vec;
01782             FT_Vector  v_middle;
01783 
01784 
01785             point++;
01786             tags++;
01787             tag = FT_CURVE_TAG( tags[0] );
01788 
01789             vec = point[0];
01790 
01791             if ( tag == FT_CURVE_TAG_ON )
01792             {
01793               error = FT_Stroker_ConicTo( stroker, &v_control, &vec );
01794               if ( error )
01795                 goto Exit;
01796               continue;
01797             }
01798 
01799             if ( tag != FT_CURVE_TAG_CONIC )
01800               goto Invalid_Outline;
01801 
01802             v_middle.x = ( v_control.x + vec.x ) / 2;
01803             v_middle.y = ( v_control.y + vec.y ) / 2;
01804 
01805             error = FT_Stroker_ConicTo( stroker, &v_control, &v_middle );
01806             if ( error )
01807               goto Exit;
01808 
01809             v_control = vec;
01810             goto Do_Conic;
01811           }
01812 
01813           error = FT_Stroker_ConicTo( stroker, &v_control, &v_start );
01814           goto Close;
01815 
01816         default:  /* FT_CURVE_TAG_CUBIC */
01817           {
01818             FT_Vector  vec1, vec2;
01819 
01820 
01821             if ( point + 1 > limit                             ||
01822                  FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
01823               goto Invalid_Outline;
01824 
01825             point += 2;
01826             tags  += 2;
01827 
01828             vec1 = point[-2];
01829             vec2 = point[-1];
01830 
01831             if ( point <= limit )
01832             {
01833               FT_Vector  vec;
01834 
01835 
01836               vec = point[0];
01837 
01838               error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &vec );
01839               if ( error )
01840                 goto Exit;
01841               continue;
01842             }
01843 
01844             error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &v_start );
01845             goto Close;
01846           }
01847         }
01848       }
01849 
01850     Close:
01851       if ( error )
01852         goto Exit;
01853 
01854       error = FT_Stroker_EndSubPath( stroker );
01855       if ( error )
01856         goto Exit;
01857 
01858       first = last + 1;
01859     }
01860 
01861     return FT_Err_Ok;
01862 
01863   Exit:
01864     return error;
01865 
01866   Invalid_Outline:
01867     return FT_Err_Invalid_Outline;
01868   }
01869 
01870 /* declare an extern to access ft_outline_glyph_class global allocated 
01871    in ftglyph.c, and use the FT_OUTLINE_GLYPH_CLASS_GET macro to access 
01872    it when FT_CONFIG_OPTION_PIC is defined */
01873 #ifndef FT_CONFIG_OPTION_PIC
01874   extern const FT_Glyph_Class  ft_outline_glyph_class;
01875 #endif
01876 #include "basepic.h"
01877 
01878 
01879   /* documentation is in ftstroke.h */
01880 
01881   FT_EXPORT_DEF( FT_Error )
01882   FT_Glyph_Stroke( FT_Glyph    *pglyph,
01883                    FT_Stroker   stroker,
01884                    FT_Bool      destroy )
01885   {
01886     FT_Error  error = FT_Err_Invalid_Argument;
01887     FT_Glyph  glyph = NULL;
01888     FT_Library library = stroker->library;
01889     FT_UNUSED(library);
01890 
01891     if ( pglyph == NULL )
01892       goto Exit;
01893 
01894     glyph = *pglyph;
01895     if ( glyph == NULL || glyph->clazz != FT_OUTLINE_GLYPH_CLASS_GET )
01896       goto Exit;
01897 
01898     {
01899       FT_Glyph  copy;
01900 
01901 
01902       error = FT_Glyph_Copy( glyph, &copy );
01903       if ( error )
01904         goto Exit;
01905 
01906       glyph = copy;
01907     }
01908 
01909     {
01910       FT_OutlineGlyph  oglyph  = (FT_OutlineGlyph) glyph;
01911       FT_Outline*      outline = &oglyph->outline;
01912       FT_UInt          num_points, num_contours;
01913 
01914 
01915       error = FT_Stroker_ParseOutline( stroker, outline, FALSE );
01916       if ( error )
01917         goto Fail;
01918 
01919       (void)FT_Stroker_GetCounts( stroker, &num_points, &num_contours );
01920 
01921       FT_Outline_Done( glyph->library, outline );
01922 
01923       error = FT_Outline_New( glyph->library,
01924                               num_points, num_contours, outline );
01925       if ( error )
01926         goto Fail;
01927 
01928       outline->n_points   = 0;
01929       outline->n_contours = 0;
01930 
01931       FT_Stroker_Export( stroker, outline );
01932     }
01933 
01934     if ( destroy )
01935       FT_Done_Glyph( *pglyph );
01936 
01937     *pglyph = glyph;
01938     goto Exit;
01939 
01940   Fail:
01941     FT_Done_Glyph( glyph );
01942     glyph = NULL;
01943 
01944     if ( !destroy )
01945       *pglyph = NULL;
01946 
01947   Exit:
01948     return error;
01949   }
01950 
01951 
01952   /* documentation is in ftstroke.h */
01953 
01954   FT_EXPORT_DEF( FT_Error )
01955   FT_Glyph_StrokeBorder( FT_Glyph    *pglyph,
01956                          FT_Stroker   stroker,
01957                          FT_Bool      inside,
01958                          FT_Bool      destroy )
01959   {
01960     FT_Error  error = FT_Err_Invalid_Argument;
01961     FT_Glyph  glyph = NULL;
01962     FT_Library library = stroker->library;
01963     FT_UNUSED(library);
01964 
01965     if ( pglyph == NULL )
01966       goto Exit;
01967 
01968     glyph = *pglyph;
01969     if ( glyph == NULL || glyph->clazz != FT_OUTLINE_GLYPH_CLASS_GET )
01970       goto Exit;
01971 
01972     {
01973       FT_Glyph  copy;
01974 
01975 
01976       error = FT_Glyph_Copy( glyph, &copy );
01977       if ( error )
01978         goto Exit;
01979 
01980       glyph = copy;
01981     }
01982 
01983     {
01984       FT_OutlineGlyph   oglyph  = (FT_OutlineGlyph) glyph;
01985       FT_StrokerBorder  border;
01986       FT_Outline*       outline = &oglyph->outline;
01987       FT_UInt           num_points, num_contours;
01988 
01989 
01990       border = FT_Outline_GetOutsideBorder( outline );
01991       if ( inside )
01992       {
01993         if ( border == FT_STROKER_BORDER_LEFT )
01994           border = FT_STROKER_BORDER_RIGHT;
01995         else
01996           border = FT_STROKER_BORDER_LEFT;
01997       }
01998 
01999       error = FT_Stroker_ParseOutline( stroker, outline, FALSE );
02000       if ( error )
02001         goto Fail;
02002 
02003       (void)FT_Stroker_GetBorderCounts( stroker, border,
02004                                         &num_points, &num_contours );
02005 
02006       FT_Outline_Done( glyph->library, outline );
02007 
02008       error = FT_Outline_New( glyph->library,
02009                               num_points,
02010                               num_contours,
02011                               outline );
02012       if ( error )
02013         goto Fail;
02014 
02015       outline->n_points   = 0;
02016       outline->n_contours = 0;
02017 
02018       FT_Stroker_ExportBorder( stroker, border, outline );
02019     }
02020 
02021     if ( destroy )
02022       FT_Done_Glyph( *pglyph );
02023 
02024     *pglyph = glyph;
02025     goto Exit;
02026 
02027   Fail:
02028     FT_Done_Glyph( glyph );
02029     glyph = NULL;
02030 
02031     if ( !destroy )
02032       *pglyph = NULL;
02033 
02034   Exit:
02035     return error;
02036   }
02037 
02038 
02039 /* END */

Generated on Sun May 27 2012 04:33:47 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.