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