Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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