blob: 6e86db657aa9ccd7b0b35b6a4605cea5a41a4f57 [file] [log] [blame]
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001/***************************************************************************/
2/* */
3/* cffgload.c */
4/* */
5/* OpenType Glyph Loader (body). */
6/* */
Werner Lemberg48c984b2002-03-30 16:41:09 +00007/* Copyright 1996-2001, 2002 by */
Tom Kacvinskycd92b112001-01-03 00:15:00 +00008/* David Turner, Robert Wilhelm, and Werner Lemberg. */
9/* */
10/* This file is part of the FreeType project, and may only be used, */
11/* modified, and distributed under the terms of the FreeType project */
12/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13/* this file you indicate that you have read the license and */
14/* understand and accept it fully. */
15/* */
16/***************************************************************************/
17
18
19#include <ft2build.h>
20#include FT_INTERNAL_DEBUG_H
21#include FT_INTERNAL_CALC_H
22#include FT_INTERNAL_STREAM_H
23#include FT_INTERNAL_SFNT_H
24#include FT_OUTLINE_H
25#include FT_TRUETYPE_TAGS_H
David Turner2b30c172001-12-12 16:07:29 +000026#include FT_INTERNAL_POSTSCRIPT_HINTS_H
Tom Kacvinskycd92b112001-01-03 00:15:00 +000027
David Turnerc8087482001-12-20 13:14:18 +000028#include "cffobjs.h"
David Turner8d3a4012001-03-20 11:14:24 +000029#include "cffload.h"
30#include "cffgload.h"
Tom Kacvinskycd92b112001-01-03 00:15:00 +000031
Werner Lemberg1f7f0e82001-06-06 17:30:41 +000032#include "cfferrs.h"
Tom Kacvinskycd92b112001-01-03 00:15:00 +000033
34
35 /*************************************************************************/
36 /* */
37 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
38 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
39 /* messages during execution. */
40 /* */
41#undef FT_COMPONENT
42#define FT_COMPONENT trace_cffgload
43
44
45 typedef enum CFF_Operator_
46 {
47 cff_op_unknown = 0,
48
49 cff_op_rmoveto,
50 cff_op_hmoveto,
51 cff_op_vmoveto,
52
53 cff_op_rlineto,
54 cff_op_hlineto,
55 cff_op_vlineto,
56
57 cff_op_rrcurveto,
58 cff_op_hhcurveto,
59 cff_op_hvcurveto,
60 cff_op_rcurveline,
61 cff_op_rlinecurve,
62 cff_op_vhcurveto,
63 cff_op_vvcurveto,
64
65 cff_op_flex,
66 cff_op_hflex,
67 cff_op_hflex1,
68 cff_op_flex1,
69
70 cff_op_endchar,
71
72 cff_op_hstem,
73 cff_op_vstem,
74 cff_op_hstemhm,
75 cff_op_vstemhm,
76
77 cff_op_hintmask,
78 cff_op_cntrmask,
David Turner8d3a4012001-03-20 11:14:24 +000079 cff_op_dotsection, /* deprecated, acts as no-op */
Tom Kacvinskycd92b112001-01-03 00:15:00 +000080
81 cff_op_abs,
82 cff_op_add,
83 cff_op_sub,
84 cff_op_div,
85 cff_op_neg,
86 cff_op_random,
87 cff_op_mul,
88 cff_op_sqrt,
89
90 cff_op_blend,
91
92 cff_op_drop,
93 cff_op_exch,
94 cff_op_index,
95 cff_op_roll,
96 cff_op_dup,
97
98 cff_op_put,
99 cff_op_get,
100 cff_op_store,
101 cff_op_load,
102
103 cff_op_and,
104 cff_op_or,
105 cff_op_not,
106 cff_op_eq,
107 cff_op_ifelse,
108
109 cff_op_callsubr,
110 cff_op_callgsubr,
111 cff_op_return,
112
113 /* do not remove */
114 cff_op_max
115
116 } CFF_Operator;
117
118
119#define CFF_COUNT_CHECK_WIDTH 0x80
120#define CFF_COUNT_EXACT 0x40
121#define CFF_COUNT_CLEAR_STACK 0x20
122
123
124 static const FT_Byte cff_argument_counts[] =
125 {
126 0, /* unknown */
127
128 2 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, /* rmoveto */
129 1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT,
130 1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT,
131
132 0 | CFF_COUNT_CLEAR_STACK, /* rlineto */
133 0 | CFF_COUNT_CLEAR_STACK,
134 0 | CFF_COUNT_CLEAR_STACK,
135
136 0 | CFF_COUNT_CLEAR_STACK, /* rrcurveto */
137 0 | CFF_COUNT_CLEAR_STACK,
138 0 | CFF_COUNT_CLEAR_STACK,
139 0 | CFF_COUNT_CLEAR_STACK,
140 0 | CFF_COUNT_CLEAR_STACK,
141 0 | CFF_COUNT_CLEAR_STACK,
142 0 | CFF_COUNT_CLEAR_STACK,
143
144 13, /* flex */
145 7,
146 9,
147 11,
148
149 0 | CFF_COUNT_CHECK_WIDTH, /* endchar */
150
151 2 | CFF_COUNT_CHECK_WIDTH, /* hstem */
152 2 | CFF_COUNT_CHECK_WIDTH,
153 2 | CFF_COUNT_CHECK_WIDTH,
154 2 | CFF_COUNT_CHECK_WIDTH,
155
David Turnerc8087482001-12-20 13:14:18 +0000156 0 | CFF_COUNT_CHECK_WIDTH, /* hintmask */
157 0 | CFF_COUNT_CHECK_WIDTH, /* cntrmask */
Tom Kacvinsky8316bc52001-03-16 13:35:56 +0000158 0, /* dotsection */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000159
160 1, /* abs */
161 2,
162 2,
163 2,
164 1,
165 0,
166 2,
167 1,
168
169 1, /* blend */
170
171 1, /* drop */
172 2,
173 1,
174 2,
175 1,
176
177 2, /* put */
178 1,
179 4,
180 3,
181
182 2, /* and */
183 2,
184 1,
185 2,
186 4,
187
188 1, /* callsubr */
189 1,
190 0
191 };
192
193
194 /*************************************************************************/
195 /*************************************************************************/
196 /*************************************************************************/
197 /********** *********/
198 /********** *********/
199 /********** GENERIC CHARSTRING PARSING *********/
200 /********** *********/
201 /********** *********/
202 /*************************************************************************/
203 /*************************************************************************/
204 /*************************************************************************/
205
206
207 /*************************************************************************/
208 /* */
209 /* <Function> */
David Turnerb9b2cac2002-07-10 16:52:06 +0000210 /* cff_builder_init */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000211 /* */
212 /* <Description> */
213 /* Initializes a given glyph builder. */
214 /* */
215 /* <InOut> */
216 /* builder :: A pointer to the glyph builder to initialize. */
217 /* */
218 /* <Input> */
219 /* face :: The current face object. */
220 /* */
221 /* size :: The current size object. */
222 /* */
223 /* glyph :: The current glyph object. */
224 /* */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000225 static void
David Turnerb9b2cac2002-07-10 16:52:06 +0000226 cff_builder_init( CFF_Builder* builder,
Werner Lemberg93616ec2001-06-27 19:46:12 +0000227 TT_Face face,
228 CFF_Size size,
David Turnerc8087482001-12-20 13:14:18 +0000229 CFF_GlyphSlot glyph,
230 FT_Bool hinting )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000231 {
232 builder->path_begun = 0;
233 builder->load_points = 1;
234
235 builder->face = face;
236 builder->glyph = glyph;
237 builder->memory = face->root.memory;
238
239 if ( glyph )
240 {
David Turner4d570242002-02-24 02:59:24 +0000241 FT_GlyphLoader loader = glyph->root.internal->loader;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000242
243
244 builder->loader = loader;
245 builder->base = &loader->base.outline;
246 builder->current = &loader->current.outline;
247 FT_GlyphLoader_Rewind( loader );
David Turnerc8087482001-12-20 13:14:18 +0000248
David Turner27c322e2002-07-08 22:26:11 +0000249 builder->hint_flags = FT_FACE(face)->internal->hint_flags;
David Turnerc8087482001-12-20 13:14:18 +0000250 builder->hints_globals = 0;
251 builder->hints_funcs = 0;
David Turner4d570242002-02-24 02:59:24 +0000252
David Turnerc8087482001-12-20 13:14:18 +0000253 if ( hinting && size )
254 {
255 builder->hints_globals = size->internal;
256 builder->hints_funcs = glyph->root.internal->glyph_hints;
257 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000258 }
259
260 if ( size )
261 {
262 builder->scale_x = size->metrics.x_scale;
263 builder->scale_y = size->metrics.y_scale;
264 }
265
266 builder->pos_x = 0;
267 builder->pos_y = 0;
268
269 builder->left_bearing.x = 0;
270 builder->left_bearing.y = 0;
271 builder->advance.x = 0;
272 builder->advance.y = 0;
273 }
274
275
276 /*************************************************************************/
277 /* */
278 /* <Function> */
David Turnerb9b2cac2002-07-10 16:52:06 +0000279 /* cff_builder_done */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000280 /* */
281 /* <Description> */
282 /* Finalizes a given glyph builder. Its contents can still be used */
283 /* after the call, but the function saves important information */
284 /* within the corresponding glyph slot. */
285 /* */
286 /* <Input> */
287 /* builder :: A pointer to the glyph builder to finalize. */
288 /* */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000289 static void
David Turnerb9b2cac2002-07-10 16:52:06 +0000290 cff_builder_done( CFF_Builder* builder )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000291 {
292 CFF_GlyphSlot glyph = builder->glyph;
293
294
295 if ( glyph )
296 glyph->root.outline = *builder->base;
297 }
298
299
300 /*************************************************************************/
301 /* */
302 /* <Function> */
Werner Lembergd573c7e2001-01-03 07:14:12 +0000303 /* cff_compute_bias */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000304 /* */
305 /* <Description> */
306 /* Computes the bias value in dependence of the number of glyph */
307 /* subroutines. */
308 /* */
309 /* <Input> */
310 /* num_subrs :: The number of glyph subroutines. */
311 /* */
312 /* <Return> */
313 /* The bias value. */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000314 static FT_Int
315 cff_compute_bias( FT_UInt num_subrs )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000316 {
317 FT_Int result;
318
319
320 if ( num_subrs < 1240 )
321 result = 107;
Werner Lembergcf24d512001-06-18 14:23:45 +0000322 else if ( num_subrs < 33900U )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000323 result = 1131;
324 else
Werner Lembergcf24d512001-06-18 14:23:45 +0000325 result = 32768U;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000326
327 return result;
328 }
329
330
331 /*************************************************************************/
332 /* */
333 /* <Function> */
David Turnerb9b2cac2002-07-10 16:52:06 +0000334 /* cff_decoder_init */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000335 /* */
336 /* <Description> */
337 /* Initializes a given glyph decoder. */
338 /* */
339 /* <InOut> */
340 /* decoder :: A pointer to the glyph builder to initialize. */
341 /* */
342 /* <Input> */
343 /* face :: The current face object. */
344 /* */
345 /* size :: The current size object. */
346 /* */
347 /* slot :: The current glyph object. */
348 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000349 FT_LOCAL_DEF( void )
David Turnerb9b2cac2002-07-10 16:52:06 +0000350 cff_decoder_init( CFF_Decoder* decoder,
Werner Lemberg93616ec2001-06-27 19:46:12 +0000351 TT_Face face,
352 CFF_Size size,
David Turnerc8087482001-12-20 13:14:18 +0000353 CFF_GlyphSlot slot,
354 FT_Bool hinting )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000355 {
David Turnerab4fc4d2002-03-14 08:57:10 +0000356 CFF_Font cff = (CFF_Font)face->extra.data;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000357
358
359 /* clear everything */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000360 FT_MEM_ZERO( decoder, sizeof ( *decoder ) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000361
362 /* initialize builder */
David Turnerb9b2cac2002-07-10 16:52:06 +0000363 cff_builder_init( &decoder->builder, face, size, slot, hinting );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000364
365 /* initialize Type2 decoder */
366 decoder->num_globals = cff->num_global_subrs;
367 decoder->globals = cff->global_subrs;
368 decoder->globals_bias = cff_compute_bias( decoder->num_globals );
369 }
370
371
372 /* this function is used to select the locals subrs array */
David Turnerbc82f1b2002-03-01 02:26:22 +0000373 FT_LOCAL_DEF( void )
David Turnerb9b2cac2002-07-10 16:52:06 +0000374 cff_decoder_prepare( CFF_Decoder* decoder,
Werner Lemberg93616ec2001-06-27 19:46:12 +0000375 FT_UInt glyph_index )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000376 {
David Turnerab4fc4d2002-03-14 08:57:10 +0000377 CFF_Font cff = (CFF_Font)decoder->builder.face->extra.data;
378 CFF_SubFont sub = &cff->top_font;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000379
380
381 /* manage CID fonts */
382 if ( cff->num_subfonts >= 1 )
383 {
David Turnerb9b2cac2002-07-10 16:52:06 +0000384 FT_Byte fd_index = cff_fd_select_get( &cff->fd_select, glyph_index );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000385
386
387 sub = cff->subfonts[fd_index];
388 }
389
390 decoder->num_locals = sub->num_local_subrs;
391 decoder->locals = sub->local_subrs;
392 decoder->locals_bias = cff_compute_bias( decoder->num_locals );
393
394 decoder->glyph_width = sub->private_dict.default_width;
395 decoder->nominal_width = sub->private_dict.nominal_width;
396 }
397
398
399 /* check that there is enough room for `count' more points */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000400 static FT_Error
401 check_points( CFF_Builder* builder,
402 FT_Int count )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000403 {
David Turnereba5ad42002-03-14 12:56:35 +0000404 return FT_GlyphLoader_CheckPoints( builder->loader, count, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000405 }
406
407
408 /* add a new point, do not check space */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000409 static void
David Turnerb9b2cac2002-07-10 16:52:06 +0000410 cff_builder_add_point( CFF_Builder* builder,
411 FT_Pos x,
412 FT_Pos y,
413 FT_Byte flag )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000414 {
415 FT_Outline* outline = builder->current;
416
417
418 if ( builder->load_points )
419 {
420 FT_Vector* point = outline->points + outline->n_points;
421 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points;
422
423
424 point->x = x >> 16;
425 point->y = y >> 16;
Werner Lemberg8eb03532001-06-19 23:03:41 +0000426 *control = (FT_Byte)( flag ? FT_Curve_Tag_On : FT_Curve_Tag_Cubic );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000427
428 builder->last = *point;
429 }
Werner Lemberg48c984b2002-03-30 16:41:09 +0000430
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000431 outline->n_points++;
432 }
433
434
435 /* check space for a new on-curve point, then add it */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000436 static FT_Error
Werner Lemberg7f74a522002-07-26 09:09:10 +0000437 cff_builder_add_point1( CFF_Builder* builder,
David Turnerb9b2cac2002-07-10 16:52:06 +0000438 FT_Pos x,
439 FT_Pos y )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000440 {
441 FT_Error error;
442
443
444 error = check_points( builder, 1 );
445 if ( !error )
David Turnerb9b2cac2002-07-10 16:52:06 +0000446 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000447
448 return error;
449 }
450
451
452 /* check room for a new contour, then add it */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000453 static FT_Error
David Turnerb9b2cac2002-07-10 16:52:06 +0000454 cff_builder_add_contour( CFF_Builder* builder )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000455 {
456 FT_Outline* outline = builder->current;
457 FT_Error error;
458
459
460 if ( !builder->load_points )
461 {
462 outline->n_contours++;
463 return CFF_Err_Ok;
464 }
465
David Turnereba5ad42002-03-14 12:56:35 +0000466 error = FT_GlyphLoader_CheckPoints( builder->loader, 0, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000467 if ( !error )
468 {
469 if ( outline->n_contours > 0 )
Werner Lemberg8eb03532001-06-19 23:03:41 +0000470 outline->contours[outline->n_contours - 1] =
471 (short)( outline->n_points - 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000472
473 outline->n_contours++;
474 }
475
476 return error;
477 }
478
479
480 /* if a path was begun, add its first on-curve point */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000481 static FT_Error
David Turnerb9b2cac2002-07-10 16:52:06 +0000482 cff_builder_start_point( CFF_Builder* builder,
483 FT_Pos x,
484 FT_Pos y )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000485 {
486 FT_Error error = 0;
487
488
489 /* test whether we are building a new contour */
490 if ( !builder->path_begun )
491 {
492 builder->path_begun = 1;
David Turnerb9b2cac2002-07-10 16:52:06 +0000493 error = cff_builder_add_contour( builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000494 if ( !error )
Werner Lemberg7f74a522002-07-26 09:09:10 +0000495 error = cff_builder_add_point1( builder, x, y );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000496 }
Werner Lemberg48c984b2002-03-30 16:41:09 +0000497
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000498 return error;
499 }
500
501
502 /* close the current contour */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000503 static void
David Turnerb9b2cac2002-07-10 16:52:06 +0000504 cff_builder_close_contour( CFF_Builder* builder )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000505 {
506 FT_Outline* outline = builder->current;
507
Werner Lemberg48c984b2002-03-30 16:41:09 +0000508
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000509 /* XXXX: We must not include the last point in the path if it */
510 /* is located on the first point. */
511 if ( outline->n_points > 1 )
512 {
513 FT_Int first = 0;
514 FT_Vector* p1 = outline->points + first;
515 FT_Vector* p2 = outline->points + outline->n_points - 1;
516 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1;
517
518
519 if ( outline->n_contours > 1 )
520 {
521 first = outline->contours[outline->n_contours - 2] + 1;
522 p1 = outline->points + first;
523 }
524
Werner Lemberg48c984b2002-03-30 16:41:09 +0000525 /* `delete' last point only if it coincides with the first */
526 /* point and if it is not a control point (which can happen). */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000527 if ( p1->x == p2->x && p1->y == p2->y )
528 if ( *control == FT_Curve_Tag_On )
529 outline->n_points--;
530 }
531
532 if ( outline->n_contours > 0 )
Werner Lemberg8eb03532001-06-19 23:03:41 +0000533 outline->contours[outline->n_contours - 1] =
534 (short)( outline->n_points - 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000535 }
536
537
Werner Lemberg93616ec2001-06-27 19:46:12 +0000538 static FT_Int
David Turnerab4fc4d2002-03-14 08:57:10 +0000539 cff_lookup_glyph_by_stdcharcode( CFF_Font cff,
Werner Lemberg48c984b2002-03-30 16:41:09 +0000540 FT_Int charcode )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000541 {
542 FT_UInt n;
543 FT_UShort glyph_sid;
544
545
546 /* check range of standard char code */
547 if ( charcode < 0 || charcode > 255 )
548 return -1;
549
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000550 /* Get code to SID mapping from `cff_standard_encoding'. */
David Turnerb9b2cac2002-07-10 16:52:06 +0000551 glyph_sid = cff_get_standard_encoding( (FT_UInt)charcode );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000552
553 for ( n = 0; n < cff->num_glyphs; n++ )
554 {
555 if ( cff->charset.sids[n] == glyph_sid )
556 return n;
557 }
558
559 return -1;
560 }
561
562
Werner Lemberg93616ec2001-06-27 19:46:12 +0000563 static FT_Error
564 cff_operator_seac( CFF_Decoder* decoder,
565 FT_Pos adx,
566 FT_Pos ady,
567 FT_Int bchar,
568 FT_Int achar )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000569 {
570 FT_Error error;
571 FT_Int bchar_index, achar_index, n_base_points;
572 FT_Outline* base = decoder->builder.base;
573 TT_Face face = decoder->builder.face;
Werner Lemberg48c984b2002-03-30 16:41:09 +0000574 CFF_Font cff = (CFF_Font)(face->extra.data);
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000575 FT_Vector left_bearing, advance;
576 FT_Byte* charstring;
577 FT_ULong charstring_len;
578
579
580 bchar_index = cff_lookup_glyph_by_stdcharcode( cff, bchar );
581 achar_index = cff_lookup_glyph_by_stdcharcode( cff, achar );
582
583 if ( bchar_index < 0 || achar_index < 0 )
584 {
585 FT_ERROR(( "cff_operator_seac:" ));
586 FT_ERROR(( " invalid seac character code arguments\n" ));
587 return CFF_Err_Syntax_Error;
588 }
589
590 /* If we are trying to load a composite glyph, do not load the */
591 /* accent character and return the array of subglyphs. */
592 if ( decoder->builder.no_recurse )
593 {
Werner Lemberg48c984b2002-03-30 16:41:09 +0000594 FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph;
595 FT_GlyphLoader loader = glyph->internal->loader;
David Turnereba5ad42002-03-14 12:56:35 +0000596 FT_SubGlyph subg;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000597
598
599 /* reallocate subglyph array if necessary */
David Turnereba5ad42002-03-14 12:56:35 +0000600 error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000601 if ( error )
602 goto Exit;
603
604 subg = loader->current.subglyphs;
605
606 /* subglyph 0 = base character */
607 subg->index = bchar_index;
608 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES |
609 FT_SUBGLYPH_FLAG_USE_MY_METRICS;
610 subg->arg1 = 0;
611 subg->arg2 = 0;
612 subg++;
613
614 /* subglyph 1 = accent character */
615 subg->index = achar_index;
616 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
617 subg->arg1 = adx;
618 subg->arg2 = ady;
619
620 /* set up remaining glyph fields */
621 glyph->num_subglyphs = 2;
622 glyph->subglyphs = loader->base.subglyphs;
623 glyph->format = ft_glyph_format_composite;
624
625 loader->current.num_subglyphs = 2;
626 }
627
628 /* First load `bchar' in builder */
David Turnerb9b2cac2002-07-10 16:52:06 +0000629 error = cff_index_access_element( &cff->charstrings_index, bchar_index,
Werner Lemberg7f74a522002-07-26 09:09:10 +0000630 &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000631 if ( !error )
632 {
David Turnerb9b2cac2002-07-10 16:52:06 +0000633 error = cff_decoder_parse_charstrings( decoder, charstring, charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000634
635 if ( error )
636 goto Exit;
637
David Turnerb9b2cac2002-07-10 16:52:06 +0000638 cff_index_forget_element( &cff->charstrings_index, &charstring );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000639 }
640
641 n_base_points = base->n_points;
642
643 /* Save the left bearing and width of the base character */
644 /* as they will be erased by the next load. */
645
646 left_bearing = decoder->builder.left_bearing;
647 advance = decoder->builder.advance;
648
649 decoder->builder.left_bearing.x = 0;
650 decoder->builder.left_bearing.y = 0;
651
652 /* Now load `achar' on top of the base outline. */
David Turnerb9b2cac2002-07-10 16:52:06 +0000653 error = cff_index_access_element( &cff->charstrings_index, achar_index,
Werner Lemberg7f74a522002-07-26 09:09:10 +0000654 &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000655 if ( !error )
656 {
David Turnerb9b2cac2002-07-10 16:52:06 +0000657 error = cff_decoder_parse_charstrings( decoder, charstring, charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000658
659 if ( error )
660 goto Exit;
661
David Turnerb9b2cac2002-07-10 16:52:06 +0000662 cff_index_forget_element( &cff->charstrings_index, &charstring );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000663 }
664
665 /* Restore the left side bearing and advance width */
666 /* of the base character. */
667 decoder->builder.left_bearing = left_bearing;
668 decoder->builder.advance = advance;
669
670 /* Finally, move the accent. */
671 if ( decoder->builder.load_points )
672 {
673 FT_Outline dummy;
674
675
Werner Lemberg8eb03532001-06-19 23:03:41 +0000676 dummy.n_points = (short)( base->n_points - n_base_points );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000677 dummy.points = base->points + n_base_points;
678
679 FT_Outline_Translate( &dummy, adx, ady );
680 }
681
682 Exit:
683 return error;
684 }
685
686
687 /*************************************************************************/
688 /* */
689 /* <Function> */
David Turnerb9b2cac2002-07-10 16:52:06 +0000690 /* cff_decoder_parse_charstrings */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000691 /* */
692 /* <Description> */
693 /* Parses a given Type 2 charstrings program. */
694 /* */
695 /* <InOut> */
696 /* decoder :: The current Type 1 decoder. */
697 /* */
698 /* <Input> */
699 /* charstring_base :: The base of the charstring stream. */
700 /* */
701 /* charstring_len :: The length in bytes of the charstring stream. */
702 /* */
703 /* <Return> */
704 /* FreeType error code. 0 means success. */
705 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000706 FT_LOCAL_DEF( FT_Error )
David Turnerb9b2cac2002-07-10 16:52:06 +0000707 cff_decoder_parse_charstrings( CFF_Decoder* decoder,
Werner Lemberg7f74a522002-07-26 09:09:10 +0000708 FT_Byte* charstring_base,
709 FT_Int charstring_len )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000710 {
Werner Lembergd573c7e2001-01-03 07:14:12 +0000711 FT_Error error;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000712 CFF_Decoder_Zone* zone;
Werner Lembergd573c7e2001-01-03 07:14:12 +0000713 FT_Byte* ip;
714 FT_Byte* limit;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000715 CFF_Builder* builder = &decoder->builder;
Werner Lembergd573c7e2001-01-03 07:14:12 +0000716 FT_Pos x, y;
717 FT_Fixed seed;
718 FT_Fixed* stack;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000719
David Turner2b30c172001-12-12 16:07:29 +0000720 T2_Hints_Funcs hinter;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000721
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000722
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000723 /* set default width */
724 decoder->num_hints = 0;
725 decoder->read_width = 1;
726
727 /* compute random seed from stack address of parameter */
728 seed = (FT_Fixed)(char*)&seed ^
729 (FT_Fixed)(char*)&decoder ^
730 (FT_Fixed)(char*)&charstring_base;
731 seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFF;
732 if ( seed == 0 )
733 seed = 0x7384;
734
735 /* initialize the decoder */
736 decoder->top = decoder->stack;
737 decoder->zone = decoder->zones;
738 zone = decoder->zones;
739 stack = decoder->top;
740
David Turner2b30c172001-12-12 16:07:29 +0000741 hinter = (T2_Hints_Funcs) builder->hints_funcs;
742
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000743 builder->path_begun = 0;
744
745 zone->base = charstring_base;
746 limit = zone->limit = charstring_base + charstring_len;
747 ip = zone->cursor = zone->base;
748
Werner Lembergcf24d512001-06-18 14:23:45 +0000749 error = CFF_Err_Ok;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000750
751 x = builder->pos_x;
752 y = builder->pos_y;
753
David Turner2b30c172001-12-12 16:07:29 +0000754 /* begin hints recording session, if any */
755 if ( hinter )
756 hinter->open( hinter->hints );
757
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000758 /* now, execute loop */
759 while ( ip < limit )
760 {
761 CFF_Operator op;
Werner Lembergd573c7e2001-01-03 07:14:12 +0000762 FT_Byte v;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000763
764
765 /********************************************************************/
766 /* */
767 /* Decode operator or operand */
768 /* */
769 v = *ip++;
770 if ( v >= 32 || v == 28 )
771 {
772 FT_Int shift = 16;
773 FT_Int32 val;
774
775
776 /* this is an operand, push it on the stack */
777 if ( v == 28 )
778 {
779 if ( ip + 1 >= limit )
780 goto Syntax_Error;
781 val = (FT_Short)( ( (FT_Short)ip[0] << 8 ) | ip[1] );
782 ip += 2;
783 }
784 else if ( v < 247 )
785 val = (FT_Long)v - 139;
786 else if ( v < 251 )
787 {
788 if ( ip >= limit )
789 goto Syntax_Error;
790 val = ( (FT_Long)v - 247 ) * 256 + *ip++ + 108;
791 }
792 else if ( v < 255 )
793 {
794 if ( ip >= limit )
795 goto Syntax_Error;
796 val = -( (FT_Long)v - 251 ) * 256 - *ip++ - 108;
797 }
798 else
799 {
800 if ( ip + 3 >= limit )
801 goto Syntax_Error;
802 val = ( (FT_Int32)ip[0] << 24 ) |
803 ( (FT_Int32)ip[1] << 16 ) |
804 ( (FT_Int32)ip[2] << 8 ) |
805 ip[3];
806 ip += 4;
807 shift = 0;
808 }
809 if ( decoder->top - stack >= CFF_MAX_OPERANDS )
810 goto Stack_Overflow;
811
812 val <<= shift;
813 *decoder->top++ = val;
814
815#ifdef FT_DEBUG_LEVEL_TRACE
816 if ( !( val & 0xFFFF ) )
817 FT_TRACE4(( " %d", (FT_Int32)( val >> 16 ) ));
818 else
Tom Kacvinsky8316bc52001-03-16 13:35:56 +0000819 FT_TRACE4(( " %.2f", val / 65536.0 ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000820#endif
821
822 }
823 else
824 {
825 FT_Fixed* args = decoder->top;
826 FT_Int num_args = args - decoder->stack;
827 FT_Int req_args;
828
829
830 /* find operator */
831 op = cff_op_unknown;
832
833 switch ( v )
834 {
835 case 1:
836 op = cff_op_hstem;
837 break;
838 case 3:
839 op = cff_op_vstem;
840 break;
841 case 4:
842 op = cff_op_vmoveto;
843 break;
844 case 5:
845 op = cff_op_rlineto;
846 break;
847 case 6:
848 op = cff_op_hlineto;
849 break;
850 case 7:
851 op = cff_op_vlineto;
852 break;
853 case 8:
854 op = cff_op_rrcurveto;
855 break;
856 case 10:
857 op = cff_op_callsubr;
858 break;
859 case 11:
860 op = cff_op_return;
861 break;
862 case 12:
863 {
864 if ( ip >= limit )
865 goto Syntax_Error;
866 v = *ip++;
867
868 switch ( v )
869 {
Tom Kacvinsky8316bc52001-03-16 13:35:56 +0000870 case 0:
871 op = cff_op_dotsection;
872 break;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000873 case 3:
874 op = cff_op_and;
875 break;
876 case 4:
877 op = cff_op_or;
878 break;
879 case 5:
880 op = cff_op_not;
881 break;
882 case 8:
883 op = cff_op_store;
884 break;
885 case 9:
886 op = cff_op_abs;
887 break;
888 case 10:
889 op = cff_op_add;
890 break;
891 case 11:
892 op = cff_op_sub;
893 break;
894 case 12:
895 op = cff_op_div;
896 break;
897 case 13:
898 op = cff_op_load;
899 break;
900 case 14:
901 op = cff_op_neg;
902 break;
903 case 15:
904 op = cff_op_eq;
905 break;
906 case 18:
907 op = cff_op_drop;
908 break;
909 case 20:
910 op = cff_op_put;
911 break;
912 case 21:
913 op = cff_op_get;
914 break;
915 case 22:
916 op = cff_op_ifelse;
917 break;
918 case 23:
919 op = cff_op_random;
920 break;
921 case 24:
922 op = cff_op_mul;
923 break;
924 case 26:
925 op = cff_op_sqrt;
926 break;
927 case 27:
928 op = cff_op_dup;
929 break;
930 case 28:
931 op = cff_op_exch;
932 break;
933 case 29:
934 op = cff_op_index;
935 break;
936 case 30:
937 op = cff_op_roll;
938 break;
939 case 34:
940 op = cff_op_hflex;
941 break;
942 case 35:
943 op = cff_op_flex;
944 break;
945 case 36:
946 op = cff_op_hflex1;
947 break;
948 case 37:
949 op = cff_op_flex1;
950 break;
951 default:
952 /* decrement ip for syntax error message */
953 ip--;
954 }
955 }
956 break;
957 case 14:
958 op = cff_op_endchar;
959 break;
960 case 16:
961 op = cff_op_blend;
962 break;
963 case 18:
964 op = cff_op_hstemhm;
965 break;
966 case 19:
967 op = cff_op_hintmask;
968 break;
969 case 20:
970 op = cff_op_cntrmask;
971 break;
972 case 21:
973 op = cff_op_rmoveto;
974 break;
975 case 22:
976 op = cff_op_hmoveto;
977 break;
978 case 23:
979 op = cff_op_vstemhm;
980 break;
981 case 24:
982 op = cff_op_rcurveline;
983 break;
984 case 25:
985 op = cff_op_rlinecurve;
986 break;
987 case 26:
988 op = cff_op_vvcurveto;
989 break;
990 case 27:
991 op = cff_op_hhcurveto;
992 break;
993 case 29:
994 op = cff_op_callgsubr;
995 break;
996 case 30:
997 op = cff_op_vhcurveto;
998 break;
999 case 31:
1000 op = cff_op_hvcurveto;
1001 break;
1002 default:
1003 ;
1004 }
1005 if ( op == cff_op_unknown )
1006 goto Syntax_Error;
1007
1008 /* check arguments */
1009 req_args = cff_argument_counts[op];
1010 if ( req_args & CFF_COUNT_CHECK_WIDTH )
1011 {
1012 args = stack;
1013
1014 if ( num_args > 0 && decoder->read_width )
1015 {
1016 /* If `nominal_width' is non-zero, the number is really a */
1017 /* difference against `nominal_width'. Else, the number here */
1018 /* is truly a width, not a difference against `nominal_width'. */
1019 /* If the font does not set `nominal_width', then */
1020 /* `nominal_width' defaults to zero, and so we can set */
1021 /* `glyph_width' to `nominal_width' plus number on the stack */
1022 /* -- for either case. */
1023
1024 FT_Int set_width_ok;
1025
1026
1027 switch ( op )
1028 {
1029 case cff_op_hmoveto:
1030 case cff_op_vmoveto:
1031 set_width_ok = num_args & 2;
1032 break;
1033
1034 case cff_op_hstem:
1035 case cff_op_vstem:
1036 case cff_op_hstemhm:
1037 case cff_op_vstemhm:
1038 case cff_op_rmoveto:
1039 set_width_ok = num_args & 1;
1040 break;
1041
1042 case cff_op_endchar:
1043 /* If there is a width specified for endchar, we either have */
1044 /* 1 argument or 5 arguments. We like to argue. */
1045 set_width_ok = ( ( num_args == 5 ) || ( num_args == 1 ) );
1046 break;
1047
1048 default:
1049 set_width_ok = 0;
1050 break;
1051 }
1052
1053 if ( set_width_ok )
1054 {
1055 decoder->glyph_width = decoder->nominal_width +
1056 ( stack[0] >> 16 );
1057
1058 /* Consumed an argument. */
1059 num_args--;
1060 args++;
1061 }
1062 }
1063
1064 decoder->read_width = 0;
1065 req_args = 0;
1066 }
1067
1068 req_args &= 15;
1069 if ( num_args < req_args )
1070 goto Stack_Underflow;
1071 args -= req_args;
1072 num_args -= req_args;
1073
1074 switch ( op )
1075 {
1076 case cff_op_hstem:
1077 case cff_op_vstem:
1078 case cff_op_hstemhm:
1079 case cff_op_vstemhm:
David Turner2b30c172001-12-12 16:07:29 +00001080 /* the number of arguments is always even here */
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001081 FT_TRACE4(( op == cff_op_hstem ? " hstem" :
David Turner2b30c172001-12-12 16:07:29 +00001082 ( op == cff_op_vstem ? " vstem" :
Werner Lemberg5da9dd72001-12-16 08:17:33 +00001083 ( op == cff_op_hstemhm ? " hstemhm" : " vstemhm" ) ) ));
David Turnerbce29862001-12-14 14:52:58 +00001084
David Turner2b30c172001-12-12 16:07:29 +00001085 if ( hinter )
1086 hinter->stems( hinter->hints,
David Turner7c0d2082001-12-21 15:59:43 +00001087 ( op == cff_op_hstem || op == cff_op_hstemhm ),
Werner Lemberg5da9dd72001-12-16 08:17:33 +00001088 num_args / 2,
David Turner2b30c172001-12-12 16:07:29 +00001089 args );
David Turnerbce29862001-12-14 14:52:58 +00001090
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001091 decoder->num_hints += num_args / 2;
1092 args = stack;
1093 break;
David Turnerbce29862001-12-14 14:52:58 +00001094
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001095 case cff_op_hintmask:
1096 case cff_op_cntrmask:
David Turner2b30c172001-12-12 16:07:29 +00001097 FT_TRACE4(( op == cff_op_hintmask ? " hintmask" : " cntrmask" ));
David Turner4d570242002-02-24 02:59:24 +00001098
Werner Lembergaf594e62001-12-22 14:38:40 +00001099 /* implement vstem when needed -- */
David Turnerb5c7de52001-12-21 21:21:13 +00001100 /* the specification doesn't say it, but this also works */
Werner Lembergaf594e62001-12-22 14:38:40 +00001101 /* with the 'cntrmask' operator */
David Turnerb5c7de52001-12-21 21:21:13 +00001102 /* */
David Turnerc8087482001-12-20 13:14:18 +00001103 if ( num_args > 0 )
1104 {
1105 if ( hinter )
1106 hinter->stems( hinter->hints,
David Turner7c0d2082001-12-21 15:59:43 +00001107 0,
David Turnerc8087482001-12-20 13:14:18 +00001108 num_args / 2,
1109 args );
David Turner4d570242002-02-24 02:59:24 +00001110
David Turnerc8087482001-12-20 13:14:18 +00001111 decoder->num_hints += num_args / 2;
1112 }
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001113
David Turner2b30c172001-12-12 16:07:29 +00001114 if ( hinter )
1115 {
1116 if ( op == cff_op_hintmask )
1117 hinter->hintmask( hinter->hints,
1118 builder->current->n_points,
David Turnerc8087482001-12-20 13:14:18 +00001119 decoder->num_hints,
David Turner2b30c172001-12-12 16:07:29 +00001120 ip );
1121 else
1122 hinter->counter( hinter->hints,
David Turnerc8087482001-12-20 13:14:18 +00001123 decoder->num_hints,
David Turner2b30c172001-12-12 16:07:29 +00001124 ip );
1125 }
David Turnerbce29862001-12-14 14:52:58 +00001126
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001127#ifdef FT_DEBUG_LEVEL_TRACE
1128 {
1129 FT_UInt maskbyte;
1130
Werner Lemberg48c984b2002-03-30 16:41:09 +00001131
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001132 FT_TRACE4(( " " ));
1133
Werner Lemberg521a2d72001-03-20 22:58:56 +00001134 for ( maskbyte = 0;
David Turner6d4fbec2001-04-20 08:50:36 +00001135 maskbyte < (FT_UInt)(( decoder->num_hints + 7 ) >> 3);
Werner Lemberg521a2d72001-03-20 22:58:56 +00001136 maskbyte++, ip++ )
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001137 FT_TRACE4(( "%02X", *ip ));
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001138 }
1139#else
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001140 ip += ( decoder->num_hints + 7 ) >> 3;
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001141#endif
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001142 if ( ip >= limit )
1143 goto Syntax_Error;
1144 args = stack;
1145 break;
1146
1147 case cff_op_rmoveto:
1148 FT_TRACE4(( " rmoveto" ));
1149
David Turnerb9b2cac2002-07-10 16:52:06 +00001150 cff_builder_close_contour( builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001151 builder->path_begun = 0;
1152 x += args[0];
1153 y += args[1];
1154 args = stack;
1155 break;
1156
1157 case cff_op_vmoveto:
1158 FT_TRACE4(( " vmoveto" ));
1159
David Turnerb9b2cac2002-07-10 16:52:06 +00001160 cff_builder_close_contour( builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001161 builder->path_begun = 0;
1162 y += args[0];
1163 args = stack;
1164 break;
1165
1166 case cff_op_hmoveto:
1167 FT_TRACE4(( " hmoveto" ));
1168
David Turnerb9b2cac2002-07-10 16:52:06 +00001169 cff_builder_close_contour( builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001170 builder->path_begun = 0;
1171 x += args[0];
1172 args = stack;
1173 break;
1174
1175 case cff_op_rlineto:
1176 FT_TRACE4(( " rlineto" ));
1177
Werner Lemberg7f74a522002-07-26 09:09:10 +00001178 if ( cff_builder_start_point ( builder, x, y ) ||
1179 check_points( builder, num_args / 2 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001180 goto Memory_Error;
1181
1182 if ( num_args < 2 || num_args & 1 )
1183 goto Stack_Underflow;
1184
1185 args = stack;
1186 while ( args < decoder->top )
1187 {
1188 x += args[0];
1189 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001190 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001191 args += 2;
1192 }
1193 args = stack;
1194 break;
1195
1196 case cff_op_hlineto:
1197 case cff_op_vlineto:
1198 {
1199 FT_Int phase = ( op == cff_op_hlineto );
1200
1201
1202 FT_TRACE4(( op == cff_op_hlineto ? " hlineto"
Werner Lembergd573c7e2001-01-03 07:14:12 +00001203 : " vlineto" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001204
David Turnerb9b2cac2002-07-10 16:52:06 +00001205 if ( cff_builder_start_point ( builder, x, y ) ||
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001206 check_points( builder, num_args ) )
1207 goto Memory_Error;
1208
1209 args = stack;
1210 while (args < decoder->top )
1211 {
1212 if ( phase )
1213 x += args[0];
1214 else
1215 y += args[0];
1216
Werner Lemberg7f74a522002-07-26 09:09:10 +00001217 if ( cff_builder_add_point1( builder, x, y ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001218 goto Memory_Error;
1219
1220 args++;
1221 phase ^= 1;
1222 }
1223 args = stack;
1224 }
1225 break;
1226
1227 case cff_op_rrcurveto:
1228 FT_TRACE4(( " rrcurveto" ));
1229
1230 /* check number of arguments; must be a multiple of 6 */
1231 if ( num_args % 6 != 0 )
1232 goto Stack_Underflow;
1233
Werner Lemberg7f74a522002-07-26 09:09:10 +00001234 if ( cff_builder_start_point ( builder, x, y ) ||
1235 check_points( builder, num_args / 2 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001236 goto Memory_Error;
1237
1238 args = stack;
1239 while ( args < decoder->top )
1240 {
1241 x += args[0];
1242 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001243 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001244 x += args[2];
1245 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001246 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001247 x += args[4];
1248 y += args[5];
David Turnerb9b2cac2002-07-10 16:52:06 +00001249 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001250 args += 6;
1251 }
1252 args = stack;
1253 break;
1254
1255 case cff_op_vvcurveto:
1256 FT_TRACE4(( " vvcurveto" ));
1257
David Turnerb9b2cac2002-07-10 16:52:06 +00001258 if ( cff_builder_start_point ( builder, x, y ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001259 goto Memory_Error;
1260
1261 args = stack;
1262 if ( num_args & 1 )
1263 {
1264 x += args[0];
1265 args++;
1266 num_args--;
1267 }
1268
1269 if ( num_args % 4 != 0 )
1270 goto Stack_Underflow;
1271
1272 if ( check_points( builder, 3 * ( num_args / 4 ) ) )
1273 goto Memory_Error;
1274
1275 while ( args < decoder->top )
1276 {
1277 y += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001278 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001279 x += args[1];
1280 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001281 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001282 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001283 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001284 args += 4;
1285 }
1286 args = stack;
1287 break;
1288
1289 case cff_op_hhcurveto:
1290 FT_TRACE4(( " hhcurveto" ));
1291
David Turnerb9b2cac2002-07-10 16:52:06 +00001292 if ( cff_builder_start_point ( builder, x, y ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001293 goto Memory_Error;
1294
1295 args = stack;
1296 if ( num_args & 1 )
1297 {
1298 y += args[0];
1299 args++;
1300 num_args--;
1301 }
1302
1303 if ( num_args % 4 != 0 )
1304 goto Stack_Underflow;
1305
1306 if ( check_points( builder, 3 * ( num_args / 4 ) ) )
1307 goto Memory_Error;
1308
1309 while ( args < decoder->top )
1310 {
1311 x += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001312 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001313 x += args[1];
1314 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001315 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001316 x += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001317 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001318 args += 4;
1319 }
1320 args = stack;
1321 break;
1322
1323 case cff_op_vhcurveto:
1324 case cff_op_hvcurveto:
1325 {
1326 FT_Int phase;
1327
1328
1329 FT_TRACE4(( op == cff_op_vhcurveto ? " vhcurveto"
Werner Lembergd573c7e2001-01-03 07:14:12 +00001330 : " hvcurveto" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001331
David Turnerb9b2cac2002-07-10 16:52:06 +00001332 if ( cff_builder_start_point ( builder, x, y ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001333 goto Memory_Error;
1334
1335 args = stack;
1336 if (num_args < 4 || ( num_args % 4 ) > 1 )
1337 goto Stack_Underflow;
1338
1339 if ( check_points( builder, ( num_args / 4 ) * 3 ) )
1340 goto Stack_Underflow;
1341
1342 phase = ( op == cff_op_hvcurveto );
1343
1344 while ( num_args >= 4 )
1345 {
1346 num_args -= 4;
1347 if ( phase )
1348 {
1349 x += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001350 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001351 x += args[1];
1352 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001353 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001354 y += args[3];
1355 if ( num_args == 1 )
1356 x += args[4];
David Turnerb9b2cac2002-07-10 16:52:06 +00001357 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001358 }
1359 else
1360 {
1361 y += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001362 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001363 x += args[1];
1364 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001365 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001366 x += args[3];
1367 if ( num_args == 1 )
1368 y += args[4];
David Turnerb9b2cac2002-07-10 16:52:06 +00001369 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001370 }
1371 args += 4;
1372 phase ^= 1;
1373 }
1374 args = stack;
1375 }
1376 break;
1377
1378 case cff_op_rlinecurve:
1379 {
1380 FT_Int num_lines = ( num_args - 6 ) / 2;
1381
1382
1383 FT_TRACE4(( " rlinecurve" ));
1384
1385 if ( num_args < 8 || ( num_args - 6 ) & 1 )
1386 goto Stack_Underflow;
1387
Werner Lemberg7f74a522002-07-26 09:09:10 +00001388 if ( cff_builder_start_point( builder, x, y ) ||
1389 check_points( builder, num_lines + 3 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001390 goto Memory_Error;
1391
1392 args = stack;
1393
1394 /* first, add the line segments */
1395 while ( num_lines > 0 )
1396 {
1397 x += args[0];
1398 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001399 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001400 args += 2;
1401 num_lines--;
1402 }
1403
1404 /* then the curve */
1405 x += args[0];
1406 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001407 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001408 x += args[2];
1409 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001410 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001411 x += args[4];
1412 y += args[5];
David Turnerb9b2cac2002-07-10 16:52:06 +00001413 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001414 args = stack;
1415 }
1416 break;
1417
1418 case cff_op_rcurveline:
1419 {
1420 FT_Int num_curves = ( num_args - 2 ) / 6;
1421
1422
1423 FT_TRACE4(( " rcurveline" ));
1424
1425 if ( num_args < 8 || ( num_args - 2 ) % 6 )
1426 goto Stack_Underflow;
1427
Werner Lemberg7f74a522002-07-26 09:09:10 +00001428 if ( cff_builder_start_point ( builder, x, y ) ||
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001429 check_points( builder, num_curves*3 + 2 ) )
1430 goto Memory_Error;
1431
1432 args = stack;
1433
1434 /* first, add the curves */
1435 while ( num_curves > 0 )
1436 {
1437 x += args[0];
1438 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001439 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001440 x += args[2];
1441 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001442 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001443 x += args[4];
1444 y += args[5];
David Turnerb9b2cac2002-07-10 16:52:06 +00001445 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001446 args += 6;
1447 num_curves--;
1448 }
1449
1450 /* then the final line */
1451 x += args[0];
1452 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001453 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001454 args = stack;
1455 }
1456 break;
1457
1458 case cff_op_hflex1:
1459 {
1460 FT_Pos start_y;
1461
1462
1463 FT_TRACE4(( " hflex1" ));
1464
1465 args = stack;
1466
1467 /* adding five more points; 4 control points, 1 on-curve point */
1468 /* make sure we have enough space for the start point if it */
1469 /* needs to be added.. */
David Turnerb9b2cac2002-07-10 16:52:06 +00001470 if ( cff_builder_start_point( builder, x, y ) ||
Werner Lemberg7f74a522002-07-26 09:09:10 +00001471 check_points( builder, 6 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001472 goto Memory_Error;
1473
1474 /* Record the starting point's y postion for later use */
1475 start_y = y;
1476
1477 /* first control point */
1478 x += args[0];
1479 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001480 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001481
1482 /* second control point */
1483 x += args[2];
1484 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001485 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001486
1487 /* join point; on curve, with y-value the same as the last */
1488 /* control point's y-value */
1489 x += args[4];
David Turnerb9b2cac2002-07-10 16:52:06 +00001490 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001491
1492 /* third control point, with y-value the same as the join */
1493 /* point's y-value */
1494 x += args[5];
David Turnerb9b2cac2002-07-10 16:52:06 +00001495 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001496
1497 /* fourth control point */
1498 x += args[6];
1499 y += args[7];
David Turnerb9b2cac2002-07-10 16:52:06 +00001500 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001501
1502 /* ending point, with y-value the same as the start */
1503 x += args[8];
1504 y = start_y;
David Turnerb9b2cac2002-07-10 16:52:06 +00001505 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001506
1507 args = stack;
1508 break;
1509 }
1510
1511 case cff_op_hflex:
1512 {
1513 FT_Pos start_y;
1514
1515
1516 FT_TRACE4(( " hflex" ));
1517
1518 args = stack;
1519
1520 /* adding six more points; 4 control points, 2 on-curve points */
David Turnerb9b2cac2002-07-10 16:52:06 +00001521 if ( cff_builder_start_point( builder, x, y ) ||
Werner Lemberg7f74a522002-07-26 09:09:10 +00001522 check_points ( builder, 6 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001523 goto Memory_Error;
1524
1525 /* record the starting point's y-position for later use */
1526 start_y = y;
1527
1528 /* first control point */
1529 x += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001530 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001531
1532 /* second control point */
1533 x += args[1];
1534 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001535 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001536
1537 /* join point; on curve, with y-value the same as the last */
1538 /* control point's y-value */
1539 x += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001540 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001541
1542 /* third control point, with y-value the same as the join */
1543 /* point's y-value */
1544 x += args[4];
David Turnerb9b2cac2002-07-10 16:52:06 +00001545 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001546
1547 /* fourth control point */
1548 x += args[5];
1549 y = start_y;
David Turnerb9b2cac2002-07-10 16:52:06 +00001550 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001551
1552 /* ending point, with y-value the same as the start point's */
1553 /* y-value -- we don't add this point, though */
1554 x += args[6];
David Turnerb9b2cac2002-07-10 16:52:06 +00001555 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001556
1557 args = stack;
1558 break;
1559 }
1560
1561 case cff_op_flex1:
1562 {
1563 FT_Pos start_x, start_y; /* record start x, y values for alter */
1564 /* use */
1565 FT_Int dx = 0, dy = 0; /* used in horizontal/vertical */
1566 /* algorithm below */
1567 FT_Int horizontal, count;
1568
1569
1570 FT_TRACE4(( " flex1" ));
1571
1572 /* adding six more points; 4 control points, 2 on-curve points */
David Turnerb9b2cac2002-07-10 16:52:06 +00001573 if ( cff_builder_start_point( builder, x, y ) ||
Werner Lemberg7f74a522002-07-26 09:09:10 +00001574 check_points( builder, 6 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001575 goto Memory_Error;
1576
1577 /* record the starting point's x, y postion for later use */
1578 start_x = x;
1579 start_y = y;
1580
1581 /* XXX: figure out whether this is supposed to be a horizontal */
1582 /* or vertical flex; the Type 2 specification is vague... */
1583
1584 args = stack;
1585
1586 /* grab up to the last argument */
1587 for ( count = 5; count > 0; count-- )
1588 {
1589 dx += args[0];
1590 dy += args[1];
1591 args += 2;
1592 }
1593
1594 /* rewind */
1595 args = stack;
1596
1597 if ( dx < 0 ) dx = -dx;
1598 if ( dy < 0 ) dy = -dy;
1599
1600 /* strange test, but here it is... */
1601 horizontal = ( dx > dy );
1602
1603 for ( count = 5; count > 0; count-- )
1604 {
1605 x += args[0];
1606 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001607 cff_builder_add_point( builder, x, y, (FT_Bool)( count == 3 ) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001608 args += 2;
1609 }
1610
1611 /* is last operand an x- or y-delta? */
1612 if ( horizontal )
1613 {
1614 x += args[0];
1615 y = start_y;
1616 }
1617 else
1618 {
1619 x = start_x;
1620 y += args[0];
1621 }
1622
David Turnerb9b2cac2002-07-10 16:52:06 +00001623 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001624
1625 args = stack;
1626 break;
1627 }
1628
1629 case cff_op_flex:
1630 {
1631 FT_UInt count;
1632
1633
1634 FT_TRACE4(( " flex" ));
1635
David Turnerb9b2cac2002-07-10 16:52:06 +00001636 if ( cff_builder_start_point( builder, x, y ) ||
Werner Lemberg7f74a522002-07-26 09:09:10 +00001637 check_points( builder, 6 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001638 goto Memory_Error;
1639
1640 args = stack;
1641 for ( count = 6; count > 0; count-- )
1642 {
1643 x += args[0];
1644 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001645 cff_builder_add_point( builder, x, y,
Werner Lemberg7f74a522002-07-26 09:09:10 +00001646 (FT_Bool)( count == 3 || count == 0 ) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001647 args += 2;
1648 }
1649
1650 args = stack;
1651 }
1652 break;
1653
1654 case cff_op_endchar:
1655 FT_TRACE4(( " endchar" ));
1656
1657 /* We are going to emulate the seac operator. */
1658 if ( num_args == 4 )
1659 {
Werner Lembergd573c7e2001-01-03 07:14:12 +00001660 error = cff_operator_seac( decoder,
1661 args[0] >> 16, args[1] >> 16,
1662 args[2] >> 16, args[3] >> 16 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001663 args += 4;
1664 }
1665
1666 if ( !error )
1667 error = CFF_Err_Ok;
1668
David Turnerb9b2cac2002-07-10 16:52:06 +00001669 cff_builder_close_contour( builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001670
David Turner2b30c172001-12-12 16:07:29 +00001671 /* close hints recording session */
1672 if ( hinter )
1673 {
Werner Lemberg5da9dd72001-12-16 08:17:33 +00001674 if (hinter->close( hinter->hints, builder->current->n_points ) )
David Turner2b30c172001-12-12 16:07:29 +00001675 goto Syntax_Error;
David Turnerbce29862001-12-14 14:52:58 +00001676
David Turner2b30c172001-12-12 16:07:29 +00001677 /* apply hints to the loaded glyph outline now */
1678 hinter->apply( hinter->hints,
1679 builder->current,
David Turner27c322e2002-07-08 22:26:11 +00001680 (PSH_Globals)builder->hints_globals,
1681 builder->hint_flags );
David Turner2b30c172001-12-12 16:07:29 +00001682 }
1683
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001684 /* add current outline to the glyph slot */
1685 FT_GlyphLoader_Add( builder->loader );
1686
1687 /* return now! */
1688 FT_TRACE4(( "\n\n" ));
1689 return error;
1690
1691 case cff_op_abs:
1692 FT_TRACE4(( " abs" ));
1693
1694 if ( args[0] < 0 )
1695 args[0] = -args[0];
1696 args++;
1697 break;
1698
1699 case cff_op_add:
1700 FT_TRACE4(( " add" ));
1701
1702 args[0] += args[1];
1703 args++;
1704 break;
1705
1706 case cff_op_sub:
1707 FT_TRACE4(( " sub" ));
1708
1709 args[0] -= args[1];
1710 args++;
1711 break;
1712
1713 case cff_op_div:
1714 FT_TRACE4(( " div" ));
1715
1716 args[0] = FT_DivFix( args[0], args[1] );
1717 args++;
1718 break;
1719
1720 case cff_op_neg:
1721 FT_TRACE4(( " neg" ));
1722
1723 args[0] = -args[0];
1724 args++;
1725 break;
1726
1727 case cff_op_random:
1728 {
Werner Lemberg94ffae52002-04-14 00:54:32 +00001729 FT_Fixed Rand;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001730
1731
1732 FT_TRACE4(( " rand" ));
1733
Werner Lemberg94ffae52002-04-14 00:54:32 +00001734 Rand = seed;
1735 if ( Rand >= 0x8000 )
1736 Rand++;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001737
Werner Lemberg94ffae52002-04-14 00:54:32 +00001738 args[0] = Rand;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001739 seed = FT_MulFix( seed, 0x10000L - seed );
1740 if ( seed == 0 )
1741 seed += 0x2873;
1742 args++;
1743 }
1744 break;
1745
1746 case cff_op_mul:
1747 FT_TRACE4(( " mul" ));
1748
1749 args[0] = FT_MulFix( args[0], args[1] );
1750 args++;
1751 break;
1752
1753 case cff_op_sqrt:
1754 FT_TRACE4(( " sqrt" ));
1755
1756 if ( args[0] > 0 )
1757 {
1758 FT_Int count = 9;
1759 FT_Fixed root = args[0];
1760 FT_Fixed new_root;
1761
1762
1763 for (;;)
1764 {
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001765 new_root = ( root + FT_DivFix( args[0], root ) + 1 ) >> 1;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001766 if ( new_root == root || count <= 0 )
1767 break;
1768 root = new_root;
1769 }
1770 args[0] = new_root;
1771 }
1772 else
1773 args[0] = 0;
1774 args++;
1775 break;
1776
1777 case cff_op_drop:
1778 /* nothing */
1779 FT_TRACE4(( " drop" ));
1780
1781 break;
1782
1783 case cff_op_exch:
1784 {
1785 FT_Fixed tmp;
1786
1787
1788 FT_TRACE4(( " exch" ));
1789
1790 tmp = args[0];
1791 args[0] = args[1];
1792 args[1] = tmp;
1793 args += 2;
1794 }
1795 break;
1796
1797 case cff_op_index:
1798 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001799 FT_Int idx = args[0] >> 16;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001800
1801
1802 FT_TRACE4(( " index" ));
1803
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001804 if ( idx < 0 )
1805 idx = 0;
1806 else if ( idx > num_args - 2 )
1807 idx = num_args - 2;
1808 args[0] = args[-( idx + 1 )];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001809 args++;
1810 }
1811 break;
1812
1813 case cff_op_roll:
1814 {
1815 FT_Int count = (FT_Int)( args[0] >> 16 );
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001816 FT_Int idx = (FT_Int)( args[1] >> 16 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001817
1818
1819 FT_TRACE4(( " roll" ));
1820
1821 if ( count <= 0 )
1822 count = 1;
1823
1824 args -= count;
1825 if ( args < stack )
1826 goto Stack_Underflow;
1827
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001828 if ( idx >= 0 )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001829 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001830 while ( idx > 0 )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001831 {
1832 FT_Fixed tmp = args[count - 1];
1833 FT_Int i;
1834
1835
1836 for ( i = count - 2; i >= 0; i-- )
1837 args[i + 1] = args[i];
1838 args[0] = tmp;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001839 idx--;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001840 }
1841 }
1842 else
1843 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001844 while ( idx < 0 )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001845 {
1846 FT_Fixed tmp = args[0];
1847 FT_Int i;
1848
1849
1850 for ( i = 0; i < count - 1; i++ )
1851 args[i] = args[i + 1];
1852 args[count - 1] = tmp;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001853 idx++;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001854 }
1855 }
1856 args += count;
1857 }
1858 break;
1859
1860 case cff_op_dup:
1861 FT_TRACE4(( " dup" ));
1862
1863 args[1] = args[0];
1864 args++;
1865 break;
1866
1867 case cff_op_put:
1868 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001869 FT_Fixed val = args[0];
1870 FT_Int idx = (FT_Int)( args[1] >> 16 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001871
1872
1873 FT_TRACE4(( " put" ));
1874
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001875 if ( idx >= 0 && idx < decoder->len_buildchar )
1876 decoder->buildchar[idx] = val;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001877 }
1878 break;
1879
1880 case cff_op_get:
1881 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001882 FT_Int idx = (FT_Int)( args[0] >> 16 );
1883 FT_Fixed val = 0;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001884
1885
1886 FT_TRACE4(( " get" ));
1887
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001888 if ( idx >= 0 && idx < decoder->len_buildchar )
1889 val = decoder->buildchar[idx];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001890
1891 args[0] = val;
1892 args++;
1893 }
1894 break;
1895
1896 case cff_op_store:
1897 FT_TRACE4(( " store "));
1898
1899 goto Unimplemented;
1900
1901 case cff_op_load:
1902 FT_TRACE4(( " load" ));
1903
1904 goto Unimplemented;
1905
David Turner8d3a4012001-03-20 11:14:24 +00001906 case cff_op_dotsection:
Werner Lemberg521a2d72001-03-20 22:58:56 +00001907 /* this operator is deprecated and ignored by the parser */
1908 FT_TRACE4(( " dotsection" ));
David Turner8d3a4012001-03-20 11:14:24 +00001909 break;
1910
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001911 case cff_op_and:
1912 {
1913 FT_Fixed cond = args[0] && args[1];
1914
1915
1916 FT_TRACE4(( " and" ));
1917
1918 args[0] = cond ? 0x10000L : 0;
1919 args++;
1920 }
1921 break;
1922
1923 case cff_op_or:
1924 {
1925 FT_Fixed cond = args[0] || args[1];
1926
1927
1928 FT_TRACE4(( " or" ));
1929
1930 args[0] = cond ? 0x10000L : 0;
1931 args++;
1932 }
1933 break;
1934
1935 case cff_op_eq:
1936 {
1937 FT_Fixed cond = !args[0];
1938
1939
1940 FT_TRACE4(( " eq" ));
1941
1942 args[0] = cond ? 0x10000L : 0;
1943 args++;
1944 }
1945 break;
1946
1947 case cff_op_ifelse:
1948 {
1949 FT_Fixed cond = (args[2] <= args[3]);
1950
1951
1952 FT_TRACE4(( " ifelse" ));
1953
1954 if ( !cond )
1955 args[0] = args[1];
1956 args++;
1957 }
1958 break;
1959
1960 case cff_op_callsubr:
1961 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001962 FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) +
1963 decoder->locals_bias );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001964
1965
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001966 FT_TRACE4(( " callsubr(%d)", idx ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001967
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001968 if ( idx >= decoder->num_locals )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001969 {
David Turnerb9b2cac2002-07-10 16:52:06 +00001970 FT_ERROR(( "cff_decoder_parse_charstrings:" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001971 FT_ERROR(( " invalid local subr index\n" ));
1972 goto Syntax_Error;
1973 }
1974
1975 if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
1976 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00001977 FT_ERROR(( "cff_decoder_parse_charstrings:"
1978 " too many nested subrs\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001979 goto Syntax_Error;
1980 }
1981
1982 zone->cursor = ip; /* save current instruction pointer */
1983
1984 zone++;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001985 zone->base = decoder->locals[idx];
1986 zone->limit = decoder->locals[idx + 1];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001987 zone->cursor = zone->base;
1988
1989 if ( !zone->base )
1990 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00001991 FT_ERROR(( "cff_decoder_parse_charstrings:"
1992 " invoking empty subrs!\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001993 goto Syntax_Error;
1994 }
1995
1996 decoder->zone = zone;
1997 ip = zone->base;
1998 limit = zone->limit;
1999 }
2000 break;
2001
2002 case cff_op_callgsubr:
2003 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002004 FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) +
2005 decoder->globals_bias );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002006
2007
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002008 FT_TRACE4(( " callgsubr(%d)", idx ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002009
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002010 if ( idx >= decoder->num_globals )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002011 {
David Turnerb9b2cac2002-07-10 16:52:06 +00002012 FT_ERROR(( "cff_decoder_parse_charstrings:" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002013 FT_ERROR(( " invalid global subr index\n" ));
2014 goto Syntax_Error;
2015 }
2016
2017 if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
2018 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002019 FT_ERROR(( "cff_decoder_parse_charstrings:"
2020 " too many nested subrs\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002021 goto Syntax_Error;
2022 }
2023
2024 zone->cursor = ip; /* save current instruction pointer */
2025
2026 zone++;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002027 zone->base = decoder->globals[idx];
2028 zone->limit = decoder->globals[idx + 1];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002029 zone->cursor = zone->base;
2030
2031 if ( !zone->base )
2032 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002033 FT_ERROR(( "cff_decoder_parse_charstrings:"
2034 " invoking empty subrs!\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002035 goto Syntax_Error;
2036 }
2037
2038 decoder->zone = zone;
2039 ip = zone->base;
2040 limit = zone->limit;
2041 }
2042 break;
2043
2044 case cff_op_return:
2045 FT_TRACE4(( " return" ));
2046
2047 if ( decoder->zone <= decoder->zones )
2048 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002049 FT_ERROR(( "cff_decoder_parse_charstrings:"
2050 " unexpected return\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002051 goto Syntax_Error;
2052 }
2053
2054 decoder->zone--;
2055 zone = decoder->zone;
2056 ip = zone->cursor;
2057 limit = zone->limit;
2058 break;
2059
2060 default:
2061 Unimplemented:
2062 FT_ERROR(( "Unimplemented opcode: %d", ip[-1] ));
2063
2064 if ( ip[-1] == 12 )
2065 FT_ERROR(( " %d", ip[0] ));
2066 FT_ERROR(( "\n" ));
2067
2068 return CFF_Err_Unimplemented_Feature;
2069 }
2070
2071 decoder->top = args;
2072
2073 } /* general operator processing */
2074
2075 } /* while ip < limit */
2076
2077 FT_TRACE4(( "..end..\n\n" ));
2078
2079 return error;
2080
2081 Syntax_Error:
David Turnerb9b2cac2002-07-10 16:52:06 +00002082 FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error!" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002083 return CFF_Err_Invalid_File_Format;
2084
2085 Stack_Underflow:
David Turnerb9b2cac2002-07-10 16:52:06 +00002086 FT_TRACE4(( "cff_decoder_parse_charstrings: stack underflow!" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002087 return CFF_Err_Too_Few_Arguments;
2088
2089 Stack_Overflow:
David Turnerb9b2cac2002-07-10 16:52:06 +00002090 FT_TRACE4(( "cff_decoder_parse_charstrings: stack overflow!" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002091 return CFF_Err_Stack_Overflow;
2092
2093 Memory_Error:
2094 return builder->error;
2095 }
2096
2097
2098 /*************************************************************************/
2099 /*************************************************************************/
2100 /*************************************************************************/
2101 /********** *********/
2102 /********** *********/
2103 /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
2104 /********** *********/
2105 /********** The following code is in charge of computing *********/
2106 /********** the maximum advance width of the font. It *********/
2107 /********** quickly processes each glyph charstring to *********/
2108 /********** extract the value from either a `sbw' or `seac' *********/
2109 /********** operator. *********/
2110 /********** *********/
2111 /*************************************************************************/
2112 /*************************************************************************/
2113 /*************************************************************************/
2114
2115
2116#if 0 /* unused until we support pure CFF fonts */
2117
2118
David Turnerbc82f1b2002-03-01 02:26:22 +00002119 FT_LOCAL_DEF( FT_Error )
David Turnerb9b2cac2002-07-10 16:52:06 +00002120 cff_compute_max_advance( TT_Face face,
Werner Lemberg93616ec2001-06-27 19:46:12 +00002121 FT_Int* max_advance )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002122 {
Werner Lembergd573c7e2001-01-03 07:14:12 +00002123 FT_Error error = 0;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002124 CFF_Decoder decoder;
Werner Lembergd573c7e2001-01-03 07:14:12 +00002125 FT_Int glyph_index;
Werner Lemberg48c984b2002-03-30 16:41:09 +00002126 CFF_Font cff = (CFF_Font)face->other;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002127
2128
2129 *max_advance = 0;
2130
2131 /* Initialize load decoder */
David Turnerb9b2cac2002-07-10 16:52:06 +00002132 cff_decoder_init( &decoder, face, 0, 0, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002133
2134 decoder.builder.metrics_only = 1;
2135 decoder.builder.load_points = 0;
2136
2137 /* For each glyph, parse the glyph charstring and extract */
2138 /* the advance width. */
2139 for ( glyph_index = 0; glyph_index < face->root.num_glyphs;
2140 glyph_index++ )
2141 {
2142 FT_Byte* charstring;
2143 FT_ULong charstring_len;
2144
2145
2146 /* now get load the unscaled outline */
David Turnerb9b2cac2002-07-10 16:52:06 +00002147 error = cff_index_access_element( &cff->charstrings_index, glyph_index,
Werner Lemberg7f74a522002-07-26 09:09:10 +00002148 &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002149 if ( !error )
2150 {
David Turnerb9b2cac2002-07-10 16:52:06 +00002151 cff_decoder_prepare( &decoder, glyph_index );
Werner Lemberg7f74a522002-07-26 09:09:10 +00002152 error = cff_decoder_parse_charstrings( &decoder,
2153 charstring, charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002154
David Turnerb9b2cac2002-07-10 16:52:06 +00002155 cff_index_forget_element( &cff->charstrings_index, &charstring );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002156 }
2157
2158 /* ignore the error if one has occurred -- skip to next glyph */
2159 error = 0;
2160 }
2161
2162 *max_advance = decoder.builder.advance.x;
2163
2164 return CFF_Err_Ok;
2165 }
2166
2167
2168#endif /* 0 */
2169
2170
2171 /*************************************************************************/
2172 /*************************************************************************/
2173 /*************************************************************************/
2174 /********** *********/
2175 /********** *********/
2176 /********** UNHINTED GLYPH LOADER *********/
2177 /********** *********/
2178 /********** The following code is in charge of loading a *********/
2179 /********** single outline. It completely ignores hinting *********/
2180 /********** and is used when FT_LOAD_NO_HINTING is set. *********/
2181 /********** *********/
2182 /*************************************************************************/
2183 /*************************************************************************/
2184 /*************************************************************************/
2185
2186
David Turnerbc82f1b2002-03-01 02:26:22 +00002187 FT_LOCAL_DEF( FT_Error )
David Turnerb9b2cac2002-07-10 16:52:06 +00002188 cff_slot_load( CFF_GlyphSlot glyph,
2189 CFF_Size size,
2190 FT_Int glyph_index,
2191 FT_Int load_flags )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002192 {
Werner Lembergd573c7e2001-01-03 07:14:12 +00002193 FT_Error error;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002194 CFF_Decoder decoder;
Werner Lembergd573c7e2001-01-03 07:14:12 +00002195 TT_Face face = (TT_Face)glyph->root.face;
2196 FT_Bool hinting;
Werner Lemberg48c984b2002-03-30 16:41:09 +00002197 CFF_Font cff = (CFF_Font)face->extra.data;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002198
Werner Lembergd573c7e2001-01-03 07:14:12 +00002199 FT_Matrix font_matrix;
2200 FT_Vector font_offset;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002201
2202
2203 if ( load_flags & FT_LOAD_NO_RECURSE )
2204 load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
2205
2206 glyph->x_scale = 0x10000L;
2207 glyph->y_scale = 0x10000L;
2208 if ( size )
2209 {
2210 glyph->x_scale = size->metrics.x_scale;
2211 glyph->y_scale = size->metrics.y_scale;
2212 }
2213
2214 glyph->root.outline.n_points = 0;
2215 glyph->root.outline.n_contours = 0;
2216
David Turner8edbcab2001-06-19 08:28:24 +00002217 hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 &&
2218 ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002219
2220 glyph->root.format = ft_glyph_format_outline; /* by default */
2221
2222 {
2223 FT_Byte* charstring;
2224 FT_ULong charstring_len;
2225
2226
David Turnerb9b2cac2002-07-10 16:52:06 +00002227 cff_decoder_init( &decoder, face, size, glyph, hinting );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002228
2229 decoder.builder.no_recurse =
2230 (FT_Bool)( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 );
2231
2232 /* now load the unscaled outline */
David Turnerb9b2cac2002-07-10 16:52:06 +00002233 error = cff_index_access_element( &cff->charstrings_index, glyph_index,
Werner Lemberg7f74a522002-07-26 09:09:10 +00002234 &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002235 if ( !error )
2236 {
David Turner29644172002-02-28 18:59:37 +00002237 CFF_IndexRec csindex = cff->charstrings_index;
Tom Kacvinskye20035a2001-03-05 16:22:25 +00002238
Werner Lemberg2e35c9b2001-03-06 13:56:42 +00002239
David Turnerb9b2cac2002-07-10 16:52:06 +00002240 cff_decoder_prepare( &decoder, glyph_index );
Werner Lemberg7f74a522002-07-26 09:09:10 +00002241 error = cff_decoder_parse_charstrings( &decoder,
2242 charstring, charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002243
David Turnerb9b2cac2002-07-10 16:52:06 +00002244 cff_index_forget_element( &cff->charstrings_index, &charstring );
Tom Kacvinskye20035a2001-03-05 16:22:25 +00002245
2246 /* We set control_data and control_len if charstrings is loaded. */
Werner Lemberg7f74a522002-07-26 09:09:10 +00002247 /* See how charstring loads at cff_index_access_element() in */
2248 /* cffload.c. */
Tom Kacvinskye20035a2001-03-05 16:22:25 +00002249
Werner Lemberg2e35c9b2001-03-06 13:56:42 +00002250 glyph->root.control_data =
2251 csindex.bytes + csindex.offsets[glyph_index] - 1;
2252 glyph->root.control_len =
2253 charstring_len;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002254 }
2255
2256 /* save new glyph tables */
David Turnerb9b2cac2002-07-10 16:52:06 +00002257 cff_builder_done( &decoder.builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002258 }
2259
2260 font_matrix = cff->top_font.font_dict.font_matrix;
2261 font_offset = cff->top_font.font_dict.font_offset;
2262
2263 /* Now, set the metrics -- this is rather simple, as */
2264 /* the left side bearing is the xMin, and the top side */
2265 /* bearing the yMax. */
2266 if ( !error )
2267 {
2268 /* For composite glyphs, return only left side bearing and */
2269 /* advance width. */
2270 if ( load_flags & FT_LOAD_NO_RECURSE )
2271 {
2272 FT_Slot_Internal internal = glyph->root.internal;
Werner Lemberg415235d2001-06-28 17:49:10 +00002273
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002274
2275 glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
2276 glyph->root.metrics.horiAdvance = decoder.glyph_width;
2277 internal->glyph_matrix = font_matrix;
2278 internal->glyph_delta = font_offset;
2279 internal->glyph_transformed = 1;
2280 }
2281 else
2282 {
2283 FT_BBox cbox;
2284 FT_Glyph_Metrics* metrics = &glyph->root.metrics;
2285
2286
2287 /* copy the _unscaled_ advance width */
2288 metrics->horiAdvance = decoder.glyph_width;
2289 glyph->root.linearHoriAdvance = decoder.glyph_width;
2290 glyph->root.internal->glyph_transformed = 0;
2291
2292 /* make up vertical metrics */
2293 metrics->vertBearingX = 0;
2294 metrics->vertBearingY = 0;
2295 metrics->vertAdvance = 0;
2296
2297 glyph->root.linearVertAdvance = 0;
2298
2299 glyph->root.format = ft_glyph_format_outline;
2300
2301 glyph->root.outline.flags = 0;
2302 if ( size && size->metrics.y_ppem < 24 )
2303 glyph->root.outline.flags |= ft_outline_high_precision;
2304
2305 glyph->root.outline.flags |= ft_outline_reverse_fill;
2306
2307 /* apply the font matrix */
2308 FT_Outline_Transform( &glyph->root.outline, &font_matrix );
2309
2310 FT_Outline_Translate( &glyph->root.outline,
2311 font_offset.x,
2312 font_offset.y );
2313
2314 if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 )
2315 {
2316 /* scale the outline and the metrics */
2317 FT_Int n;
2318 FT_Outline* cur = &glyph->root.outline;
2319 FT_Vector* vec = cur->points;
2320 FT_Fixed x_scale = glyph->x_scale;
2321 FT_Fixed y_scale = glyph->y_scale;
2322
2323
2324 /* First of all, scale the points */
David Turnerc8087482001-12-20 13:14:18 +00002325 if ( !hinting )
2326 for ( n = cur->n_points; n > 0; n--, vec++ )
2327 {
2328 vec->x = FT_MulFix( vec->x, x_scale );
2329 vec->y = FT_MulFix( vec->y, y_scale );
2330 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002331
2332 FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
2333
2334 /* Then scale the metrics */
2335 metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
2336 metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
2337
2338 metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale );
2339 metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale );
David Turnerbce29862001-12-14 14:52:58 +00002340
2341 if ( hinting )
2342 {
Werner Lemberg48c984b2002-03-30 16:41:09 +00002343 metrics->horiAdvance = ( metrics->horiAdvance + 32 ) & -64;
2344 metrics->vertAdvance = ( metrics->vertAdvance + 32 ) & -64;
David Turnerbce29862001-12-14 14:52:58 +00002345
Werner Lemberg5da9dd72001-12-16 08:17:33 +00002346 metrics->vertBearingX = ( metrics->vertBearingX + 32 ) & -64;
2347 metrics->vertBearingY = ( metrics->vertBearingY + 32 ) & -64;
David Turnerbce29862001-12-14 14:52:58 +00002348 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002349 }
2350
2351 /* compute the other metrics */
2352 FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
2353
2354 /* grid fit the bounding box if necessary */
2355 if ( hinting )
2356 {
2357 cbox.xMin &= -64;
2358 cbox.yMin &= -64;
2359 cbox.xMax = ( cbox.xMax + 63 ) & -64;
2360 cbox.yMax = ( cbox.yMax + 63 ) & -64;
2361 }
2362
2363 metrics->width = cbox.xMax - cbox.xMin;
2364 metrics->height = cbox.yMax - cbox.yMin;
2365
2366 metrics->horiBearingX = cbox.xMin;
2367 metrics->horiBearingY = cbox.yMax;
2368 }
2369 }
2370
2371 return error;
2372 }
2373
2374
2375/* END */