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