1ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/***************************************************************************/
2ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
3ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  cffgload.c                                                             */
4ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
5ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*    OpenType Glyph Loader (body).                                        */
6ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
7ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  Copyright 1996-2013 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#include "../../include/ft2build.h"
20ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "../../include/freetype/internal/ftdebug.h"
21ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "../../include/freetype/internal/ftstream.h"
22ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "../../include/freetype/internal/sfnt.h"
23ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "../../include/freetype/ftoutln.h"
24ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "../../include/freetype/ftcffdrv.h"
25ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
26ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "cffobjs.h"
27ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "cffload.h"
28ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "cffgload.h"
29ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "cf2ft.h"      /* for cf2_decoder_parse_charstrings */
30ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
31ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "cfferrs.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_cffgload
42ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
43ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
44ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
45ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
46ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  typedef enum  CFF_Operator_
47ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
48ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_unknown = 0,
49ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
50ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_rmoveto,
51ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_hmoveto,
52ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_vmoveto,
53ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
54ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_rlineto,
55ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_hlineto,
56ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_vlineto,
57ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
58ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_rrcurveto,
59ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_hhcurveto,
60ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_hvcurveto,
61ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_rcurveline,
62ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_rlinecurve,
63ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_vhcurveto,
64ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_vvcurveto,
65ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
66ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_flex,
67ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_hflex,
68ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_hflex1,
69ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_flex1,
70ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
71ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_endchar,
72ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
73ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_hstem,
74ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_vstem,
75ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_hstemhm,
76ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_vstemhm,
77ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
78ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_hintmask,
79ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_cntrmask,
80ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_dotsection,  /* deprecated, acts as no-op */
81ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
82ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_abs,
83ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_add,
84ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_sub,
85ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_div,
86ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_neg,
87ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_random,
88ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_mul,
89ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_sqrt,
90ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
91ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_blend,
92ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
93ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_drop,
94ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_exch,
95ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_index,
96ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_roll,
97ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_dup,
98ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
99ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_put,
100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_get,
101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_store,
102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_load,
103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_and,
105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_or,
106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_not,
107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_eq,
108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_ifelse,
109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_callsubr,
111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_callgsubr,
112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_return,
113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* Type 1 opcodes: invalid but seen in real life */
115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_hsbw,
116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_closepath,
117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_callothersubr,
118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_pop,
119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_seac,
120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_sbw,
121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_setcurrentpoint,
122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* do not remove */
124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_op_max
125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  } CFF_Operator;
127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define CFF_COUNT_CHECK_WIDTH  0x80
130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define CFF_COUNT_EXACT        0x40
131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define CFF_COUNT_CLEAR_STACK  0x20
132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* count values which have the `CFF_COUNT_CHECK_WIDTH' flag set are  */
134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* used for checking the width and requested numbers of arguments    */
135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* only; they are set to zero afterwards                             */
136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* the other two flags are informative only and unused currently     */
138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static const FT_Byte  cff_argument_counts[] =
140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0,  /* unknown */
142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, /* rmoveto */
144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT,
145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT,
146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0 | CFF_COUNT_CLEAR_STACK, /* rlineto */
148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0 | CFF_COUNT_CLEAR_STACK,
149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0 | CFF_COUNT_CLEAR_STACK,
150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0 | CFF_COUNT_CLEAR_STACK, /* rrcurveto */
152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0 | CFF_COUNT_CLEAR_STACK,
153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0 | CFF_COUNT_CLEAR_STACK,
154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0 | CFF_COUNT_CLEAR_STACK,
155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0 | CFF_COUNT_CLEAR_STACK,
156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0 | CFF_COUNT_CLEAR_STACK,
157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0 | CFF_COUNT_CLEAR_STACK,
158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    13, /* flex */
160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    7,
161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    9,
162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    11,
163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0 | CFF_COUNT_CHECK_WIDTH, /* endchar */
165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2 | CFF_COUNT_CHECK_WIDTH, /* hstem */
167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2 | CFF_COUNT_CHECK_WIDTH,
168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2 | CFF_COUNT_CHECK_WIDTH,
169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2 | CFF_COUNT_CHECK_WIDTH,
170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0 | CFF_COUNT_CHECK_WIDTH, /* hintmask */
172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0 | CFF_COUNT_CHECK_WIDTH, /* cntrmask */
173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0, /* dotsection */
174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    1, /* abs */
176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2,
177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2,
178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2,
179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    1,
180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0,
181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2,
182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    1,
183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    1, /* blend */
185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    1, /* drop */
187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2,
188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    1,
189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2,
190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    1,
191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2, /* put */
193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    1,
194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    4,
195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    3,
196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2, /* and */
198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2,
199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    1,
200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2,
201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    4,
202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    1, /* callsubr */
204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    1,
205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0,
206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2, /* hsbw */
208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0,
209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0,
210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    0,
211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    5, /* seac */
212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    4, /* sbw */
213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2  /* setcurrentpoint */
214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  };
215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /**********                                                      *********/
223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /**********                                                      *********/
224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /**********             GENERIC CHARSTRING PARSING               *********/
225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /**********                                                      *********/
226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /**********                                                      *********/
227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <Function>                                                            */
235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    cff_builder_init                                                   */
236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <Description>                                                         */
238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    Initializes a given glyph builder.                                 */
239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <InOut>                                                               */
241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    builder :: A pointer to the glyph builder to initialize.           */
242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <Input>                                                               */
244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    face    :: The current face object.                                */
245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    size    :: The current size object.                                */
247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    glyph   :: The current glyph object.                               */
249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    hinting :: Whether hinting is active.                              */
251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static void
253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_builder_init( CFF_Builder*   builder,
254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    TT_Face        face,
255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    CFF_Size       size,
256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    CFF_GlyphSlot  glyph,
257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FT_Bool        hinting )
258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->path_begun  = 0;
260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->load_points = 1;
261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->face   = face;
263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->glyph  = glyph;
264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->memory = face->root.memory;
265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( glyph )
267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_GlyphLoader  loader = glyph->root.internal->loader;
269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      builder->loader  = loader;
272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      builder->base    = &loader->base.outline;
273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      builder->current = &loader->current.outline;
274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_GlyphLoader_Rewind( loader );
275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      builder->hints_globals = 0;
277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      builder->hints_funcs   = 0;
278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( hinting && size )
280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        CFF_Internal  internal = (CFF_Internal)size->root.internal;
282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        builder->hints_globals = (void *)internal->topfont;
285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        builder->hints_funcs   = glyph->root.internal->glyph_hints;
286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->pos_x = 0;
290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->pos_y = 0;
291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->left_bearing.x = 0;
293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->left_bearing.y = 0;
294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->advance.x      = 0;
295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->advance.y      = 0;
296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <Function>                                                            */
302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    cff_builder_done                                                   */
303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <Description>                                                         */
305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    Finalizes a given glyph builder.  Its contents can still be used   */
306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    after the call, but the function saves important information       */
307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    within the corresponding glyph slot.                               */
308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <Input>                                                               */
310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    builder :: A pointer to the glyph builder to finalize.             */
311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static void
313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_builder_done( CFF_Builder*  builder )
314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CFF_GlyphSlot  glyph = builder->glyph;
316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( glyph )
319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      glyph->root.outline = *builder->base;
320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <Function>                                                            */
326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    cff_compute_bias                                                   */
327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <Description>                                                         */
329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    Computes the bias value in dependence of the number of glyph       */
330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    subroutines.                                                       */
331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <Input>                                                               */
333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    in_charstring_type :: The `CharstringType' value of the top DICT   */
334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                          dictionary.                                  */
335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    num_subrs          :: The number of glyph subroutines.             */
337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <Return>                                                              */
339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    The bias value.                                                    */
340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_Int
341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_compute_bias( FT_Int   in_charstring_type,
342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FT_UInt  num_subrs )
343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Int  result;
345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( in_charstring_type == 1 )
348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      result = 0;
349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else if ( num_subrs < 1240 )
350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      result = 107;
351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else if ( num_subrs < 33900U )
352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      result = 1131;
353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      result = 32768U;
355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return result;
357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <Function>                                                            */
363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    cff_decoder_init                                                   */
364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <Description>                                                         */
366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    Initializes a given glyph decoder.                                 */
367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <InOut>                                                               */
369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    decoder :: A pointer to the glyph builder to initialize.           */
370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <Input>                                                               */
372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    face      :: The current face object.                              */
373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    size      :: The current size object.                              */
375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    slot      :: The current glyph object.                             */
377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    hinting   :: Whether hinting is active.                            */
379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    hint_mode :: The hinting mode.                                     */
381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( void )
383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_decoder_init( CFF_Decoder*    decoder,
384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    TT_Face         face,
385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    CFF_Size        size,
386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    CFF_GlyphSlot   slot,
387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FT_Bool         hinting,
388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FT_Render_Mode  hint_mode )
389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CFF_Font  cff = (CFF_Font)face->extra.data;
391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* clear everything */
394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MEM_ZERO( decoder, sizeof ( *decoder ) );
395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* initialize builder */
397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_builder_init( &decoder->builder, face, size, slot, hinting );
398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* initialize Type2 decoder */
400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder->cff          = cff;
401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder->num_globals  = cff->global_subrs_index.count;
402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder->globals      = cff->global_subrs;
403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder->globals_bias = cff_compute_bias(
404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                              cff->top_font.font_dict.charstring_type,
405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                              decoder->num_globals );
406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder->hint_mode    = hint_mode;
408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* this function is used to select the subfont */
412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* and the locals subrs array                  */
413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( FT_Error )
414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_decoder_prepare( CFF_Decoder*  decoder,
415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       CFF_Size      size,
416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       FT_UInt       glyph_index )
417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CFF_Builder  *builder = &decoder->builder;
419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CFF_Font      cff     = (CFF_Font)builder->face->extra.data;
420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CFF_SubFont   sub     = &cff->top_font;
421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Error      error   = FT_Err_Ok;
422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* manage CID fonts */
425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( cff->num_subfonts )
426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte  fd_index = cff_fd_select_get( &cff->fd_select, glyph_index );
428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( fd_index >= cff->num_subfonts )
431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_TRACE4(( "cff_decoder_prepare: invalid CID subfont index\n" ));
433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        error = FT_THROW( Invalid_File_Format );
434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Exit;
435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_TRACE3(( "glyph index %d (subfont %d):\n", glyph_index, fd_index ));
438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      sub = cff->subfonts[fd_index];
440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( builder->hints_funcs && size )
442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        CFF_Internal  internal = (CFF_Internal)size->root.internal;
444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* for CFFs without subfonts, this value has already been set */
447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        builder->hints_globals = (void *)internal->subfonts[fd_index];
448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef FT_DEBUG_LEVEL_TRACE
451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_TRACE3(( "glyph index %d:\n", glyph_index ));
453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif
454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder->num_locals    = sub->local_subrs_index.count;
456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder->locals        = sub->local_subrs;
457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder->locals_bias   = cff_compute_bias(
458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                               decoder->cff->top_font.font_dict.charstring_type,
459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                               decoder->num_locals );
460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder->glyph_width   = sub->private_dict.default_width;
462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder->nominal_width = sub->private_dict.nominal_width;
463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder->current_subfont = sub;     /* for Adobe's CFF handler */
465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Exit:
467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return error;
468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* check that there is enough space for `count' more points */
472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( FT_Error )
473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_check_points( CFF_Builder*  builder,
474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FT_Int        count )
475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_GLYPHLOADER_CHECK_POINTS( builder->loader, count, 0 );
477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* add a new point, do not check space */
481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( void )
482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_builder_add_point( CFF_Builder*  builder,
483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                         FT_Pos        x,
484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                         FT_Pos        y,
485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                         FT_Byte       flag )
486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Outline*  outline = builder->current;
488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( builder->load_points )
491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Vector*  point   = outline->points + outline->n_points;
493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points;
494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      CFF_Driver  driver  = (CFF_Driver)FT_FACE_DRIVER( builder->face );
497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( driver->hinting_engine == FT_CFF_HINTING_FREETYPE )
500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        point->x = x >> 16;
502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        point->y = y >> 16;
503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif
506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* cf2_decoder_parse_charstrings uses 16.16 coordinates */
508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        point->x = x >> 10;
509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        point->y = y >> 10;
510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    outline->n_points++;
515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* check space for a new on-curve point, then add it */
519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( FT_Error )
520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_builder_add_point1( CFF_Builder*  builder,
521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                          FT_Pos        x,
522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                          FT_Pos        y )
523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Error  error;
525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    error = cff_check_points( builder, 1 );
528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !error )
529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cff_builder_add_point( builder, x, y, 1 );
530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return error;
532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* check space for a new contour, then add it */
536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_Error
537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_builder_add_contour( CFF_Builder*  builder )
538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Outline*  outline = builder->current;
540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Error     error;
541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !builder->load_points )
544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      outline->n_contours++;
546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return FT_Err_Ok;
547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    error = FT_GLYPHLOADER_CHECK_POINTS( builder->loader, 0, 1 );
550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !error )
551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( outline->n_contours > 0 )
553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        outline->contours[outline->n_contours - 1] =
554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          (short)( outline->n_points - 1 );
555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      outline->n_contours++;
557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return error;
560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* if a path was begun, add its first on-curve point */
564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( FT_Error )
565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_builder_start_point( CFF_Builder*  builder,
566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                           FT_Pos        x,
567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                           FT_Pos        y )
568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Error  error = FT_Err_Ok;
570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* test whether we are building a new contour */
573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !builder->path_begun )
574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      builder->path_begun = 1;
576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      error = cff_builder_add_contour( builder );
577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( !error )
578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        error = cff_builder_add_point1( builder, x, y );
579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return error;
582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* close the current contour */
586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( void )
587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_builder_close_contour( CFF_Builder*  builder )
588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Outline*  outline = builder->current;
590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Int       first;
591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !outline )
594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return;
595ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    first = outline->n_contours <= 1
597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ? 0 : outline->contours[outline->n_contours - 2] + 1;
598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* We must not include the last point in the path if it */
600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* is located on the first point.                       */
601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( outline->n_points > 1 )
602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Vector*  p1      = outline->points + first;
604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Vector*  p2      = outline->points + outline->n_points - 1;
605ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points - 1;
606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
607ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
608ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* `delete' last point only if it coincides with the first    */
609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* point and if it is not a control point (which can happen). */
610ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( p1->x == p2->x && p1->y == p2->y )
611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( *control == FT_CURVE_TAG_ON )
612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          outline->n_points--;
613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
615ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( outline->n_contours > 0 )
616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* Don't add contours only consisting of one point, i.e., */
618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* check whether begin point and last point are the same. */
619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( first == outline->n_points - 1 )
620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        outline->n_contours--;
622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        outline->n_points--;
623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
625ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        outline->contours[outline->n_contours - 1] =
626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          (short)( outline->n_points - 1 );
627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( FT_Int )
632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_lookup_glyph_by_stdcharcode( CFF_Font  cff,
633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                   FT_Int    charcode )
634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt    n;
636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UShort  glyph_sid;
637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* CID-keyed fonts don't have glyph names */
640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !cff->charset.sids )
641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return -1;
642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check range of standard char code */
644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( charcode < 0 || charcode > 255 )
645ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return -1;
646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* Get code to SID mapping from `cff_standard_encoding'. */
648ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    glyph_sid = cff_get_standard_encoding( (FT_UInt)charcode );
649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( n = 0; n < cff->num_glyphs; n++ )
651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( cff->charset.sids[n] == glyph_sid )
653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return n;
654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return -1;
657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( FT_Error )
661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_get_glyph_data( TT_Face    face,
662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_UInt    glyph_index,
663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_Byte**  pointer,
664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_ULong*  length )
665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef FT_CONFIG_OPTION_INCREMENTAL
667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* For incremental fonts get the character data using the */
668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* callback function.                                     */
669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( face->root.internal->incremental_interface )
670ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Data   data;
672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Error  error =
673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                  face->root.internal->incremental_interface->funcs->get_glyph_data(
674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    face->root.internal->incremental_interface->object,
675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    glyph_index, &data );
676ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      *pointer = (FT_Byte*)data.pointer;
679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      *length = data.length;
680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return error;
682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* FT_CONFIG_OPTION_INCREMENTAL */
685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      CFF_Font  cff  = (CFF_Font)(face->extra.data);
688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return cff_index_access_element( &cff->charstrings_index, glyph_index,
691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                       pointer, length );
692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( void )
697ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_free_glyph_data( TT_Face    face,
698ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       FT_Byte**  pointer,
699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       FT_ULong   length )
700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifndef FT_CONFIG_OPTION_INCREMENTAL
702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UNUSED( length );
703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif
704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef FT_CONFIG_OPTION_INCREMENTAL
706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* For incremental fonts get the character data using the */
707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* callback function.                                     */
708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( face->root.internal->incremental_interface )
709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Data data;
711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      data.pointer = *pointer;
714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      data.length  = length;
715ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      face->root.internal->incremental_interface->funcs->free_glyph_data(
717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        face->root.internal->incremental_interface->object, &data );
718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* FT_CONFIG_OPTION_INCREMENTAL */
721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
723ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      CFF_Font  cff = (CFF_Font)(face->extra.data);
724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
726ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cff_index_forget_element( &cff->charstrings_index, pointer );
727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
730ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
731ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
733ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_Error
734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_operator_seac( CFF_Decoder*  decoder,
735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     FT_Pos        asb,
736ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     FT_Pos        adx,
737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     FT_Pos        ady,
738ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     FT_Int        bchar,
739ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     FT_Int        achar )
740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Error      error;
742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CFF_Builder*  builder = &decoder->builder;
743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Int        bchar_index, achar_index;
744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    TT_Face       face = decoder->builder.face;
745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Vector     left_bearing, advance;
746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*      charstring;
747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ULong      charstring_len;
748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Pos        glyph_width;
749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
750ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( decoder->seac )
752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_ERROR(( "cff_operator_seac: invalid nested seac\n" ));
754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return FT_THROW( Syntax_Error );
755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
756ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
757ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    adx += decoder->builder.left_bearing.x;
758ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ady += decoder->builder.left_bearing.y;
759ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
760ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef FT_CONFIG_OPTION_INCREMENTAL
761ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* Incremental fonts don't necessarily have valid charsets.        */
762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* They use the character code, not the glyph index, in this case. */
763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( face->root.internal->incremental_interface )
764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      bchar_index = bchar;
766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      achar_index = achar;
767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
768ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* FT_CONFIG_OPTION_INCREMENTAL */
770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      CFF_Font cff = (CFF_Font)(face->extra.data);
772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
773ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      bchar_index = cff_lookup_glyph_by_stdcharcode( cff, bchar );
775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      achar_index = cff_lookup_glyph_by_stdcharcode( cff, achar );
776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( bchar_index < 0 || achar_index < 0 )
779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_ERROR(( "cff_operator_seac:"
781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 " invalid seac character code arguments\n" ));
782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return FT_THROW( Syntax_Error );
783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* If we are trying to load a composite glyph, do not load the */
786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* accent character and return the array of subglyphs.         */
787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( builder->no_recurse )
788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_GlyphSlot    glyph  = (FT_GlyphSlot)builder->glyph;
790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_GlyphLoader  loader = glyph->internal->loader;
791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_SubGlyph     subg;
792ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
794ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* reallocate subglyph array if necessary */
795ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 );
796ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( error )
797ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Exit;
798ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
799ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      subg = loader->current.subglyphs;
800ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
801ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* subglyph 0 = base character */
802ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      subg->index = bchar_index;
803ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES |
804ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FT_SUBGLYPH_FLAG_USE_MY_METRICS;
805ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      subg->arg1  = 0;
806ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      subg->arg2  = 0;
807ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      subg++;
808ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
809ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* subglyph 1 = accent character */
810ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      subg->index = achar_index;
811ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
812ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      subg->arg1  = (FT_Int)( adx >> 16 );
813ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      subg->arg2  = (FT_Int)( ady >> 16 );
814ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
815ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* set up remaining glyph fields */
816ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      glyph->num_subglyphs = 2;
817ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      glyph->subglyphs     = loader->base.subglyphs;
818ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      glyph->format        = FT_GLYPH_FORMAT_COMPOSITE;
819ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
820ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      loader->current.num_subglyphs = 2;
821ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
822ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
823ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_GlyphLoader_Prepare( builder->loader );
824ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
825ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* First load `bchar' in builder */
826ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    error = cff_get_glyph_data( face, bchar_index,
827ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                &charstring, &charstring_len );
828ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !error )
829ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
830ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* the seac operator must not be nested */
831ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      decoder->seac = TRUE;
832ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      error = cff_decoder_parse_charstrings( decoder, charstring,
833ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                             charstring_len );
834ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      decoder->seac = FALSE;
835ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
836ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cff_free_glyph_data( face, &charstring, charstring_len );
837ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
838ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( error )
839ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Exit;
840ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
841ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
842ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* Save the left bearing, advance and glyph width of the base */
843ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* character as they will be erased by the next load.         */
844ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
845ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    left_bearing = builder->left_bearing;
846ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    advance      = builder->advance;
847ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    glyph_width  = decoder->glyph_width;
848ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
849ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->left_bearing.x = 0;
850ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->left_bearing.y = 0;
851ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
852ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->pos_x = adx - asb;
853ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->pos_y = ady;
854ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
855ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* Now load `achar' on top of the base outline. */
856ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    error = cff_get_glyph_data( face, achar_index,
857ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                &charstring, &charstring_len );
858ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !error )
859ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
860ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* the seac operator must not be nested */
861ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      decoder->seac = TRUE;
862ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      error = cff_decoder_parse_charstrings( decoder, charstring,
863ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                             charstring_len );
864ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      decoder->seac = FALSE;
865ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
866ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cff_free_glyph_data( face, &charstring, charstring_len );
867ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
868ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( error )
869ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Exit;
870ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
871ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
872ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* Restore the left side bearing, advance and glyph width */
873ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* of the base character.                                 */
874ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->left_bearing = left_bearing;
875ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->advance      = advance;
876ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder->glyph_width  = glyph_width;
877ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
878ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->pos_x = 0;
879ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->pos_y = 0;
880ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
881ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Exit:
882ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return error;
883ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
884ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
885ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
886ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
887ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
888ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <Function>                                                            */
889ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    cff_decoder_parse_charstrings                                      */
890ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
891ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <Description>                                                         */
892ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    Parses a given Type 2 charstrings program.                         */
893ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
894ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <InOut>                                                               */
895ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    decoder         :: The current Type 1 decoder.                     */
896ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
897ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <Input>                                                               */
898ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    charstring_base :: The base of the charstring stream.              */
899ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
900ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    charstring_len  :: The length in bytes of the charstring stream.   */
901ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
902ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* <Return>                                                              */
903ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*    FreeType error code.  0 means success.                             */
904ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*                                                                       */
905ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( FT_Error )
906ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_decoder_parse_charstrings( CFF_Decoder*  decoder,
907ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                 FT_Byte*      charstring_base,
908ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                 FT_ULong      charstring_len )
909ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
910ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Error           error;
911ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CFF_Decoder_Zone*  zone;
912ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*           ip;
913ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*           limit;
914ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CFF_Builder*       builder = &decoder->builder;
915ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Pos             x, y;
916ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Fixed           seed;
917ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Fixed*          stack;
918ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Int             charstring_type =
919ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                         decoder->cff->top_font.font_dict.charstring_type;
920ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
921ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    T2_Hints_Funcs     hinter;
922ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
923ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
924ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* set default width */
925ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder->num_hints  = 0;
926ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder->read_width = 1;
927ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
928ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* compute random seed from stack address of parameter */
929ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    seed = (FT_Fixed)( ( (FT_PtrDist)(char*)&seed              ^
930ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                         (FT_PtrDist)(char*)&decoder           ^
931ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                         (FT_PtrDist)(char*)&charstring_base ) &
932ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                         FT_ULONG_MAX ) ;
933ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFFL;
934ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( seed == 0 )
935ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      seed = 0x7384;
936ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
937ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* initialize the decoder */
938ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder->top  = decoder->stack;
939ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder->zone = decoder->zones;
940ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    zone          = decoder->zones;
941ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    stack         = decoder->top;
942ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
943ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    hinter = (T2_Hints_Funcs)builder->hints_funcs;
944ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
945ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    builder->path_begun = 0;
946ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
947ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    zone->base           = charstring_base;
948ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    limit = zone->limit  = charstring_base + charstring_len;
949ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ip    = zone->cursor = zone->base;
950ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
951ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    error = FT_Err_Ok;
952ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
953ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    x = builder->pos_x;
954ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    y = builder->pos_y;
955ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
956ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* begin hints recording session, if any */
957ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( hinter )
958ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      hinter->open( hinter->hints );
959ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
960ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* now execute loop */
961ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    while ( ip < limit )
962ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
963ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      CFF_Operator  op;
964ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte       v;
965ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
966ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
967ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /********************************************************************/
968ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /*                                                                  */
969ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* Decode operator or operand                                       */
970ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /*                                                                  */
971ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      v = *ip++;
972ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( v >= 32 || v == 28 )
973ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
974ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Int    shift = 16;
975ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Int32  val;
976ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
977ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
978ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* this is an operand, push it on the stack */
979ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
980ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* if we use shifts, all computations are done with unsigned */
981ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* values; the conversion to a signed value is the last step */
982ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( v == 28 )
983ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
984ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( ip + 1 >= limit )
985ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            goto Syntax_Error;
986ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          val = (FT_Short)( ( (FT_UShort)ip[0] << 8 ) | ip[1] );
987ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          ip += 2;
988ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
989ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else if ( v < 247 )
990ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          val = (FT_Int32)v - 139;
991ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else if ( v < 251 )
992ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
993ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( ip >= limit )
994ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            goto Syntax_Error;
995ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          val = ( (FT_Int32)v - 247 ) * 256 + *ip++ + 108;
996ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
997ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else if ( v < 255 )
998ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
999ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( ip >= limit )
1000ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            goto Syntax_Error;
1001ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          val = -( (FT_Int32)v - 251 ) * 256 - *ip++ - 108;
1002ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1003ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else
1004ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
1005ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( ip + 3 >= limit )
1006ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            goto Syntax_Error;
1007ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          val = (FT_Int32)( ( (FT_UInt32)ip[0] << 24 ) |
1008ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            ( (FT_UInt32)ip[1] << 16 ) |
1009ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            ( (FT_UInt32)ip[2] <<  8 ) |
1010ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                              (FT_UInt32)ip[3]         );
1011ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          ip    += 4;
1012ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( charstring_type == 2 )
1013ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            shift = 0;
1014ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1015ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( decoder->top - stack >= CFF_MAX_OPERANDS )
1016ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          goto Stack_Overflow;
1017ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1018ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        val             = (FT_Int32)( (FT_UInt32)val << shift );
1019ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        *decoder->top++ = val;
1020ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1021ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef FT_DEBUG_LEVEL_TRACE
1022ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( !( val & 0xFFFFL ) )
1023ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " %hd", (FT_Short)( (FT_UInt32)val >> 16 ) ));
1024ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else
1025ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " %.2f", val / 65536.0 ));
1026ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif
1027ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1028ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
1029ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
1030ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
1031ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* The specification says that normally arguments are to be taken */
1032ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* from the bottom of the stack.  However, this seems not to be   */
1033ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* correct, at least for Acroread 7.0.8 on GNU/Linux: It pops the */
1034ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* arguments similar to a PS interpreter.                         */
1035ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1036ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Fixed*  args     = decoder->top;
1037ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Int     num_args = (FT_Int)( args - decoder->stack );
1038ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Int     req_args;
1039ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1040ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1041ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* find operator */
1042ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        op = cff_op_unknown;
1043ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1044ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        switch ( v )
1045ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
1046ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 1:
1047ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_hstem;
1048ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1049ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 3:
1050ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_vstem;
1051ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1052ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 4:
1053ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_vmoveto;
1054ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1055ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 5:
1056ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_rlineto;
1057ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1058ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 6:
1059ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_hlineto;
1060ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1061ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 7:
1062ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_vlineto;
1063ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1064ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 8:
1065ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_rrcurveto;
1066ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1067ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 9:
1068ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_closepath;
1069ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1070ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 10:
1071ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_callsubr;
1072ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1073ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 11:
1074ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_return;
1075ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1076ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 12:
1077ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1078ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( ip >= limit )
1079ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Syntax_Error;
1080ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            v = *ip++;
1081ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1082ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            switch ( v )
1083ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1084ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 0:
1085ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_dotsection;
1086ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1087ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 1: /* this is actually the Type1 vstem3 operator */
1088ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_vstem;
1089ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1090ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 2: /* this is actually the Type1 hstem3 operator */
1091ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_hstem;
1092ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1093ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 3:
1094ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_and;
1095ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1096ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 4:
1097ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_or;
1098ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1099ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 5:
1100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_not;
1101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 6:
1103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_seac;
1104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 7:
1106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_sbw;
1107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 8:
1109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_store;
1110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 9:
1112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_abs;
1113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 10:
1115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_add;
1116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 11:
1118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_sub;
1119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 12:
1121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_div;
1122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 13:
1124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_load;
1125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 14:
1127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_neg;
1128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 15:
1130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_eq;
1131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 16:
1133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_callothersubr;
1134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 17:
1136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_pop;
1137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 18:
1139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_drop;
1140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 20:
1142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_put;
1143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 21:
1145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_get;
1146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 22:
1148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_ifelse;
1149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 23:
1151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_random;
1152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 24:
1154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_mul;
1155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 26:
1157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_sqrt;
1158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 27:
1160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_dup;
1161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 28:
1163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_exch;
1164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 29:
1166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_index;
1167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 30:
1169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_roll;
1170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 33:
1172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_setcurrentpoint;
1173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 34:
1175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_hflex;
1176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 35:
1178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_flex;
1179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 36:
1181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_hflex1;
1182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 37:
1184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op = cff_op_flex1;
1185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /*default: */  /* XYQ 2007-9-6: we can't just quit if we see some reserved op */
1187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              /* decrement ip for syntax error message */
1188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov             /* ip--;*/
1189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 13:
1193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_hsbw;
1194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 14:
1196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_endchar;
1197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 16:
1199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_blend;
1200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 18:
1202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_hstemhm;
1203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 19:
1205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_hintmask;
1206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 20:
1208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_cntrmask;
1209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 21:
1211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_rmoveto;
1212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 22:
1214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_hmoveto;
1215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 23:
1217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_vstemhm;
1218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 24:
1220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_rcurveline;
1221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 25:
1223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_rlinecurve;
1224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 26:
1226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_vvcurveto;
1227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 27:
1229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_hhcurveto;
1230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 29:
1232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_callgsubr;
1233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 30:
1235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_vhcurveto;
1236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case 31:
1238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          op = cff_op_hvcurveto;
1239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        default:
1241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " unknown op (%d)\n", v ));
1242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( op == cff_op_unknown )
1246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          continue;
1247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* check arguments */
1249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        req_args = cff_argument_counts[op];
1250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( req_args & CFF_COUNT_CHECK_WIDTH )
1251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
1252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( num_args > 0 && decoder->read_width )
1253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* If `nominal_width' is non-zero, the number is really a      */
1255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* difference against `nominal_width'.  Else, the number here  */
1256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* is truly a width, not a difference against `nominal_width'. */
1257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* If the font does not set `nominal_width', then              */
1258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* `nominal_width' defaults to zero, and so we can set         */
1259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* `glyph_width' to `nominal_width' plus number on the stack   */
1260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* -- for either case.                                         */
1261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int  set_width_ok;
1263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            switch ( op )
1266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case cff_op_hmoveto:
1268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case cff_op_vmoveto:
1269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              set_width_ok = num_args & 2;
1270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case cff_op_hstem:
1273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case cff_op_vstem:
1274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case cff_op_hstemhm:
1275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case cff_op_vstemhm:
1276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case cff_op_rmoveto:
1277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case cff_op_hintmask:
1278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case cff_op_cntrmask:
1279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              set_width_ok = num_args & 1;
1280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case cff_op_endchar:
1283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              /* If there is a width specified for endchar, we either have */
1284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              /* 1 argument or 5 arguments.  We like to argue.             */
1285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              set_width_ok = ( num_args == 5 ) || ( num_args == 1 );
1286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            default:
1289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              set_width_ok = 0;
1290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( set_width_ok )
1294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              decoder->glyph_width = decoder->nominal_width +
1296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                       ( stack[0] >> 16 );
1297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              if ( decoder->width_only )
1299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              {
1300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                /* we only want the advance width; stop here */
1301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                break;
1302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              }
1303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              /* Consumed an argument. */
1305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              num_args--;
1306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          decoder->read_width = 0;
1310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          req_args            = 0;
1311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
1312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        req_args &= 0x000F;
1314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( num_args < req_args )
1315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          goto Stack_Underflow;
1316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        args     -= req_args;
1317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        num_args -= req_args;
1318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov		/* Sunliang.Liu sync 221's revison. */
1320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov		if (args > decoder->stack + CFF_MAX_OPERANDS)
1321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov			goto Stack_Overflow;
1322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* At this point, `args' points to the first argument of the  */
1324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* operand in case `req_args' isn't zero.  Otherwise, we have */
1325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* to adjust `args' manually.                                 */
1326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* Note that we only pop arguments from the stack which we    */
1328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* really need and can digest so that we can continue in case */
1329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* of superfluous stack elements.                             */
1330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        switch ( op )
1332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
1333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_hstem:
1334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_vstem:
1335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_hstemhm:
1336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_vstemhm:
1337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* the number of arguments is always even here */
1338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4((
1339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              op == cff_op_hstem   ? " hstem\n"   :
1340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ( op == cff_op_vstem   ? " vstem\n"   :
1341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ( op == cff_op_hstemhm ? " hstemhm\n" : " vstemhm\n" ) ) ));
1342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( hinter )
1344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            hinter->stems( hinter->hints,
1345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                           ( op == cff_op_hstem || op == cff_op_hstemhm ),
1346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                           num_args / 2,
1347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                           args - ( num_args & ~1 ) );
1348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          decoder->num_hints += num_args / 2;
1350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args = stack;
1351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_hintmask:
1354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_cntrmask:
1355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( op == cff_op_hintmask ? " hintmask" : " cntrmask" ));
1356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* implement vstem when needed --                        */
1358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* the specification doesn't say it, but this also works */
1359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* with the 'cntrmask' operator                          */
1360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /*                                                       */
1361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( num_args > 0 )
1362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( hinter )
1364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              hinter->stems( hinter->hints,
1365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                             0,
1366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                             num_args / 2,
1367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                             args - ( num_args & ~1 ) );
1368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            decoder->num_hints += num_args / 2;
1370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* In a valid charstring there must be at least one byte */
1373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* after `hintmask' or `cntrmask' (e.g., for a `return'  */
1374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* instruction).  Additionally, there must be space for  */
1375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* `num_hints' bits.                                     */
1376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( ( ip + ( ( decoder->num_hints + 7 ) >> 3 ) ) >= limit )
1378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            goto Syntax_Error;
1379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( hinter )
1381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( op == cff_op_hintmask )
1383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              hinter->hintmask( hinter->hints,
1384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                builder->current->n_points,
1385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                decoder->num_hints,
1386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                ip );
1387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            else
1388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              hinter->counter( hinter->hints,
1389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                               decoder->num_hints,
1390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                               ip );
1391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef FT_DEBUG_LEVEL_TRACE
1394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_UInt maskbyte;
1396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " (maskbytes:" ));
1399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            for ( maskbyte = 0;
1401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                  maskbyte < (FT_UInt)( ( decoder->num_hints + 7 ) >> 3 );
1402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                  maskbyte++, ip++ )
1403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_TRACE4(( " 0x%02X", *ip ));
1404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( ")\n" ));
1406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#else
1408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          ip += ( decoder->num_hints + 7 ) >> 3;
1409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif
1410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args = stack;
1411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_rmoveto:
1414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " rmoveto\n" ));
1415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          cff_builder_close_contour( builder );
1417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          builder->path_begun = 0;
1418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          x   += args[-2];
1419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          y   += args[-1];
1420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args = stack;
1421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_vmoveto:
1424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " vmoveto\n" ));
1425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          cff_builder_close_contour( builder );
1427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          builder->path_begun = 0;
1428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          y   += args[-1];
1429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args = stack;
1430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_hmoveto:
1433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " hmoveto\n" ));
1434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          cff_builder_close_contour( builder );
1436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          builder->path_begun = 0;
1437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          x   += args[-1];
1438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args = stack;
1439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_rlineto:
1442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " rlineto\n" ));
1443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( cff_builder_start_point( builder, x, y )  ||
1445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov               cff_check_points( builder, num_args / 2 ) )
1446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            goto Fail;
1447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( num_args < 2 )
1449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            goto Stack_Underflow;
1450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args -= num_args & ~1;
1452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          while ( args < decoder->top )
1453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            x += args[0];
1455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            y += args[1];
1456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 1 );
1457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args += 2;
1458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args = stack;
1460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_hlineto:
1463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_vlineto:
1464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int  phase = ( op == cff_op_hlineto );
1466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( op == cff_op_hlineto ? " hlineto\n"
1469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                             : " vlineto\n" ));
1470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( num_args < 0 )
1472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Stack_Underflow;
1473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* there exist subsetted fonts (found in PDFs) */
1475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* which call `hlineto' without arguments      */
1476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( num_args == 0 )
1477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              break;
1478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( cff_builder_start_point( builder, x, y ) ||
1480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 cff_check_points( builder, num_args )    )
1481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Fail;
1482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args = stack;
1484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            while ( args < decoder->top )
1485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              if ( phase )
1487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                x += args[0];
1488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              else
1489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                y += args[0];
1490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              if ( cff_builder_add_point1( builder, x, y ) )
1492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                goto Fail;
1493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              args++;
1495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              phase ^= 1;
1496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args = stack;
1498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_rrcurveto:
1502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int  nargs;
1504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " rrcurveto\n" ));
1507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( num_args < 6 )
1509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Stack_Underflow;
1510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            nargs = num_args - num_args % 6;
1512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( cff_builder_start_point( builder, x, y ) ||
1514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 cff_check_points( builder, nargs / 2 )   )
1515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Fail;
1516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args -= nargs;
1518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            while ( args < decoder->top )
1519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              x += args[0];
1521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              y += args[1];
1522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              cff_builder_add_point( builder, x, y, 0 );
1523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              x += args[2];
1524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              y += args[3];
1525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              cff_builder_add_point( builder, x, y, 0 );
1526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              x += args[4];
1527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              y += args[5];
1528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              cff_builder_add_point( builder, x, y, 1 );
1529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              args += 6;
1530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args = stack;
1532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_vvcurveto:
1536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int  nargs;
1538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " vvcurveto\n" ));
1541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( num_args < 4 )
1543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Stack_Underflow;
1544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* if num_args isn't of the form 4n or 4n+1, */
1546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* we enforce it by clearing the second bit  */
1547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            nargs = num_args & ~2;
1549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( cff_builder_start_point( builder, x, y ) )
1551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Fail;
1552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args -= nargs;
1554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( nargs & 1 )
1556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              x += args[0];
1558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              args++;
1559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              nargs--;
1560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( cff_check_points( builder, 3 * ( nargs / 4 ) ) )
1563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Fail;
1564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            while ( args < decoder->top )
1566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              y += args[0];
1568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              cff_builder_add_point( builder, x, y, 0 );
1569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              x += args[1];
1570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              y += args[2];
1571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              cff_builder_add_point( builder, x, y, 0 );
1572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              y += args[3];
1573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              cff_builder_add_point( builder, x, y, 1 );
1574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              args += 4;
1575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args = stack;
1577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_hhcurveto:
1581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int  nargs;
1583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " hhcurveto\n" ));
1586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( num_args < 4 )
1588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Stack_Underflow;
1589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* if num_args isn't of the form 4n or 4n+1, */
1591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* we enforce it by clearing the second bit  */
1592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            nargs = num_args & ~2;
1594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1595ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( cff_builder_start_point( builder, x, y ) )
1596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Fail;
1597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args -= nargs;
1599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( nargs & 1 )
1600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              y += args[0];
1602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              args++;
1603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              nargs--;
1604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1605ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( cff_check_points( builder, 3 * ( nargs / 4 ) ) )
1607ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Fail;
1608ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            while ( args < decoder->top )
1610ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              x += args[0];
1612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              cff_builder_add_point( builder, x, y, 0 );
1613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              x += args[1];
1614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              y += args[2];
1615ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              cff_builder_add_point( builder, x, y, 0 );
1616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              x += args[3];
1617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              cff_builder_add_point( builder, x, y, 1 );
1618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              args += 4;
1619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args = stack;
1621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_vhcurveto:
1625ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_hvcurveto:
1626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int  phase;
1628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int  nargs;
1629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( op == cff_op_vhcurveto ? " vhcurveto\n"
1632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                               : " hvcurveto\n" ));
1633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( cff_builder_start_point( builder, x, y ) )
1635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Fail;
1636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( num_args < 4 )
1638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Stack_Underflow;
1639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* if num_args isn't of the form 8n, 8n+1, 8n+4, or 8n+5, */
1641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* we enforce it by clearing the second bit               */
1642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            nargs = num_args & ~2;
1644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1645ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args -= nargs;
1646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( cff_check_points( builder, ( nargs / 4 ) * 3 ) )
1647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Stack_Underflow;
1648ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            phase = ( op == cff_op_hvcurveto );
1650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            while ( nargs >= 4 )
1652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              nargs -= 4;
1654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              if ( phase )
1655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              {
1656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                x += args[0];
1657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                cff_builder_add_point( builder, x, y, 0 );
1658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                x += args[1];
1659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                y += args[2];
1660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                cff_builder_add_point( builder, x, y, 0 );
1661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                y += args[3];
1662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                if ( nargs == 1 )
1663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                  x += args[4];
1664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                cff_builder_add_point( builder, x, y, 1 );
1665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              }
1666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              else
1667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              {
1668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                y += args[0];
1669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                cff_builder_add_point( builder, x, y, 0 );
1670ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                x += args[1];
1671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                y += args[2];
1672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                cff_builder_add_point( builder, x, y, 0 );
1673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                x += args[3];
1674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                if ( nargs == 1 )
1675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                  y += args[4];
1676ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                cff_builder_add_point( builder, x, y, 1 );
1677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              }
1678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              args  += 4;
1679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              phase ^= 1;
1680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args = stack;
1682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_rlinecurve:
1686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int  num_lines;
1688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int  nargs;
1689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " rlinecurve\n" ));
1692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( num_args < 8 )
1694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Stack_Underflow;
1695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            nargs     = num_args & ~1;
1697ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            num_lines = ( nargs - 6 ) / 2;
1698ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( cff_builder_start_point( builder, x, y )   ||
1700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 cff_check_points( builder, num_lines + 3 ) )
1701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Fail;
1702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args -= nargs;
1704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* first, add the line segments */
1706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            while ( num_lines > 0 )
1707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              x += args[0];
1709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              y += args[1];
1710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              cff_builder_add_point( builder, x, y, 1 );
1711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              args += 2;
1712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              num_lines--;
1713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1715ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* then the curve */
1716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            x += args[0];
1717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            y += args[1];
1718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 0 );
1719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            x += args[2];
1720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            y += args[3];
1721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 0 );
1722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            x += args[4];
1723ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            y += args[5];
1724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 1 );
1725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args = stack;
1726ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_rcurveline:
1730ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1731ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int  num_curves;
1732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int  nargs;
1733ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " rcurveline\n" ));
1736ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( num_args < 8 )
1738ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Stack_Underflow;
1739ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            nargs      = num_args - 2;
1741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            nargs      = nargs - nargs % 6 + 2;
1742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            num_curves = ( nargs - 2 ) / 6;
1743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( cff_builder_start_point( builder, x, y )        ||
1745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 cff_check_points( builder, num_curves * 3 + 2 ) )
1746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Fail;
1747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args -= nargs;
1749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1750ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* first, add the curves */
1751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            while ( num_curves > 0 )
1752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              x += args[0];
1754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              y += args[1];
1755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              cff_builder_add_point( builder, x, y, 0 );
1756ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              x += args[2];
1757ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              y += args[3];
1758ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              cff_builder_add_point( builder, x, y, 0 );
1759ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              x += args[4];
1760ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              y += args[5];
1761ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              cff_builder_add_point( builder, x, y, 1 );
1762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              args += 6;
1763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              num_curves--;
1764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* then the final line */
1767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            x += args[0];
1768ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            y += args[1];
1769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 1 );
1770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args = stack;
1771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1773ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_hflex1:
1775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Pos start_y;
1777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " hflex1\n" ));
1780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* adding five more points: 4 control points, 1 on-curve point */
1782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* -- make sure we have enough space for the start point if it */
1783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* needs to be added                                           */
1784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( cff_builder_start_point( builder, x, y ) ||
1785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 cff_check_points( builder, 6 )           )
1786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Fail;
1787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* record the starting point's y position for later use */
1789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            start_y = y;
1790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* first control point */
1792ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            x += args[0];
1793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            y += args[1];
1794ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 0 );
1795ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1796ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* second control point */
1797ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            x += args[2];
1798ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            y += args[3];
1799ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 0 );
1800ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1801ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* join point; on curve, with y-value the same as the last */
1802ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* control point's y-value                                 */
1803ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            x += args[4];
1804ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 1 );
1805ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1806ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* third control point, with y-value the same as the join */
1807ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* point's y-value                                        */
1808ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            x += args[5];
1809ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 0 );
1810ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1811ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* fourth control point */
1812ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            x += args[6];
1813ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            y += args[7];
1814ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 0 );
1815ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1816ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* ending point, with y-value the same as the start   */
1817ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            x += args[8];
1818ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            y  = start_y;
1819ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 1 );
1820ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1821ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args = stack;
1822ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
1823ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1824ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1825ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_hflex:
1826ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1827ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Pos start_y;
1828ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1829ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1830ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " hflex\n" ));
1831ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1832ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* adding six more points; 4 control points, 2 on-curve points */
1833ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( cff_builder_start_point( builder, x, y ) ||
1834ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 cff_check_points( builder, 6 )           )
1835ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Fail;
1836ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1837ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* record the starting point's y-position for later use */
1838ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            start_y = y;
1839ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1840ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* first control point */
1841ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            x += args[0];
1842ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 0 );
1843ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1844ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* second control point */
1845ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            x += args[1];
1846ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            y += args[2];
1847ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 0 );
1848ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1849ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* join point; on curve, with y-value the same as the last */
1850ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* control point's y-value                                 */
1851ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            x += args[3];
1852ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 1 );
1853ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1854ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* third control point, with y-value the same as the join */
1855ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* point's y-value                                        */
1856ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            x += args[4];
1857ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 0 );
1858ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1859ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* fourth control point */
1860ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            x += args[5];
1861ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            y  = start_y;
1862ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 0 );
1863ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1864ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* ending point, with y-value the same as the start point's */
1865ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* y-value -- we don't add this point, though               */
1866ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            x += args[6];
1867ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 1 );
1868ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1869ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args = stack;
1870ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
1871ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1872ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1873ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_flex1:
1874ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1875ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Pos     start_x, start_y; /* record start x, y values for */
1876ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                         /* alter use                    */
1877ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Fixed   dx = 0, dy = 0;   /* used in horizontal/vertical  */
1878ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                         /* algorithm below              */
1879ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int     horizontal, count;
1880ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Fixed*  temp;
1881ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1882ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1883ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " flex1\n" ));
1884ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1885ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* adding six more points; 4 control points, 2 on-curve points */
1886ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( cff_builder_start_point( builder, x, y ) ||
1887ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 cff_check_points( builder, 6 )           )
1888ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Fail;
1889ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1890ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* record the starting point's x, y position for later use */
1891ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            start_x = x;
1892ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            start_y = y;
1893ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1894ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* XXX: figure out whether this is supposed to be a horizontal */
1895ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /*      or vertical flex; the Type 2 specification is vague... */
1896ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1897ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            temp = args;
1898ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1899ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* grab up to the last argument */
1900ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            for ( count = 5; count > 0; count-- )
1901ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1902ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              dx += temp[0];
1903ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              dy += temp[1];
1904ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              temp += 2;
1905ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1906ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1907ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( dx < 0 )
1908ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              dx = -dx;
1909ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( dy < 0 )
1910ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              dy = -dy;
1911ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1912ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* strange test, but here it is... */
1913ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            horizontal = ( dx > dy );
1914ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1915ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            for ( count = 5; count > 0; count-- )
1916ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1917ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              x += args[0];
1918ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              y += args[1];
1919ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              cff_builder_add_point( builder, x, y,
1920ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                     (FT_Bool)( count == 3 ) );
1921ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              args += 2;
1922ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1923ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1924ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* is last operand an x- or y-delta? */
1925ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( horizontal )
1926ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1927ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              x += args[0];
1928ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              y  = start_y;
1929ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1930ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            else
1931ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1932ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              x  = start_x;
1933ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              y += args[0];
1934ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1935ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1936ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_add_point( builder, x, y, 1 );
1937ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1938ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args = stack;
1939ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
1940ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov           }
1941ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1942ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_flex:
1943ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1944ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_UInt  count;
1945ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1946ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1947ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " flex\n" ));
1948ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1949ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( cff_builder_start_point( builder, x, y ) ||
1950ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 cff_check_points( builder, 6 )           )
1951ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Fail;
1952ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1953ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            for ( count = 6; count > 0; count-- )
1954ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
1955ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              x += args[0];
1956ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              y += args[1];
1957ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              cff_builder_add_point( builder, x, y,
1958ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                     (FT_Bool)( count == 4 || count == 1 ) );
1959ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              args += 2;
1960ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
1961ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1962ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args = stack;
1963ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1964ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
1965ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1966ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_seac:
1967ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " seac\n" ));
1968ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1969ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            error = cff_operator_seac( decoder,
1970ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                       args[0], args[1], args[2],
1971ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                       (FT_Int)( args[3] >> 16 ),
1972ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                       (FT_Int)( args[4] >> 16 ) );
1973ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1974ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* add current outline to the glyph slot */
1975ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_GlyphLoader_Add( builder->loader );
1976ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1977ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* return now! */
1978ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( "\n" ));
1979ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return error;
1980ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1981ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_endchar:
1982ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " endchar\n" ));
1983ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1984ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* We are going to emulate the seac operator. */
1985ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( num_args >= 4 )
1986ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
1987ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* Save glyph width so that the subglyphs don't overwrite it. */
1988ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Pos  glyph_width = decoder->glyph_width;
1989ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1990ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1991ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            error = cff_operator_seac( decoder,
1992ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                       0L, args[-4], args[-3],
1993ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                       (FT_Int)( args[-2] >> 16 ),
1994ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                       (FT_Int)( args[-1] >> 16 ) );
1995ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
1996ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            decoder->glyph_width = glyph_width;
1997ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
1998ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          else
1999ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2000ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( !error )
2001ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              error = FT_Err_Ok;
2002ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2003ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cff_builder_close_contour( builder );
2004ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2005ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* close hints recording session */
2006ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( hinter )
2007ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
2008ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              if ( hinter->close( hinter->hints,
2009ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                  builder->current->n_points ) )
2010ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                goto Syntax_Error;
2011ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2012ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              /* apply hints to the loaded glyph outline now */
2013ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              hinter->apply( hinter->hints,
2014ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                             builder->current,
2015ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                             (PSH_Globals)builder->hints_globals,
2016ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                             decoder->hint_mode );
2017ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
2018ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2019ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* add current outline to the glyph slot */
2020ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_GlyphLoader_Add( builder->loader );
2021ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2022ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2023ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* return now! */
2024ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( "\n" ));
2025ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          return error;
2026ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2027ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_abs:
2028ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " abs\n" ));
2029ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2030ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( args[0] < 0 )
2031ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args[0] = -args[0];
2032ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args++;
2033ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2034ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2035ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_add:
2036ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " add\n" ));
2037ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2038ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args[0] += args[1];
2039ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args++;
2040ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2041ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2042ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_sub:
2043ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " sub\n" ));
2044ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2045ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args[0] -= args[1];
2046ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args++;
2047ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2048ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2049ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_div:
2050ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " div\n" ));
2051ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2052ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args[0] = FT_DivFix( args[0], args[1] );
2053ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args++;
2054ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2055ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2056ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_neg:
2057ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " neg\n" ));
2058ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2059ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args[0] = -args[0];
2060ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args++;
2061ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2062ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2063ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_random:
2064ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2065ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Fixed  Rand;
2066ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2067ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2068ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " rand\n" ));
2069ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2070ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            Rand = seed;
2071ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( Rand >= 0x8000L )
2072ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              Rand++;
2073ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2074ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args[0] = Rand;
2075ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            seed    = FT_MulFix( seed, 0x10000L - seed );
2076ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( seed == 0 )
2077ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              seed += 0x2873;
2078ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args++;
2079ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2080ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2081ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2082ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_mul:
2083ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " mul\n" ));
2084ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2085ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args[0] = FT_MulFix( args[0], args[1] );
2086ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args++;
2087ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2088ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2089ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_sqrt:
2090ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " sqrt\n" ));
2091ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2092ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( args[0] > 0 )
2093ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2094ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int    count = 9;
2095ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Fixed  root  = args[0];
2096ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Fixed  new_root;
2097ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2098ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2099ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            for (;;)
2100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
2101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              new_root = ( root + FT_DivFix( args[0], root ) + 1 ) >> 1;
2102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              if ( new_root == root || count <= 0 )
2103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                break;
2104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              root = new_root;
2105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
2106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args[0] = new_root;
2107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          else
2109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args[0] = 0;
2110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args++;
2111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_drop:
2114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* nothing */
2115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " drop\n" ));
2116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_exch:
2120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Fixed  tmp;
2122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " exch\n" ));
2125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            tmp     = args[0];
2127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args[0] = args[1];
2128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args[1] = tmp;
2129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args   += 2;
2130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_index:
2134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int  idx = (FT_Int)( args[0] >> 16 );
2136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " index\n" ));
2139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( idx < 0 )
2141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              idx = 0;
2142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            else if ( idx > num_args - 2 )
2143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              idx = num_args - 2;
2144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args[0] = args[-( idx + 1 )];
2145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args++;
2146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_roll:
2150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int  count = (FT_Int)( args[0] >> 16 );
2152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int  idx   = (FT_Int)( args[1] >> 16 );
2153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " roll\n" ));
2156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( count <= 0 )
2158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              count = 1;
2159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args -= count;
2161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( args < stack )
2162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Stack_Underflow;
2163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( idx >= 0 )
2165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
2166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              while ( idx > 0 )
2167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              {
2168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FT_Fixed  tmp = args[count - 1];
2169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FT_Int    i;
2170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                for ( i = count - 2; i >= 0; i-- )
2173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                  args[i + 1] = args[i];
2174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                args[0] = tmp;
2175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                idx--;
2176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              }
2177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
2178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            else
2179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
2180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              while ( idx < 0 )
2181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              {
2182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FT_Fixed  tmp = args[0];
2183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FT_Int    i;
2184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                for ( i = 0; i < count - 1; i++ )
2187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                  args[i] = args[i + 1];
2188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                args[count - 1] = tmp;
2189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                idx++;
2190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              }
2191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
2192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args += count;
2193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_dup:
2197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " dup\n" ));
2198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args[1] = args[0];
2200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args += 2;
2201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_put:
2204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Fixed  val = args[0];
2206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int    idx = (FT_Int)( args[1] >> 16 );
2207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " put\n" ));
2210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( idx >= 0 && idx < CFF_MAX_TRANS_ELEMENTS )
2212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              decoder->buildchar[idx] = val;
2213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_get:
2217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Int    idx = (FT_Int)( args[0] >> 16 );
2219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Fixed  val = 0;
2220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " get\n" ));
2223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( idx >= 0 && idx < CFF_MAX_TRANS_ELEMENTS )
2225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              val = decoder->buildchar[idx];
2226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args[0] = val;
2228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args++;
2229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_store:
2233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " store\n"));
2234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          goto Unimplemented;
2236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_load:
2238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " load\n" ));
2239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          goto Unimplemented;
2241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_dotsection:
2243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* this operator is deprecated and ignored by the parser */
2244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " dotsection\n" ));
2245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_closepath:
2248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* this is an invalid Type 2 operator; however, there        */
2249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* exist fonts which are incorrectly converted from probably */
2250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* Type 1 to CFF, and some parsers seem to accept it         */
2251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " closepath (invalid op)\n" ));
2253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args = stack;
2255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_hsbw:
2258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* this is an invalid Type 2 operator; however, there        */
2259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* exist fonts which are incorrectly converted from probably */
2260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* Type 1 to CFF, and some parsers seem to accept it         */
2261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " hsbw (invalid op)\n" ));
2263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          decoder->glyph_width = decoder->nominal_width + ( args[1] >> 16 );
2265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          decoder->builder.left_bearing.x = args[0];
2267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          decoder->builder.left_bearing.y = 0;
2268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          x    = decoder->builder.pos_x + args[0];
2270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          y    = decoder->builder.pos_y;
2271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args = stack;
2272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_sbw:
2275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* this is an invalid Type 2 operator; however, there        */
2276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* exist fonts which are incorrectly converted from probably */
2277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* Type 1 to CFF, and some parsers seem to accept it         */
2278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " sbw (invalid op)\n" ));
2280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          decoder->glyph_width = decoder->nominal_width + ( args[2] >> 16 );
2282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          decoder->builder.left_bearing.x = args[0];
2284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          decoder->builder.left_bearing.y = args[1];
2285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          x    = decoder->builder.pos_x + args[0];
2287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          y    = decoder->builder.pos_y + args[1];
2288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args = stack;
2289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_setcurrentpoint:
2292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* this is an invalid Type 2 operator; however, there        */
2293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* exist fonts which are incorrectly converted from probably */
2294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* Type 1 to CFF, and some parsers seem to accept it         */
2295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " setcurrentpoint (invalid op)\n" ));
2297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          x    = decoder->builder.pos_x + args[0];
2299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          y    = decoder->builder.pos_y + args[1];
2300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args = stack;
2301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_callothersubr:
2304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* this is an invalid Type 2 operator; however, there        */
2305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* exist fonts which are incorrectly converted from probably */
2306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* Type 1 to CFF, and some parsers seem to accept it         */
2307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " callothersubr (invalid op)\n" ));
2309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* subsequent `pop' operands should add the arguments,       */
2311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* this is the implementation described for `unknown' other  */
2312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* subroutines in the Type1 spec.                            */
2313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /*                                                           */
2314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* XXX Fix return arguments (see discussion below).          */
2315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args -= 2 + ( args[-2] >> 16 );
2316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( args < stack )
2317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            goto Stack_Underflow;
2318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_pop:
2321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* this is an invalid Type 2 operator; however, there        */
2322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* exist fonts which are incorrectly converted from probably */
2323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* Type 1 to CFF, and some parsers seem to accept it         */
2324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " pop (invalid op)\n" ));
2326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* XXX Increasing `args' is wrong: After a certain number of */
2328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* `pop's we get a stack overflow.  Reason for doing it is   */
2329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* code like this (actually found in a CFF font):            */
2330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /*                                                           */
2331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /*   17 1 3 callothersubr                                    */
2332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /*   pop                                                     */
2333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /*   callsubr                                                */
2334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /*                                                           */
2335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* Since we handle `callothersubr' as a no-op, and           */
2336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* `callsubr' needs at least one argument, `pop' can't be a  */
2337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* no-op too as it basically should be.                      */
2338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /*                                                           */
2339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* The right solution would be to provide real support for   */
2340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* `callothersubr' as done in `t1decode.c', however, given   */
2341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* the fact that CFF fonts with `pop' are invalid, it is     */
2342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* questionable whether it is worth the time.                */
2343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          args++;
2344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_and:
2347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Fixed  cond = args[0] && args[1];
2349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " and\n" ));
2352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args[0] = cond ? 0x10000L : 0;
2354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args++;
2355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_or:
2359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Fixed  cond = args[0] || args[1];
2361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " or\n" ));
2364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args[0] = cond ? 0x10000L : 0;
2366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args++;
2367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_eq:
2371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Fixed  cond = !args[0];
2373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " eq\n" ));
2376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args[0] = cond ? 0x10000L : 0;
2378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args++;
2379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_ifelse:
2383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_Fixed  cond = ( args[2] <= args[3] );
2385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " ifelse\n" ));
2388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( !cond )
2390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              args[0] = args[1];
2391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            args++;
2392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_callsubr:
2396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_UInt  idx = (FT_UInt)( ( args[0] >> 16 ) +
2398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                      decoder->locals_bias );
2399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " callsubr(%d)\n", idx ));
2402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( idx >= decoder->num_locals )
2404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
2405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_ERROR(( "cff_decoder_parse_charstrings:"
2406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                         " invalid local subr index\n" ));
2407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Syntax_Error;
2408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
2409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
2411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
2412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_ERROR(( "cff_decoder_parse_charstrings:"
2413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                         " too many nested subrs\n" ));
2414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Syntax_Error;
2415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
2416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            zone->cursor = ip;  /* save current instruction pointer */
2418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            zone++;
2420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            zone->base   = decoder->locals[idx];
2421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            zone->limit  = decoder->locals[idx + 1];
2422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            zone->cursor = zone->base;
2423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( !zone->base || zone->limit == zone->base )
2425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
2426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_ERROR(( "cff_decoder_parse_charstrings:"
2427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                         " invoking empty subrs\n" ));
2428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Syntax_Error;
2429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
2430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            decoder->zone = zone;
2432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ip            = zone->base;
2433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            limit         = zone->limit;
2434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_callgsubr:
2438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_UInt  idx = (FT_UInt)( ( args[0] >> 16 ) +
2440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                      decoder->globals_bias );
2441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_TRACE4(( " callgsubr(%d)\n", idx ));
2444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( idx >= decoder->num_globals )
2446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
2447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_ERROR(( "cff_decoder_parse_charstrings:"
2448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                         " invalid global subr index\n" ));
2449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Syntax_Error;
2450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
2451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
2453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
2454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_ERROR(( "cff_decoder_parse_charstrings:"
2455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                         " too many nested subrs\n" ));
2456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Syntax_Error;
2457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
2458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            zone->cursor = ip;  /* save current instruction pointer */
2460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            zone++;
2462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            zone->base   = decoder->globals[idx];
2463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            zone->limit  = decoder->globals[idx + 1];
2464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            zone->cursor = zone->base;
2465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( !zone->base || zone->limit == zone->base )
2467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
2468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              FT_ERROR(( "cff_decoder_parse_charstrings:"
2469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                         " invoking empty subrs\n" ));
2470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              goto Syntax_Error;
2471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
2472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            decoder->zone = zone;
2474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ip            = zone->base;
2475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            limit         = zone->limit;
2476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        case cff_op_return:
2480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_TRACE4(( " return\n" ));
2481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( decoder->zone <= decoder->zones )
2483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_ERROR(( "cff_decoder_parse_charstrings:"
2485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       " unexpected return\n" ));
2486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            goto Syntax_Error;
2487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          decoder->zone--;
2490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          zone  = decoder->zone;
2491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          ip    = zone->cursor;
2492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          limit = zone->limit;
2493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          break;
2494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        default:
2496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        Unimplemented:
2497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_ERROR(( "Unimplemented opcode: %d", ip[-1] ));
2498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( ip[-1] == 12 )
2500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_ERROR(( " %d", ip[0] ));
2501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_ERROR(( "\n" ));
2502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          return FT_THROW( Unimplemented_Feature );
2504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
2505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        decoder->top = args;
2507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( decoder->top - stack >= CFF_MAX_OPERANDS )
2509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          goto Stack_Overflow;
2510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      } /* general operator processing */
2512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } /* while ip < limit */
2514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_TRACE4(( "..end..\n\n" ));
2516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Fail:
2518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return error;
2519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Syntax_Error:
2521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error\n" ));
2522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_THROW( Invalid_File_Format );
2523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Stack_Underflow:
2525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_TRACE4(( "cff_decoder_parse_charstrings: stack underflow\n" ));
2526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_THROW( Too_Few_Arguments );
2527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Stack_Overflow:
2529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_TRACE4(( "cff_decoder_parse_charstrings: stack overflow\n" ));
2530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_THROW( Stack_Overflow );
2531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
2534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /**********                                                      *********/
2540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /**********                                                      *********/
2541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /**********            COMPUTE THE MAXIMUM ADVANCE WIDTH         *********/
2542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /**********                                                      *********/
2543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /**********    The following code is in charge of computing      *********/
2544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /**********    the maximum advance width of the font.  It        *********/
2545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /**********    quickly processes each glyph charstring to        *********/
2546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /**********    extract the value from either a `sbw' or `seac'   *********/
2547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /**********    operator.                                         *********/
2548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /**********                                                      *********/
2549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*************************************************************************/
2552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#if 0 /* unused until we support pure CFF fonts */
2555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( FT_Error )
2558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_compute_max_advance( TT_Face  face,
2559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                           FT_Int*  max_advance )
2560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Error     error = FT_Err_Ok;
2562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CFF_Decoder  decoder;
2563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Int       glyph_index;
2564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CFF_Font     cff = (CFF_Font)face->other;
2565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    *max_advance = 0;
2568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* Initialize load decoder */
2570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    cff_decoder_init( &decoder, face, 0, 0, 0, 0 );
2571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder.builder.metrics_only = 1;
2573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    decoder.builder.load_points  = 0;
2574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* For each glyph, parse the glyph charstring and extract */
2576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* the advance width.                                     */
2577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( glyph_index = 0; glyph_index < face->root.num_glyphs;
2578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          glyph_index++ )
2579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*  charstring;
2581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_ULong  charstring_len;
2582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* now get load the unscaled outline */
2585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      error = cff_get_glyph_data( face, glyph_index,
2586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                  &charstring, &charstring_len );
2587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( !error )
2588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        error = cff_decoder_prepare( &decoder, size, glyph_index );
2590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( !error )
2591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          error = cff_decoder_parse_charstrings( &decoder,
2592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                 charstring,
2593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                 charstring_len );
2594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2595ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cff_free_glyph_data( face, &charstring, &charstring_len );
2596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* ignore the error if one has occurred -- skip to next glyph */
2599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      error = FT_Err_Ok;
2600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    *max_advance = decoder.builder.advance.x;
2603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_Err_Ok;
2605ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
2606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2607ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2608ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* 0 */
2609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2610ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_LOCAL_DEF( FT_Error )
2612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  cff_slot_load( CFF_GlyphSlot  glyph,
2613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 CFF_Size       size,
2614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 FT_UInt        glyph_index,
2615ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                 FT_Int32       load_flags )
2616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
2617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Error     error;
2618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CFF_Decoder  decoder;
2619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    TT_Face      face = (TT_Face)glyph->root.face;
2620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Bool      hinting, scaled, force_scaling;
2621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CFF_Font     cff  = (CFF_Font)face->extra.data;
2622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Matrix    font_matrix;
2624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Vector    font_offset;
2625ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    force_scaling = FALSE;
2628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* in a CID-keyed font, consider `glyph_index' as a CID and map */
2630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* it immediately to the real glyph_index -- if it isn't a      */
2631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* subsetted font, glyph_indices and CIDs are identical, though */
2632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( cff->top_font.font_dict.cid_registry != 0xFFFFU &&
2633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov         cff->charset.cids                               )
2634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* don't handle CID 0 (.notdef) which is directly mapped to GID 0 */
2636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( glyph_index != 0 )
2637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        glyph_index = cff_charset_cid_to_gindex( &cff->charset,
2639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                 glyph_index );
2640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( glyph_index == 0 )
2641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          return FT_THROW( Invalid_Argument );
2642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else if ( glyph_index >= cff->num_glyphs )
2645ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return FT_THROW( Invalid_Argument );
2646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( load_flags & FT_LOAD_NO_RECURSE )
2648ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
2649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    glyph->x_scale = 0x10000L;
2651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    glyph->y_scale = 0x10000L;
2652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( size )
2653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      glyph->x_scale = size->root.metrics.x_scale;
2655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      glyph->y_scale = size->root.metrics.y_scale;
2656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
2659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* try to load embedded bitmap if any              */
2661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /*                                                 */
2662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* XXX: The convention should be emphasized in     */
2663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /*      the documents because it can be confusing. */
2664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( size )
2665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      CFF_Face      cff_face = (CFF_Face)size->root.face;
2667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      SFNT_Service  sfnt     = (SFNT_Service)cff_face->sfnt;
2668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Stream     stream   = cff_face->root.stream;
2669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2670ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( size->strike_index != 0xFFFFFFFFUL      &&
2672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov           sfnt->load_eblc                         &&
2673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov           ( load_flags & FT_LOAD_NO_BITMAP ) == 0 )
2674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        TT_SBit_MetricsRec  metrics;
2676ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        error = sfnt->load_sbit_image( face,
2679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                       size->strike_index,
2680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                       glyph_index,
2681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                       (FT_Int)load_flags,
2682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                       stream,
2683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                       &glyph->root.bitmap,
2684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                       &metrics );
2685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( !error )
2687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
2688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Bool    has_vertical_info;
2689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_UShort  advance;
2690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Short   dummy;
2691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          glyph->root.outline.n_points   = 0;
2694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          glyph->root.outline.n_contours = 0;
2695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          glyph->root.metrics.width  = (FT_Pos)metrics.width  << 6;
2697ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          glyph->root.metrics.height = (FT_Pos)metrics.height << 6;
2698ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          glyph->root.metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6;
2700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          glyph->root.metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6;
2701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          glyph->root.metrics.horiAdvance  = (FT_Pos)metrics.horiAdvance  << 6;
2702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          glyph->root.metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6;
2704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          glyph->root.metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6;
2705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          glyph->root.metrics.vertAdvance  = (FT_Pos)metrics.vertAdvance  << 6;
2706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          glyph->root.format = FT_GLYPH_FORMAT_BITMAP;
2708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
2710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            glyph->root.bitmap_left = metrics.vertBearingX;
2712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            glyph->root.bitmap_top  = metrics.vertBearingY;
2713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          else
2715ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            glyph->root.bitmap_left = metrics.horiBearingX;
2717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            glyph->root.bitmap_top  = metrics.horiBearingY;
2718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* compute linear advance widths */
2721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          ( (SFNT_Service)face->sfnt )->get_metrics( face, 0,
2723ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                     glyph_index,
2724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                     &dummy,
2725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                     &advance );
2726ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          glyph->root.linearHoriAdvance = advance;
2727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          has_vertical_info = FT_BOOL(
2729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                face->vertical_info                   &&
2730ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                face->vertical.number_Of_VMetrics > 0 );
2731ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* get the vertical metrics from the vtmx table if we have one */
2733ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( has_vertical_info )
2734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ( (SFNT_Service)face->sfnt )->get_metrics( face, 1,
2736ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                       glyph_index,
2737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                       &dummy,
2738ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                       &advance );
2739ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            glyph->root.linearVertAdvance = advance;
2740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          else
2742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
2743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            /* make up vertical ones */
2744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ( face->os2.version != 0xFFFFU )
2745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              glyph->root.linearVertAdvance = (FT_Pos)
2746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                ( face->os2.sTypoAscender - face->os2.sTypoDescender );
2747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            else
2748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              glyph->root.linearVertAdvance = (FT_Pos)
2749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                ( face->horizontal.Ascender - face->horizontal.Descender );
2750ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
2751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          return error;
2753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
2754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2756ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2757ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
2758ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2759ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* return immediately if we only want the embedded bitmaps */
2760ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( load_flags & FT_LOAD_SBITS_ONLY )
2761ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return FT_THROW( Invalid_Argument );
2762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* if we have a CID subfont, use its matrix (which has already */
2764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* been multiplied with the root matrix)                       */
2765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* this scaling is only relevant if the PS hinter isn't active */
2767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( cff->num_subfonts )
2768ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_ULong  top_upm, sub_upm;
2770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte   fd_index = cff_fd_select_get( &cff->fd_select,
2771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                              glyph_index );
2772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2773ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( fd_index >= cff->num_subfonts )
2775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        fd_index = (FT_Byte)( cff->num_subfonts - 1 );
2776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      top_upm = cff->top_font.font_dict.units_per_em;
2778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      sub_upm = cff->subfonts[fd_index]->font_dict.units_per_em;
2779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      font_matrix = cff->subfonts[fd_index]->font_dict.font_matrix;
2782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      font_offset = cff->subfonts[fd_index]->font_dict.font_offset;
2783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( top_upm != sub_upm )
2785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        glyph->x_scale = FT_MulDiv( glyph->x_scale, top_upm, sub_upm );
2787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        glyph->y_scale = FT_MulDiv( glyph->y_scale, top_upm, sub_upm );
2788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        force_scaling = TRUE;
2790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2792ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
2793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2794ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      font_matrix = cff->top_font.font_dict.font_matrix;
2795ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      font_offset = cff->top_font.font_dict.font_offset;
2796ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2797ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2798ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    glyph->root.outline.n_points   = 0;
2799ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    glyph->root.outline.n_contours = 0;
2800ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2801ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* top-level code ensures that FT_LOAD_NO_HINTING is set */
2802ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* if FT_LOAD_NO_SCALE is active                         */
2803ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
2804ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    scaled  = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE   ) == 0 );
2805ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2806ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    glyph->hint        = hinting;
2807ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    glyph->scaled      = scaled;
2808ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;  /* by default */
2809ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2810ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2811ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
2812ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      CFF_Driver  driver = (CFF_Driver)FT_FACE_DRIVER( face );
2813ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif
2814ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2815ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2816ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Byte*  charstring;
2817ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_ULong  charstring_len;
2818ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2819ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2820ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cff_decoder_init( &decoder, face, size, glyph, hinting,
2821ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FT_LOAD_TARGET_MODE( load_flags ) );
2822ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2823ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( load_flags & FT_LOAD_ADVANCE_ONLY )
2824ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        decoder.width_only = TRUE;
2825ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2826ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      decoder.builder.no_recurse =
2827ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        (FT_Bool)( load_flags & FT_LOAD_NO_RECURSE );
2828ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2829ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* now load the unscaled outline */
2830ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      error = cff_get_glyph_data( face, glyph_index,
2831ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                  &charstring, &charstring_len );
2832ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( error )
2833ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Glyph_Build_Finished;
2834ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2835ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      error = cff_decoder_prepare( &decoder, size, glyph_index );
2836ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( error )
2837ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Glyph_Build_Finished;
2838ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2839ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
2840ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* choose which CFF renderer to use */
2841ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( driver->hinting_engine == FT_CFF_HINTING_FREETYPE )
2842ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        error = cff_decoder_parse_charstrings( &decoder,
2843ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                               charstring,
2844ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                               charstring_len );
2845ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
2846ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif
2847ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2848ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        error = cf2_decoder_parse_charstrings( &decoder,
2849ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                               charstring,
2850ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                               charstring_len );
2851ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2852ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* Adobe's engine uses 16.16 numbers everywhere;              */
2853ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* as a consequence, glyphs larger than 2000ppem get rejected */
2854ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( FT_ERR_EQ( error, Glyph_Too_Big ) )
2855ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
2856ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* this time, we retry unhinted and scale up the glyph later on */
2857ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* (the engine uses and sets the hardcoded value 0x10000 / 64 = */
2858ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* 0x400 for both `x_scale' and `y_scale' in this case)         */
2859ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          hinting       = FALSE;
2860ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          force_scaling = TRUE;
2861ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          glyph->hint   = hinting;
2862ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2863ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          error = cf2_decoder_parse_charstrings( &decoder,
2864ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                 charstring,
2865ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                 charstring_len );
2866ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
2867ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2868ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2869ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      cff_free_glyph_data( face, &charstring, charstring_len );
2870ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2871ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( error )
2872ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Glyph_Build_Finished;
2873ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2874ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef FT_CONFIG_OPTION_INCREMENTAL
2875ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* Control data and length may not be available for incremental */
2876ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* fonts.                                                       */
2877ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( face->root.internal->incremental_interface )
2878ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2879ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        glyph->root.control_data = 0;
2880ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        glyph->root.control_len = 0;
2881ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2882ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
2883ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* FT_CONFIG_OPTION_INCREMENTAL */
2884ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2885ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* We set control_data and control_len if charstrings is loaded. */
2886ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* See how charstring loads at cff_index_access_element() in     */
2887ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* cffload.c.                                                    */
2888ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2889ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        CFF_Index  csindex = &cff->charstrings_index;
2890ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2891ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2892ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( csindex->offsets )
2893ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
2894ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          glyph->root.control_data = csindex->bytes +
2895ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                     csindex->offsets[glyph_index] - 1;
2896ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          glyph->root.control_len  = charstring_len;
2897ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
2898ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2899ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2900ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Glyph_Build_Finished:
2901ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* save new glyph tables, if no error */
2902ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( !error )
2903ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        cff_builder_done( &decoder.builder );
2904ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* XXX: anything to do for broken glyph entry? */
2905ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2906ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2907ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef FT_CONFIG_OPTION_INCREMENTAL
2908ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2909ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* Incremental fonts can optionally override the metrics. */
2910ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !error                                                               &&
2911ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov         face->root.internal->incremental_interface                           &&
2912ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov         face->root.internal->incremental_interface->funcs->get_glyph_metrics )
2913ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2914ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_Incremental_MetricsRec  metrics;
2915ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2916ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2917ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      metrics.bearing_x = decoder.builder.left_bearing.x;
2918ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      metrics.bearing_y = 0;
2919ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      metrics.advance   = decoder.builder.advance.x;
2920ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      metrics.advance_v = decoder.builder.advance.y;
2921ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2922ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      error = face->root.internal->incremental_interface->funcs->get_glyph_metrics(
2923ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                face->root.internal->incremental_interface->object,
2924ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                glyph_index, FALSE, &metrics );
2925ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2926ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      decoder.builder.left_bearing.x = metrics.bearing_x;
2927ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      decoder.builder.advance.x      = metrics.advance;
2928ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      decoder.builder.advance.y      = metrics.advance_v;
2929ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
2930ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2931ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* FT_CONFIG_OPTION_INCREMENTAL */
2932ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2933ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !error )
2934ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
2935ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* Now, set the metrics -- this is rather simple, as   */
2936ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* the left side bearing is the xMin, and the top side */
2937ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* bearing the yMax.                                   */
2938ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2939ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* For composite glyphs, return only left side bearing and */
2940ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* advance width.                                          */
2941ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( load_flags & FT_LOAD_NO_RECURSE )
2942ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2943ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Slot_Internal  internal = glyph->root.internal;
2944ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2945ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2946ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
2947ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        glyph->root.metrics.horiAdvance  = decoder.glyph_width;
2948ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        internal->glyph_matrix           = font_matrix;
2949ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        internal->glyph_delta            = font_offset;
2950ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        internal->glyph_transformed      = 1;
2951ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
2952ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
2953ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
2954ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_BBox            cbox;
2955ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Glyph_Metrics*  metrics = &glyph->root.metrics;
2956ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Vector          advance;
2957ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Bool            has_vertical_info;
2958ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2959ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2960ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* copy the _unscaled_ advance width */
2961ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        metrics->horiAdvance                    = decoder.glyph_width;
2962ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        glyph->root.linearHoriAdvance           = decoder.glyph_width;
2963ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        glyph->root.internal->glyph_transformed = 0;
2964ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2965ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        has_vertical_info = FT_BOOL( face->vertical_info                   &&
2966ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                     face->vertical.number_Of_VMetrics > 0 );
2967ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2968ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* get the vertical metrics from the vtmx table if we have one */
2969ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( has_vertical_info )
2970ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
2971ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Short   vertBearingY = 0;
2972ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_UShort  vertAdvance  = 0;
2973ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2974ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2975ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          ( (SFNT_Service)face->sfnt )->get_metrics( face, 1,
2976ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                     glyph_index,
2977ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                     &vertBearingY,
2978ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                                     &vertAdvance );
2979ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          metrics->vertBearingY = vertBearingY;
2980ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          metrics->vertAdvance  = vertAdvance;
2981ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
2982ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else
2983ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
2984ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* make up vertical ones */
2985ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( face->os2.version != 0xFFFFU )
2986ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            metrics->vertAdvance = (FT_Pos)( face->os2.sTypoAscender -
2987ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                             face->os2.sTypoDescender );
2988ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          else
2989ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            metrics->vertAdvance = (FT_Pos)( face->horizontal.Ascender -
2990ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                             face->horizontal.Descender );
2991ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
2992ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2993ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        glyph->root.linearVertAdvance = metrics->vertAdvance;
2994ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2995ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
2996ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
2997ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        glyph->root.outline.flags = 0;
2998ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( size && size->root.metrics.y_ppem < 24 )
2999ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION;
3000ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3001ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL;
3002ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3003ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( !( font_matrix.xx == 0x10000L &&
3004ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                font_matrix.yy == 0x10000L &&
3005ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                font_matrix.xy == 0        &&
3006ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                font_matrix.yx == 0        ) )
3007ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Outline_Transform( &glyph->root.outline, &font_matrix );
3008ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3009ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( !( font_offset.x == 0 &&
3010ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                font_offset.y == 0 ) )
3011ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Outline_Translate( &glyph->root.outline,
3012ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                font_offset.x, font_offset.y );
3013ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3014ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        advance.x = metrics->horiAdvance;
3015ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        advance.y = 0;
3016ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Vector_Transform( &advance, &font_matrix );
3017ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        metrics->horiAdvance = advance.x + font_offset.x;
3018ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3019ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        advance.x = 0;
3020ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        advance.y = metrics->vertAdvance;
3021ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Vector_Transform( &advance, &font_matrix );
3022ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        metrics->vertAdvance = advance.y + font_offset.y;
3023ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3024ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling )
3025ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
3026ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* scale the outline and the metrics */
3027ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Int       n;
3028ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Outline*  cur     = &glyph->root.outline;
3029ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Vector*   vec     = cur->points;
3030ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Fixed     x_scale = glyph->x_scale;
3031ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Fixed     y_scale = glyph->y_scale;
3032ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3033ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3034ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* First of all, scale the points */
3035ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( !hinting || !decoder.builder.hints_funcs )
3036ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            for ( n = cur->n_points; n > 0; n--, vec++ )
3037ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            {
3038ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              vec->x = FT_MulFix( vec->x, x_scale );
3039ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              vec->y = FT_MulFix( vec->y, y_scale );
3040ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
3041ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3042ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* Then scale the metrics */
3043ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
3044ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
3045ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
3046ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3047ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* compute the other metrics */
3048ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
3049ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3050ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        metrics->width  = cbox.xMax - cbox.xMin;
3051ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        metrics->height = cbox.yMax - cbox.yMin;
3052ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3053ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        metrics->horiBearingX = cbox.xMin;
3054ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        metrics->horiBearingY = cbox.yMax;
3055ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3056ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( has_vertical_info )
3057ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          metrics->vertBearingX = metrics->horiBearingX -
3058ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                    metrics->horiAdvance / 2;
3059ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else
3060ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
3061ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
3062ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ft_synthesize_vertical_metrics( metrics,
3063ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                            metrics->vertAdvance );
3064ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
3065ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
3066ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
3067ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3068ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return error;
3069ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
3070ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3071ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
3072ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* END */
3073