blob: 69277ae59e37f358dbce7381fa5db2f5fbcc49db [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 Turnerd1245c02002-08-27 22:34:20 +0000350 cff_decoder_init( CFF_Decoder* decoder,
351 TT_Face face,
352 CFF_Size size,
353 CFF_GlyphSlot slot,
354 FT_Bool hinting,
355 FT_Render_Mode hint_mode )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000356 {
David Turnerab4fc4d2002-03-14 08:57:10 +0000357 CFF_Font cff = (CFF_Font)face->extra.data;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000358
359
360 /* clear everything */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000361 FT_MEM_ZERO( decoder, sizeof ( *decoder ) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000362
363 /* initialize builder */
David Turnerb9b2cac2002-07-10 16:52:06 +0000364 cff_builder_init( &decoder->builder, face, size, slot, hinting );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000365
366 /* initialize Type2 decoder */
367 decoder->num_globals = cff->num_global_subrs;
368 decoder->globals = cff->global_subrs;
369 decoder->globals_bias = cff_compute_bias( decoder->num_globals );
David Turnerd1245c02002-08-27 22:34:20 +0000370
371 decoder->hint_mode = hint_mode;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000372 }
373
374
375 /* this function is used to select the locals subrs array */
David Turnerbc82f1b2002-03-01 02:26:22 +0000376 FT_LOCAL_DEF( void )
David Turnerb9b2cac2002-07-10 16:52:06 +0000377 cff_decoder_prepare( CFF_Decoder* decoder,
Werner Lemberg93616ec2001-06-27 19:46:12 +0000378 FT_UInt glyph_index )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000379 {
David Turnerab4fc4d2002-03-14 08:57:10 +0000380 CFF_Font cff = (CFF_Font)decoder->builder.face->extra.data;
381 CFF_SubFont sub = &cff->top_font;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000382
383
384 /* manage CID fonts */
385 if ( cff->num_subfonts >= 1 )
386 {
David Turnerb9b2cac2002-07-10 16:52:06 +0000387 FT_Byte fd_index = cff_fd_select_get( &cff->fd_select, glyph_index );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000388
389
390 sub = cff->subfonts[fd_index];
391 }
392
393 decoder->num_locals = sub->num_local_subrs;
394 decoder->locals = sub->local_subrs;
395 decoder->locals_bias = cff_compute_bias( decoder->num_locals );
396
397 decoder->glyph_width = sub->private_dict.default_width;
398 decoder->nominal_width = sub->private_dict.nominal_width;
399 }
400
401
402 /* check that there is enough room for `count' more points */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000403 static FT_Error
404 check_points( CFF_Builder* builder,
405 FT_Int count )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000406 {
David Turnereba5ad42002-03-14 12:56:35 +0000407 return FT_GlyphLoader_CheckPoints( builder->loader, count, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000408 }
409
410
411 /* add a new point, do not check space */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000412 static void
David Turnerb9b2cac2002-07-10 16:52:06 +0000413 cff_builder_add_point( CFF_Builder* builder,
414 FT_Pos x,
415 FT_Pos y,
416 FT_Byte flag )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000417 {
418 FT_Outline* outline = builder->current;
419
420
421 if ( builder->load_points )
422 {
423 FT_Vector* point = outline->points + outline->n_points;
424 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points;
425
426
427 point->x = x >> 16;
428 point->y = y >> 16;
David Turnerb08fe2d2002-08-27 20:20:29 +0000429 *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000430
431 builder->last = *point;
432 }
Werner Lemberg48c984b2002-03-30 16:41:09 +0000433
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000434 outline->n_points++;
435 }
436
437
438 /* check space for a new on-curve point, then add it */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000439 static FT_Error
Werner Lemberg7f74a522002-07-26 09:09:10 +0000440 cff_builder_add_point1( CFF_Builder* builder,
David Turnerb9b2cac2002-07-10 16:52:06 +0000441 FT_Pos x,
442 FT_Pos y )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000443 {
444 FT_Error error;
445
446
447 error = check_points( builder, 1 );
448 if ( !error )
David Turnerb9b2cac2002-07-10 16:52:06 +0000449 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000450
451 return error;
452 }
453
454
455 /* check room for a new contour, then add it */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000456 static FT_Error
David Turnerb9b2cac2002-07-10 16:52:06 +0000457 cff_builder_add_contour( CFF_Builder* builder )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000458 {
459 FT_Outline* outline = builder->current;
460 FT_Error error;
461
462
463 if ( !builder->load_points )
464 {
465 outline->n_contours++;
466 return CFF_Err_Ok;
467 }
468
David Turnereba5ad42002-03-14 12:56:35 +0000469 error = FT_GlyphLoader_CheckPoints( builder->loader, 0, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000470 if ( !error )
471 {
472 if ( outline->n_contours > 0 )
Werner Lemberg8eb03532001-06-19 23:03:41 +0000473 outline->contours[outline->n_contours - 1] =
474 (short)( outline->n_points - 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000475
476 outline->n_contours++;
477 }
478
479 return error;
480 }
481
482
483 /* if a path was begun, add its first on-curve point */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000484 static FT_Error
David Turnerb9b2cac2002-07-10 16:52:06 +0000485 cff_builder_start_point( CFF_Builder* builder,
486 FT_Pos x,
487 FT_Pos y )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000488 {
489 FT_Error error = 0;
490
491
492 /* test whether we are building a new contour */
493 if ( !builder->path_begun )
494 {
495 builder->path_begun = 1;
David Turnerb9b2cac2002-07-10 16:52:06 +0000496 error = cff_builder_add_contour( builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000497 if ( !error )
Werner Lemberg7f74a522002-07-26 09:09:10 +0000498 error = cff_builder_add_point1( builder, x, y );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000499 }
Werner Lemberg48c984b2002-03-30 16:41:09 +0000500
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000501 return error;
502 }
503
504
505 /* close the current contour */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000506 static void
David Turnerb9b2cac2002-07-10 16:52:06 +0000507 cff_builder_close_contour( CFF_Builder* builder )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000508 {
509 FT_Outline* outline = builder->current;
510
Werner Lemberg48c984b2002-03-30 16:41:09 +0000511
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000512 /* XXXX: We must not include the last point in the path if it */
513 /* is located on the first point. */
514 if ( outline->n_points > 1 )
515 {
516 FT_Int first = 0;
517 FT_Vector* p1 = outline->points + first;
518 FT_Vector* p2 = outline->points + outline->n_points - 1;
519 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1;
520
521
522 if ( outline->n_contours > 1 )
523 {
524 first = outline->contours[outline->n_contours - 2] + 1;
525 p1 = outline->points + first;
526 }
527
Werner Lemberg48c984b2002-03-30 16:41:09 +0000528 /* `delete' last point only if it coincides with the first */
529 /* point and if it is not a control point (which can happen). */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000530 if ( p1->x == p2->x && p1->y == p2->y )
David Turnerb08fe2d2002-08-27 20:20:29 +0000531 if ( *control == FT_CURVE_TAG_ON )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000532 outline->n_points--;
533 }
534
535 if ( outline->n_contours > 0 )
Werner Lemberg8eb03532001-06-19 23:03:41 +0000536 outline->contours[outline->n_contours - 1] =
537 (short)( outline->n_points - 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000538 }
539
540
Werner Lemberg93616ec2001-06-27 19:46:12 +0000541 static FT_Int
David Turnerab4fc4d2002-03-14 08:57:10 +0000542 cff_lookup_glyph_by_stdcharcode( CFF_Font cff,
Werner Lemberg48c984b2002-03-30 16:41:09 +0000543 FT_Int charcode )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000544 {
545 FT_UInt n;
546 FT_UShort glyph_sid;
547
548
549 /* check range of standard char code */
550 if ( charcode < 0 || charcode > 255 )
551 return -1;
552
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000553 /* Get code to SID mapping from `cff_standard_encoding'. */
David Turnerb9b2cac2002-07-10 16:52:06 +0000554 glyph_sid = cff_get_standard_encoding( (FT_UInt)charcode );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000555
556 for ( n = 0; n < cff->num_glyphs; n++ )
557 {
558 if ( cff->charset.sids[n] == glyph_sid )
559 return n;
560 }
561
562 return -1;
563 }
564
565
Werner Lemberg93616ec2001-06-27 19:46:12 +0000566 static FT_Error
Graham Asher3fd12f12002-08-15 12:10:48 +0000567 cff_get_glyph_data( TT_Face face,
568 FT_UInt glyph_index,
569 FT_Byte** pointer,
570 FT_ULong* length )
571 {
572#ifdef FT_CONFIG_OPTION_INCREMENTAL
573 /* For incremental fonts get the character data using the */
574 /* callback function. */
575 if ( face->root.internal->incremental_interface )
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000576 {
577 FT_Data data;
578 FT_Error error =
579 face->root.internal->incremental_interface->funcs->get_glyph_data(
580 face->root.internal->incremental_interface->object,
581 glyph_index, &data );
582
583
Graham Asher3fd12f12002-08-15 12:10:48 +0000584 *pointer = (FT_Byte*)data.pointer;
Graham Asher9eefed12002-08-23 10:08:38 +0000585 *length = data.length;
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000586
Graham Asher3fd12f12002-08-15 12:10:48 +0000587 return error;
588 }
589 else
Werner Lembergf25ce9d2002-08-15 23:07:18 +0000590#endif /* FT_CONFIG_OPTION_INCREMENTAL */
Graham Asher3fd12f12002-08-15 12:10:48 +0000591
592 {
Graham Asher9eefed12002-08-23 10:08:38 +0000593 CFF_Font cff = (CFF_Font)(face->extra.data);
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000594
595
Graham Asher3fd12f12002-08-15 12:10:48 +0000596 return cff_index_access_element( &cff->charstrings_index, glyph_index,
597 pointer, length );
598 }
599 }
600
601
602 static void
603 cff_free_glyph_data( TT_Face face,
604 FT_Byte** pointer,
605 FT_ULong length )
606 {
Graham Asher824daa52002-08-15 12:58:21 +0000607#ifndef FT_CONFIG_OPTION_INCREMENTAL
Werner Lembergf25ce9d2002-08-15 23:07:18 +0000608 FT_UNUSED( length );
Graham Asher824daa52002-08-15 12:58:21 +0000609#endif
610
Graham Asher3fd12f12002-08-15 12:10:48 +0000611#ifdef FT_CONFIG_OPTION_INCREMENTAL
612 /* For incremental fonts get the character data using the */
613 /* callback function. */
614 if ( face->root.internal->incremental_interface )
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000615 {
Graham Asher9eefed12002-08-23 10:08:38 +0000616 FT_Data data;
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000617
618
619 data.pointer = *pointer;
620 data.length = length;
621
Graham Asher3fd12f12002-08-15 12:10:48 +0000622 face->root.internal->incremental_interface->funcs->free_glyph_data(
623 face->root.internal->incremental_interface->object,&data );
624 }
625 else
Werner Lembergf25ce9d2002-08-15 23:07:18 +0000626#endif /* FT_CONFIG_OPTION_INCREMENTAL */
Graham Asher3fd12f12002-08-15 12:10:48 +0000627
628 {
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000629 CFF_Font cff = (CFF_Font)(face->extra.data);
630
631
Graham Asher3fd12f12002-08-15 12:10:48 +0000632 cff_index_forget_element( &cff->charstrings_index, pointer );
633 }
634 }
635
636
637 static FT_Error
Werner Lemberg93616ec2001-06-27 19:46:12 +0000638 cff_operator_seac( CFF_Decoder* decoder,
639 FT_Pos adx,
640 FT_Pos ady,
641 FT_Int bchar,
642 FT_Int achar )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000643 {
644 FT_Error error;
645 FT_Int bchar_index, achar_index, n_base_points;
646 FT_Outline* base = decoder->builder.base;
647 TT_Face face = decoder->builder.face;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000648 FT_Vector left_bearing, advance;
649 FT_Byte* charstring;
650 FT_ULong charstring_len;
651
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000652
Graham Asher9eefed12002-08-23 10:08:38 +0000653#ifdef FT_CONFIG_OPTION_INCREMENTAL
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000654 /* Incremental fonts don't necessarily have valid charsets. */
655 /* They use the character code, not the glyph index, in this case. */
Graham Asher9eefed12002-08-23 10:08:38 +0000656 if ( face->root.internal->incremental_interface )
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000657 {
Graham Asher9eefed12002-08-23 10:08:38 +0000658 bchar_index = bchar;
659 achar_index = achar;
660 }
661 else
662#endif /* FT_CONFIG_OPTION_INCREMENTAL */
663 {
664 CFF_Font cff = (CFF_Font)(face->extra.data);
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000665
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000666
Graham Asher9eefed12002-08-23 10:08:38 +0000667 bchar_index = cff_lookup_glyph_by_stdcharcode( cff, bchar );
668 achar_index = cff_lookup_glyph_by_stdcharcode( cff, achar );
Werner Lemberg6b5c6692002-09-05 15:10:54 +0000669 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000670
671 if ( bchar_index < 0 || achar_index < 0 )
672 {
673 FT_ERROR(( "cff_operator_seac:" ));
674 FT_ERROR(( " invalid seac character code arguments\n" ));
675 return CFF_Err_Syntax_Error;
676 }
677
678 /* If we are trying to load a composite glyph, do not load the */
679 /* accent character and return the array of subglyphs. */
680 if ( decoder->builder.no_recurse )
681 {
Werner Lemberg48c984b2002-03-30 16:41:09 +0000682 FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph;
683 FT_GlyphLoader loader = glyph->internal->loader;
David Turnereba5ad42002-03-14 12:56:35 +0000684 FT_SubGlyph subg;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000685
686
687 /* reallocate subglyph array if necessary */
David Turnereba5ad42002-03-14 12:56:35 +0000688 error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000689 if ( error )
690 goto Exit;
691
692 subg = loader->current.subglyphs;
693
694 /* subglyph 0 = base character */
695 subg->index = bchar_index;
696 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES |
697 FT_SUBGLYPH_FLAG_USE_MY_METRICS;
698 subg->arg1 = 0;
699 subg->arg2 = 0;
700 subg++;
701
702 /* subglyph 1 = accent character */
703 subg->index = achar_index;
704 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
Werner Lemberg68e9f922002-09-27 11:09:23 +0000705 subg->arg1 = (FT_Int)adx;
706 subg->arg2 = (FT_Int)ady;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000707
708 /* set up remaining glyph fields */
709 glyph->num_subglyphs = 2;
710 glyph->subglyphs = loader->base.subglyphs;
David Turnerb08fe2d2002-08-27 20:20:29 +0000711 glyph->format = FT_GLYPH_FORMAT_COMPOSITE;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000712
713 loader->current.num_subglyphs = 2;
714 }
715
716 /* First load `bchar' in builder */
Graham Asher3fd12f12002-08-15 12:10:48 +0000717 error = cff_get_glyph_data( face, bchar_index,
718 &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000719 if ( !error )
720 {
Graham Asher9eefed12002-08-23 10:08:38 +0000721 error = cff_decoder_parse_charstrings( decoder, charstring,
722 charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000723
724 if ( error )
725 goto Exit;
726
Graham Asher3fd12f12002-08-15 12:10:48 +0000727 cff_free_glyph_data( face, &charstring, charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000728 }
729
730 n_base_points = base->n_points;
731
732 /* Save the left bearing and width of the base character */
733 /* as they will be erased by the next load. */
734
735 left_bearing = decoder->builder.left_bearing;
736 advance = decoder->builder.advance;
737
738 decoder->builder.left_bearing.x = 0;
739 decoder->builder.left_bearing.y = 0;
740
741 /* Now load `achar' on top of the base outline. */
Graham Asher3fd12f12002-08-15 12:10:48 +0000742 error = cff_get_glyph_data( face, achar_index,
743 &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000744 if ( !error )
745 {
Werner Lembergf25ce9d2002-08-15 23:07:18 +0000746 error = cff_decoder_parse_charstrings( decoder, charstring,
747 charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000748
749 if ( error )
750 goto Exit;
751
Graham Asher3fd12f12002-08-15 12:10:48 +0000752 cff_free_glyph_data( face, &charstring, charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000753 }
754
755 /* Restore the left side bearing and advance width */
756 /* of the base character. */
757 decoder->builder.left_bearing = left_bearing;
758 decoder->builder.advance = advance;
759
760 /* Finally, move the accent. */
761 if ( decoder->builder.load_points )
762 {
763 FT_Outline dummy;
764
765
Werner Lemberg8eb03532001-06-19 23:03:41 +0000766 dummy.n_points = (short)( base->n_points - n_base_points );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000767 dummy.points = base->points + n_base_points;
768
769 FT_Outline_Translate( &dummy, adx, ady );
770 }
771
772 Exit:
773 return error;
774 }
775
776
777 /*************************************************************************/
778 /* */
779 /* <Function> */
David Turnerb9b2cac2002-07-10 16:52:06 +0000780 /* cff_decoder_parse_charstrings */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000781 /* */
782 /* <Description> */
783 /* Parses a given Type 2 charstrings program. */
784 /* */
785 /* <InOut> */
786 /* decoder :: The current Type 1 decoder. */
787 /* */
788 /* <Input> */
789 /* charstring_base :: The base of the charstring stream. */
790 /* */
791 /* charstring_len :: The length in bytes of the charstring stream. */
792 /* */
793 /* <Return> */
794 /* FreeType error code. 0 means success. */
795 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000796 FT_LOCAL_DEF( FT_Error )
David Turnerb9b2cac2002-07-10 16:52:06 +0000797 cff_decoder_parse_charstrings( CFF_Decoder* decoder,
Werner Lemberg7f74a522002-07-26 09:09:10 +0000798 FT_Byte* charstring_base,
Werner Lemberg68e9f922002-09-27 11:09:23 +0000799 FT_ULong charstring_len )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000800 {
Werner Lembergd573c7e2001-01-03 07:14:12 +0000801 FT_Error error;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000802 CFF_Decoder_Zone* zone;
Werner Lembergd573c7e2001-01-03 07:14:12 +0000803 FT_Byte* ip;
804 FT_Byte* limit;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000805 CFF_Builder* builder = &decoder->builder;
Werner Lembergd573c7e2001-01-03 07:14:12 +0000806 FT_Pos x, y;
807 FT_Fixed seed;
808 FT_Fixed* stack;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000809
David Turner2b30c172001-12-12 16:07:29 +0000810 T2_Hints_Funcs hinter;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000811
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000812
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000813 /* set default width */
814 decoder->num_hints = 0;
815 decoder->read_width = 1;
816
817 /* compute random seed from stack address of parameter */
818 seed = (FT_Fixed)(char*)&seed ^
819 (FT_Fixed)(char*)&decoder ^
820 (FT_Fixed)(char*)&charstring_base;
821 seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFF;
822 if ( seed == 0 )
823 seed = 0x7384;
824
825 /* initialize the decoder */
826 decoder->top = decoder->stack;
827 decoder->zone = decoder->zones;
828 zone = decoder->zones;
829 stack = decoder->top;
830
David Turner2b30c172001-12-12 16:07:29 +0000831 hinter = (T2_Hints_Funcs) builder->hints_funcs;
832
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000833 builder->path_begun = 0;
834
835 zone->base = charstring_base;
836 limit = zone->limit = charstring_base + charstring_len;
837 ip = zone->cursor = zone->base;
838
Werner Lembergcf24d512001-06-18 14:23:45 +0000839 error = CFF_Err_Ok;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000840
841 x = builder->pos_x;
842 y = builder->pos_y;
843
David Turner2b30c172001-12-12 16:07:29 +0000844 /* begin hints recording session, if any */
845 if ( hinter )
846 hinter->open( hinter->hints );
847
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000848 /* now, execute loop */
849 while ( ip < limit )
850 {
851 CFF_Operator op;
Werner Lembergd573c7e2001-01-03 07:14:12 +0000852 FT_Byte v;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000853
854
855 /********************************************************************/
856 /* */
857 /* Decode operator or operand */
858 /* */
859 v = *ip++;
860 if ( v >= 32 || v == 28 )
861 {
862 FT_Int shift = 16;
863 FT_Int32 val;
864
865
866 /* this is an operand, push it on the stack */
867 if ( v == 28 )
868 {
869 if ( ip + 1 >= limit )
870 goto Syntax_Error;
871 val = (FT_Short)( ( (FT_Short)ip[0] << 8 ) | ip[1] );
872 ip += 2;
873 }
874 else if ( v < 247 )
875 val = (FT_Long)v - 139;
876 else if ( v < 251 )
877 {
878 if ( ip >= limit )
879 goto Syntax_Error;
880 val = ( (FT_Long)v - 247 ) * 256 + *ip++ + 108;
881 }
882 else if ( v < 255 )
883 {
884 if ( ip >= limit )
885 goto Syntax_Error;
886 val = -( (FT_Long)v - 251 ) * 256 - *ip++ - 108;
887 }
888 else
889 {
890 if ( ip + 3 >= limit )
891 goto Syntax_Error;
892 val = ( (FT_Int32)ip[0] << 24 ) |
893 ( (FT_Int32)ip[1] << 16 ) |
894 ( (FT_Int32)ip[2] << 8 ) |
895 ip[3];
896 ip += 4;
897 shift = 0;
898 }
899 if ( decoder->top - stack >= CFF_MAX_OPERANDS )
900 goto Stack_Overflow;
901
902 val <<= shift;
903 *decoder->top++ = val;
904
905#ifdef FT_DEBUG_LEVEL_TRACE
906 if ( !( val & 0xFFFF ) )
907 FT_TRACE4(( " %d", (FT_Int32)( val >> 16 ) ));
908 else
Tom Kacvinsky8316bc52001-03-16 13:35:56 +0000909 FT_TRACE4(( " %.2f", val / 65536.0 ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000910#endif
911
912 }
913 else
914 {
915 FT_Fixed* args = decoder->top;
Werner Lemberg68e9f922002-09-27 11:09:23 +0000916 FT_Int num_args = (FT_Int)( args - decoder->stack );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000917 FT_Int req_args;
918
919
920 /* find operator */
921 op = cff_op_unknown;
922
923 switch ( v )
924 {
925 case 1:
926 op = cff_op_hstem;
927 break;
928 case 3:
929 op = cff_op_vstem;
930 break;
931 case 4:
932 op = cff_op_vmoveto;
933 break;
934 case 5:
935 op = cff_op_rlineto;
936 break;
937 case 6:
938 op = cff_op_hlineto;
939 break;
940 case 7:
941 op = cff_op_vlineto;
942 break;
943 case 8:
944 op = cff_op_rrcurveto;
945 break;
946 case 10:
947 op = cff_op_callsubr;
948 break;
949 case 11:
950 op = cff_op_return;
951 break;
952 case 12:
953 {
954 if ( ip >= limit )
955 goto Syntax_Error;
956 v = *ip++;
957
958 switch ( v )
959 {
Tom Kacvinsky8316bc52001-03-16 13:35:56 +0000960 case 0:
961 op = cff_op_dotsection;
962 break;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000963 case 3:
964 op = cff_op_and;
965 break;
966 case 4:
967 op = cff_op_or;
968 break;
969 case 5:
970 op = cff_op_not;
971 break;
972 case 8:
973 op = cff_op_store;
974 break;
975 case 9:
976 op = cff_op_abs;
977 break;
978 case 10:
979 op = cff_op_add;
980 break;
981 case 11:
982 op = cff_op_sub;
983 break;
984 case 12:
985 op = cff_op_div;
986 break;
987 case 13:
988 op = cff_op_load;
989 break;
990 case 14:
991 op = cff_op_neg;
992 break;
993 case 15:
994 op = cff_op_eq;
995 break;
996 case 18:
997 op = cff_op_drop;
998 break;
999 case 20:
1000 op = cff_op_put;
1001 break;
1002 case 21:
1003 op = cff_op_get;
1004 break;
1005 case 22:
1006 op = cff_op_ifelse;
1007 break;
1008 case 23:
1009 op = cff_op_random;
1010 break;
1011 case 24:
1012 op = cff_op_mul;
1013 break;
1014 case 26:
1015 op = cff_op_sqrt;
1016 break;
1017 case 27:
1018 op = cff_op_dup;
1019 break;
1020 case 28:
1021 op = cff_op_exch;
1022 break;
1023 case 29:
1024 op = cff_op_index;
1025 break;
1026 case 30:
1027 op = cff_op_roll;
1028 break;
1029 case 34:
1030 op = cff_op_hflex;
1031 break;
1032 case 35:
1033 op = cff_op_flex;
1034 break;
1035 case 36:
1036 op = cff_op_hflex1;
1037 break;
1038 case 37:
1039 op = cff_op_flex1;
1040 break;
1041 default:
1042 /* decrement ip for syntax error message */
1043 ip--;
1044 }
1045 }
1046 break;
1047 case 14:
1048 op = cff_op_endchar;
1049 break;
1050 case 16:
1051 op = cff_op_blend;
1052 break;
1053 case 18:
1054 op = cff_op_hstemhm;
1055 break;
1056 case 19:
1057 op = cff_op_hintmask;
1058 break;
1059 case 20:
1060 op = cff_op_cntrmask;
1061 break;
1062 case 21:
1063 op = cff_op_rmoveto;
1064 break;
1065 case 22:
1066 op = cff_op_hmoveto;
1067 break;
1068 case 23:
1069 op = cff_op_vstemhm;
1070 break;
1071 case 24:
1072 op = cff_op_rcurveline;
1073 break;
1074 case 25:
1075 op = cff_op_rlinecurve;
1076 break;
1077 case 26:
1078 op = cff_op_vvcurveto;
1079 break;
1080 case 27:
1081 op = cff_op_hhcurveto;
1082 break;
1083 case 29:
1084 op = cff_op_callgsubr;
1085 break;
1086 case 30:
1087 op = cff_op_vhcurveto;
1088 break;
1089 case 31:
1090 op = cff_op_hvcurveto;
1091 break;
1092 default:
1093 ;
1094 }
1095 if ( op == cff_op_unknown )
1096 goto Syntax_Error;
1097
1098 /* check arguments */
1099 req_args = cff_argument_counts[op];
1100 if ( req_args & CFF_COUNT_CHECK_WIDTH )
1101 {
1102 args = stack;
1103
1104 if ( num_args > 0 && decoder->read_width )
1105 {
1106 /* If `nominal_width' is non-zero, the number is really a */
1107 /* difference against `nominal_width'. Else, the number here */
1108 /* is truly a width, not a difference against `nominal_width'. */
1109 /* If the font does not set `nominal_width', then */
1110 /* `nominal_width' defaults to zero, and so we can set */
1111 /* `glyph_width' to `nominal_width' plus number on the stack */
1112 /* -- for either case. */
1113
1114 FT_Int set_width_ok;
1115
1116
1117 switch ( op )
1118 {
1119 case cff_op_hmoveto:
1120 case cff_op_vmoveto:
1121 set_width_ok = num_args & 2;
1122 break;
1123
1124 case cff_op_hstem:
1125 case cff_op_vstem:
1126 case cff_op_hstemhm:
1127 case cff_op_vstemhm:
1128 case cff_op_rmoveto:
1129 set_width_ok = num_args & 1;
1130 break;
1131
1132 case cff_op_endchar:
1133 /* If there is a width specified for endchar, we either have */
1134 /* 1 argument or 5 arguments. We like to argue. */
1135 set_width_ok = ( ( num_args == 5 ) || ( num_args == 1 ) );
1136 break;
1137
1138 default:
1139 set_width_ok = 0;
1140 break;
1141 }
1142
1143 if ( set_width_ok )
1144 {
1145 decoder->glyph_width = decoder->nominal_width +
1146 ( stack[0] >> 16 );
1147
1148 /* Consumed an argument. */
1149 num_args--;
1150 args++;
1151 }
1152 }
1153
1154 decoder->read_width = 0;
1155 req_args = 0;
1156 }
1157
1158 req_args &= 15;
1159 if ( num_args < req_args )
1160 goto Stack_Underflow;
1161 args -= req_args;
1162 num_args -= req_args;
1163
1164 switch ( op )
1165 {
1166 case cff_op_hstem:
1167 case cff_op_vstem:
1168 case cff_op_hstemhm:
1169 case cff_op_vstemhm:
David Turner2b30c172001-12-12 16:07:29 +00001170 /* the number of arguments is always even here */
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001171 FT_TRACE4(( op == cff_op_hstem ? " hstem" :
David Turner2b30c172001-12-12 16:07:29 +00001172 ( op == cff_op_vstem ? " vstem" :
Werner Lemberg5da9dd72001-12-16 08:17:33 +00001173 ( op == cff_op_hstemhm ? " hstemhm" : " vstemhm" ) ) ));
David Turnerbce29862001-12-14 14:52:58 +00001174
David Turner2b30c172001-12-12 16:07:29 +00001175 if ( hinter )
1176 hinter->stems( hinter->hints,
David Turner7c0d2082001-12-21 15:59:43 +00001177 ( op == cff_op_hstem || op == cff_op_hstemhm ),
Werner Lemberg5da9dd72001-12-16 08:17:33 +00001178 num_args / 2,
David Turner2b30c172001-12-12 16:07:29 +00001179 args );
David Turnerbce29862001-12-14 14:52:58 +00001180
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001181 decoder->num_hints += num_args / 2;
1182 args = stack;
1183 break;
David Turnerbce29862001-12-14 14:52:58 +00001184
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001185 case cff_op_hintmask:
1186 case cff_op_cntrmask:
David Turner2b30c172001-12-12 16:07:29 +00001187 FT_TRACE4(( op == cff_op_hintmask ? " hintmask" : " cntrmask" ));
David Turner4d570242002-02-24 02:59:24 +00001188
Werner Lembergaf594e62001-12-22 14:38:40 +00001189 /* implement vstem when needed -- */
David Turnerb5c7de52001-12-21 21:21:13 +00001190 /* the specification doesn't say it, but this also works */
Werner Lembergaf594e62001-12-22 14:38:40 +00001191 /* with the 'cntrmask' operator */
David Turnerb5c7de52001-12-21 21:21:13 +00001192 /* */
David Turnerc8087482001-12-20 13:14:18 +00001193 if ( num_args > 0 )
1194 {
1195 if ( hinter )
1196 hinter->stems( hinter->hints,
David Turner7c0d2082001-12-21 15:59:43 +00001197 0,
David Turnerc8087482001-12-20 13:14:18 +00001198 num_args / 2,
1199 args );
David Turner4d570242002-02-24 02:59:24 +00001200
David Turnerc8087482001-12-20 13:14:18 +00001201 decoder->num_hints += num_args / 2;
1202 }
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001203
David Turner2b30c172001-12-12 16:07:29 +00001204 if ( hinter )
1205 {
1206 if ( op == cff_op_hintmask )
1207 hinter->hintmask( hinter->hints,
1208 builder->current->n_points,
David Turnerc8087482001-12-20 13:14:18 +00001209 decoder->num_hints,
David Turner2b30c172001-12-12 16:07:29 +00001210 ip );
1211 else
1212 hinter->counter( hinter->hints,
David Turnerc8087482001-12-20 13:14:18 +00001213 decoder->num_hints,
David Turner2b30c172001-12-12 16:07:29 +00001214 ip );
1215 }
David Turnerbce29862001-12-14 14:52:58 +00001216
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001217#ifdef FT_DEBUG_LEVEL_TRACE
1218 {
1219 FT_UInt maskbyte;
1220
Werner Lemberg48c984b2002-03-30 16:41:09 +00001221
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001222 FT_TRACE4(( " " ));
1223
Werner Lemberg521a2d72001-03-20 22:58:56 +00001224 for ( maskbyte = 0;
David Turner6d4fbec2001-04-20 08:50:36 +00001225 maskbyte < (FT_UInt)(( decoder->num_hints + 7 ) >> 3);
Werner Lemberg521a2d72001-03-20 22:58:56 +00001226 maskbyte++, ip++ )
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001227 FT_TRACE4(( "%02X", *ip ));
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001228 }
1229#else
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001230 ip += ( decoder->num_hints + 7 ) >> 3;
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001231#endif
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001232 if ( ip >= limit )
1233 goto Syntax_Error;
1234 args = stack;
1235 break;
1236
1237 case cff_op_rmoveto:
1238 FT_TRACE4(( " rmoveto" ));
1239
David Turnerb9b2cac2002-07-10 16:52:06 +00001240 cff_builder_close_contour( builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001241 builder->path_begun = 0;
1242 x += args[0];
1243 y += args[1];
1244 args = stack;
1245 break;
1246
1247 case cff_op_vmoveto:
1248 FT_TRACE4(( " vmoveto" ));
1249
David Turnerb9b2cac2002-07-10 16:52:06 +00001250 cff_builder_close_contour( builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001251 builder->path_begun = 0;
1252 y += args[0];
1253 args = stack;
1254 break;
1255
1256 case cff_op_hmoveto:
1257 FT_TRACE4(( " hmoveto" ));
1258
David Turnerb9b2cac2002-07-10 16:52:06 +00001259 cff_builder_close_contour( builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001260 builder->path_begun = 0;
1261 x += args[0];
1262 args = stack;
1263 break;
1264
1265 case cff_op_rlineto:
1266 FT_TRACE4(( " rlineto" ));
1267
Werner Lemberg7f74a522002-07-26 09:09:10 +00001268 if ( cff_builder_start_point ( builder, x, y ) ||
1269 check_points( builder, num_args / 2 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001270 goto Memory_Error;
1271
1272 if ( num_args < 2 || num_args & 1 )
1273 goto Stack_Underflow;
1274
1275 args = stack;
1276 while ( args < decoder->top )
1277 {
1278 x += args[0];
1279 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001280 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001281 args += 2;
1282 }
1283 args = stack;
1284 break;
1285
1286 case cff_op_hlineto:
1287 case cff_op_vlineto:
1288 {
1289 FT_Int phase = ( op == cff_op_hlineto );
1290
1291
1292 FT_TRACE4(( op == cff_op_hlineto ? " hlineto"
Werner Lembergd573c7e2001-01-03 07:14:12 +00001293 : " vlineto" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001294
David Turnerb9b2cac2002-07-10 16:52:06 +00001295 if ( cff_builder_start_point ( builder, x, y ) ||
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001296 check_points( builder, num_args ) )
1297 goto Memory_Error;
1298
1299 args = stack;
1300 while (args < decoder->top )
1301 {
1302 if ( phase )
1303 x += args[0];
1304 else
1305 y += args[0];
1306
Werner Lemberg7f74a522002-07-26 09:09:10 +00001307 if ( cff_builder_add_point1( builder, x, y ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001308 goto Memory_Error;
1309
1310 args++;
1311 phase ^= 1;
1312 }
1313 args = stack;
1314 }
1315 break;
1316
1317 case cff_op_rrcurveto:
1318 FT_TRACE4(( " rrcurveto" ));
1319
1320 /* check number of arguments; must be a multiple of 6 */
1321 if ( num_args % 6 != 0 )
1322 goto Stack_Underflow;
1323
Werner Lemberg7f74a522002-07-26 09:09:10 +00001324 if ( cff_builder_start_point ( builder, x, y ) ||
1325 check_points( builder, num_args / 2 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001326 goto Memory_Error;
1327
1328 args = stack;
1329 while ( args < decoder->top )
1330 {
1331 x += args[0];
1332 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001333 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001334 x += args[2];
1335 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001336 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001337 x += args[4];
1338 y += args[5];
David Turnerb9b2cac2002-07-10 16:52:06 +00001339 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001340 args += 6;
1341 }
1342 args = stack;
1343 break;
1344
1345 case cff_op_vvcurveto:
1346 FT_TRACE4(( " vvcurveto" ));
1347
David Turnerb9b2cac2002-07-10 16:52:06 +00001348 if ( cff_builder_start_point ( builder, x, y ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001349 goto Memory_Error;
1350
1351 args = stack;
1352 if ( num_args & 1 )
1353 {
1354 x += args[0];
1355 args++;
1356 num_args--;
1357 }
1358
1359 if ( num_args % 4 != 0 )
1360 goto Stack_Underflow;
1361
1362 if ( check_points( builder, 3 * ( num_args / 4 ) ) )
1363 goto Memory_Error;
1364
1365 while ( args < decoder->top )
1366 {
1367 y += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001368 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001369 x += args[1];
1370 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001371 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001372 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001373 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001374 args += 4;
1375 }
1376 args = stack;
1377 break;
1378
1379 case cff_op_hhcurveto:
1380 FT_TRACE4(( " hhcurveto" ));
1381
David Turnerb9b2cac2002-07-10 16:52:06 +00001382 if ( cff_builder_start_point ( builder, x, y ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001383 goto Memory_Error;
1384
1385 args = stack;
1386 if ( num_args & 1 )
1387 {
1388 y += args[0];
1389 args++;
1390 num_args--;
1391 }
1392
1393 if ( num_args % 4 != 0 )
1394 goto Stack_Underflow;
1395
1396 if ( check_points( builder, 3 * ( num_args / 4 ) ) )
1397 goto Memory_Error;
1398
1399 while ( args < decoder->top )
1400 {
1401 x += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001402 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001403 x += args[1];
1404 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001405 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001406 x += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001407 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001408 args += 4;
1409 }
1410 args = stack;
1411 break;
1412
1413 case cff_op_vhcurveto:
1414 case cff_op_hvcurveto:
1415 {
1416 FT_Int phase;
1417
1418
1419 FT_TRACE4(( op == cff_op_vhcurveto ? " vhcurveto"
Werner Lembergd573c7e2001-01-03 07:14:12 +00001420 : " hvcurveto" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001421
David Turnerb9b2cac2002-07-10 16:52:06 +00001422 if ( cff_builder_start_point ( builder, x, y ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001423 goto Memory_Error;
1424
1425 args = stack;
1426 if (num_args < 4 || ( num_args % 4 ) > 1 )
1427 goto Stack_Underflow;
1428
1429 if ( check_points( builder, ( num_args / 4 ) * 3 ) )
1430 goto Stack_Underflow;
1431
1432 phase = ( op == cff_op_hvcurveto );
1433
1434 while ( num_args >= 4 )
1435 {
1436 num_args -= 4;
1437 if ( phase )
1438 {
1439 x += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001440 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001441 x += args[1];
1442 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001443 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001444 y += args[3];
1445 if ( num_args == 1 )
1446 x += args[4];
David Turnerb9b2cac2002-07-10 16:52:06 +00001447 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001448 }
1449 else
1450 {
1451 y += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001452 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001453 x += args[1];
1454 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001455 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001456 x += args[3];
1457 if ( num_args == 1 )
1458 y += args[4];
David Turnerb9b2cac2002-07-10 16:52:06 +00001459 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001460 }
1461 args += 4;
1462 phase ^= 1;
1463 }
1464 args = stack;
1465 }
1466 break;
1467
1468 case cff_op_rlinecurve:
1469 {
1470 FT_Int num_lines = ( num_args - 6 ) / 2;
1471
1472
1473 FT_TRACE4(( " rlinecurve" ));
1474
1475 if ( num_args < 8 || ( num_args - 6 ) & 1 )
1476 goto Stack_Underflow;
1477
Werner Lemberg7f74a522002-07-26 09:09:10 +00001478 if ( cff_builder_start_point( builder, x, y ) ||
1479 check_points( builder, num_lines + 3 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001480 goto Memory_Error;
1481
1482 args = stack;
1483
1484 /* first, add the line segments */
1485 while ( num_lines > 0 )
1486 {
1487 x += args[0];
1488 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001489 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001490 args += 2;
1491 num_lines--;
1492 }
1493
1494 /* then the curve */
1495 x += args[0];
1496 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001497 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001498 x += args[2];
1499 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001500 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001501 x += args[4];
1502 y += args[5];
David Turnerb9b2cac2002-07-10 16:52:06 +00001503 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001504 args = stack;
1505 }
1506 break;
1507
1508 case cff_op_rcurveline:
1509 {
1510 FT_Int num_curves = ( num_args - 2 ) / 6;
1511
1512
1513 FT_TRACE4(( " rcurveline" ));
1514
1515 if ( num_args < 8 || ( num_args - 2 ) % 6 )
1516 goto Stack_Underflow;
1517
Werner Lemberg7f74a522002-07-26 09:09:10 +00001518 if ( cff_builder_start_point ( builder, x, y ) ||
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001519 check_points( builder, num_curves*3 + 2 ) )
1520 goto Memory_Error;
1521
1522 args = stack;
1523
1524 /* first, add the curves */
1525 while ( num_curves > 0 )
1526 {
1527 x += args[0];
1528 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001529 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001530 x += args[2];
1531 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001532 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001533 x += args[4];
1534 y += args[5];
David Turnerb9b2cac2002-07-10 16:52:06 +00001535 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001536 args += 6;
1537 num_curves--;
1538 }
1539
1540 /* then the final line */
1541 x += args[0];
1542 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001543 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001544 args = stack;
1545 }
1546 break;
1547
1548 case cff_op_hflex1:
1549 {
1550 FT_Pos start_y;
1551
1552
1553 FT_TRACE4(( " hflex1" ));
1554
1555 args = stack;
1556
1557 /* adding five more points; 4 control points, 1 on-curve point */
1558 /* make sure we have enough space for the start point if it */
1559 /* needs to be added.. */
David Turnerb9b2cac2002-07-10 16:52:06 +00001560 if ( cff_builder_start_point( builder, x, y ) ||
Werner Lemberg7f74a522002-07-26 09:09:10 +00001561 check_points( builder, 6 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001562 goto Memory_Error;
1563
1564 /* Record the starting point's y postion for later use */
1565 start_y = y;
1566
1567 /* first control point */
1568 x += args[0];
1569 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001570 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001571
1572 /* second control point */
1573 x += args[2];
1574 y += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001575 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001576
1577 /* join point; on curve, with y-value the same as the last */
1578 /* control point's y-value */
1579 x += args[4];
David Turnerb9b2cac2002-07-10 16:52:06 +00001580 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001581
1582 /* third control point, with y-value the same as the join */
1583 /* point's y-value */
1584 x += args[5];
David Turnerb9b2cac2002-07-10 16:52:06 +00001585 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001586
1587 /* fourth control point */
1588 x += args[6];
1589 y += args[7];
David Turnerb9b2cac2002-07-10 16:52:06 +00001590 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001591
1592 /* ending point, with y-value the same as the start */
1593 x += args[8];
1594 y = start_y;
David Turnerb9b2cac2002-07-10 16:52:06 +00001595 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001596
1597 args = stack;
1598 break;
1599 }
1600
1601 case cff_op_hflex:
1602 {
1603 FT_Pos start_y;
1604
1605
1606 FT_TRACE4(( " hflex" ));
1607
1608 args = stack;
1609
1610 /* adding six more points; 4 control points, 2 on-curve points */
David Turnerb9b2cac2002-07-10 16:52:06 +00001611 if ( cff_builder_start_point( builder, x, y ) ||
Werner Lemberg7f74a522002-07-26 09:09:10 +00001612 check_points ( builder, 6 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001613 goto Memory_Error;
1614
1615 /* record the starting point's y-position for later use */
1616 start_y = y;
1617
1618 /* first control point */
1619 x += args[0];
David Turnerb9b2cac2002-07-10 16:52:06 +00001620 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001621
1622 /* second control point */
1623 x += args[1];
1624 y += args[2];
David Turnerb9b2cac2002-07-10 16:52:06 +00001625 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001626
1627 /* join point; on curve, with y-value the same as the last */
1628 /* control point's y-value */
1629 x += args[3];
David Turnerb9b2cac2002-07-10 16:52:06 +00001630 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001631
1632 /* third control point, with y-value the same as the join */
1633 /* point's y-value */
1634 x += args[4];
David Turnerb9b2cac2002-07-10 16:52:06 +00001635 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001636
1637 /* fourth control point */
1638 x += args[5];
1639 y = start_y;
David Turnerb9b2cac2002-07-10 16:52:06 +00001640 cff_builder_add_point( builder, x, y, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001641
1642 /* ending point, with y-value the same as the start point's */
1643 /* y-value -- we don't add this point, though */
1644 x += args[6];
David Turnerb9b2cac2002-07-10 16:52:06 +00001645 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001646
1647 args = stack;
1648 break;
1649 }
1650
1651 case cff_op_flex1:
1652 {
1653 FT_Pos start_x, start_y; /* record start x, y values for alter */
1654 /* use */
1655 FT_Int dx = 0, dy = 0; /* used in horizontal/vertical */
1656 /* algorithm below */
1657 FT_Int horizontal, count;
1658
1659
1660 FT_TRACE4(( " flex1" ));
1661
1662 /* adding six more points; 4 control points, 2 on-curve points */
David Turnerb9b2cac2002-07-10 16:52:06 +00001663 if ( cff_builder_start_point( builder, x, y ) ||
Werner Lemberg7f74a522002-07-26 09:09:10 +00001664 check_points( builder, 6 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001665 goto Memory_Error;
1666
1667 /* record the starting point's x, y postion for later use */
1668 start_x = x;
1669 start_y = y;
1670
1671 /* XXX: figure out whether this is supposed to be a horizontal */
1672 /* or vertical flex; the Type 2 specification is vague... */
1673
1674 args = stack;
1675
1676 /* grab up to the last argument */
1677 for ( count = 5; count > 0; count-- )
1678 {
Werner Lemberg68e9f922002-09-27 11:09:23 +00001679 dx += (FT_Int)args[0];
1680 dy += (FT_Int)args[1];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001681 args += 2;
1682 }
1683
1684 /* rewind */
1685 args = stack;
1686
1687 if ( dx < 0 ) dx = -dx;
1688 if ( dy < 0 ) dy = -dy;
1689
1690 /* strange test, but here it is... */
1691 horizontal = ( dx > dy );
1692
1693 for ( count = 5; count > 0; count-- )
1694 {
1695 x += args[0];
1696 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001697 cff_builder_add_point( builder, x, y, (FT_Bool)( count == 3 ) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001698 args += 2;
1699 }
1700
1701 /* is last operand an x- or y-delta? */
1702 if ( horizontal )
1703 {
1704 x += args[0];
1705 y = start_y;
1706 }
1707 else
1708 {
1709 x = start_x;
1710 y += args[0];
1711 }
1712
David Turnerb9b2cac2002-07-10 16:52:06 +00001713 cff_builder_add_point( builder, x, y, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001714
1715 args = stack;
1716 break;
1717 }
1718
1719 case cff_op_flex:
1720 {
1721 FT_UInt count;
1722
1723
1724 FT_TRACE4(( " flex" ));
1725
David Turnerb9b2cac2002-07-10 16:52:06 +00001726 if ( cff_builder_start_point( builder, x, y ) ||
Werner Lemberg7f74a522002-07-26 09:09:10 +00001727 check_points( builder, 6 ) )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001728 goto Memory_Error;
1729
1730 args = stack;
1731 for ( count = 6; count > 0; count-- )
1732 {
1733 x += args[0];
1734 y += args[1];
David Turnerb9b2cac2002-07-10 16:52:06 +00001735 cff_builder_add_point( builder, x, y,
Werner Lemberg7f74a522002-07-26 09:09:10 +00001736 (FT_Bool)( count == 3 || count == 0 ) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001737 args += 2;
1738 }
1739
1740 args = stack;
1741 }
1742 break;
1743
1744 case cff_op_endchar:
1745 FT_TRACE4(( " endchar" ));
1746
1747 /* We are going to emulate the seac operator. */
1748 if ( num_args == 4 )
1749 {
Werner Lembergd573c7e2001-01-03 07:14:12 +00001750 error = cff_operator_seac( decoder,
Werner Lemberg68e9f922002-09-27 11:09:23 +00001751 args[0] >> 16,
1752 args[1] >> 16,
1753 (FT_Int)( args[2] >> 16 ),
1754 (FT_Int)( args[3] >> 16 ) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001755 args += 4;
1756 }
1757
1758 if ( !error )
1759 error = CFF_Err_Ok;
1760
David Turnerb9b2cac2002-07-10 16:52:06 +00001761 cff_builder_close_contour( builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001762
David Turner2b30c172001-12-12 16:07:29 +00001763 /* close hints recording session */
1764 if ( hinter )
1765 {
Werner Lemberg5da9dd72001-12-16 08:17:33 +00001766 if (hinter->close( hinter->hints, builder->current->n_points ) )
David Turner2b30c172001-12-12 16:07:29 +00001767 goto Syntax_Error;
David Turnerbce29862001-12-14 14:52:58 +00001768
David Turner2b30c172001-12-12 16:07:29 +00001769 /* apply hints to the loaded glyph outline now */
1770 hinter->apply( hinter->hints,
1771 builder->current,
David Turner27c322e2002-07-08 22:26:11 +00001772 (PSH_Globals)builder->hints_globals,
1773 builder->hint_flags );
David Turner2b30c172001-12-12 16:07:29 +00001774 }
1775
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001776 /* add current outline to the glyph slot */
1777 FT_GlyphLoader_Add( builder->loader );
1778
1779 /* return now! */
1780 FT_TRACE4(( "\n\n" ));
1781 return error;
1782
1783 case cff_op_abs:
1784 FT_TRACE4(( " abs" ));
1785
1786 if ( args[0] < 0 )
1787 args[0] = -args[0];
1788 args++;
1789 break;
1790
1791 case cff_op_add:
1792 FT_TRACE4(( " add" ));
1793
1794 args[0] += args[1];
1795 args++;
1796 break;
1797
1798 case cff_op_sub:
1799 FT_TRACE4(( " sub" ));
1800
1801 args[0] -= args[1];
1802 args++;
1803 break;
1804
1805 case cff_op_div:
1806 FT_TRACE4(( " div" ));
1807
1808 args[0] = FT_DivFix( args[0], args[1] );
1809 args++;
1810 break;
1811
1812 case cff_op_neg:
1813 FT_TRACE4(( " neg" ));
1814
1815 args[0] = -args[0];
1816 args++;
1817 break;
1818
1819 case cff_op_random:
1820 {
Werner Lemberg94ffae52002-04-14 00:54:32 +00001821 FT_Fixed Rand;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001822
1823
1824 FT_TRACE4(( " rand" ));
1825
Werner Lemberg94ffae52002-04-14 00:54:32 +00001826 Rand = seed;
1827 if ( Rand >= 0x8000 )
1828 Rand++;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001829
Werner Lemberg94ffae52002-04-14 00:54:32 +00001830 args[0] = Rand;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001831 seed = FT_MulFix( seed, 0x10000L - seed );
1832 if ( seed == 0 )
1833 seed += 0x2873;
1834 args++;
1835 }
1836 break;
1837
1838 case cff_op_mul:
1839 FT_TRACE4(( " mul" ));
1840
1841 args[0] = FT_MulFix( args[0], args[1] );
1842 args++;
1843 break;
1844
1845 case cff_op_sqrt:
1846 FT_TRACE4(( " sqrt" ));
1847
1848 if ( args[0] > 0 )
1849 {
1850 FT_Int count = 9;
1851 FT_Fixed root = args[0];
1852 FT_Fixed new_root;
1853
1854
1855 for (;;)
1856 {
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001857 new_root = ( root + FT_DivFix( args[0], root ) + 1 ) >> 1;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001858 if ( new_root == root || count <= 0 )
1859 break;
1860 root = new_root;
1861 }
1862 args[0] = new_root;
1863 }
1864 else
1865 args[0] = 0;
1866 args++;
1867 break;
1868
1869 case cff_op_drop:
1870 /* nothing */
1871 FT_TRACE4(( " drop" ));
1872
1873 break;
1874
1875 case cff_op_exch:
1876 {
1877 FT_Fixed tmp;
1878
1879
1880 FT_TRACE4(( " exch" ));
1881
1882 tmp = args[0];
1883 args[0] = args[1];
1884 args[1] = tmp;
1885 args += 2;
1886 }
1887 break;
1888
1889 case cff_op_index:
1890 {
Werner Lemberg68e9f922002-09-27 11:09:23 +00001891 FT_Int idx = (FT_Int)( args[0] >> 16 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001892
1893
1894 FT_TRACE4(( " index" ));
1895
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001896 if ( idx < 0 )
1897 idx = 0;
1898 else if ( idx > num_args - 2 )
1899 idx = num_args - 2;
1900 args[0] = args[-( idx + 1 )];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001901 args++;
1902 }
1903 break;
1904
1905 case cff_op_roll:
1906 {
1907 FT_Int count = (FT_Int)( args[0] >> 16 );
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001908 FT_Int idx = (FT_Int)( args[1] >> 16 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001909
1910
1911 FT_TRACE4(( " roll" ));
1912
1913 if ( count <= 0 )
1914 count = 1;
1915
1916 args -= count;
1917 if ( args < stack )
1918 goto Stack_Underflow;
1919
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001920 if ( idx >= 0 )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001921 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001922 while ( idx > 0 )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001923 {
1924 FT_Fixed tmp = args[count - 1];
1925 FT_Int i;
1926
1927
1928 for ( i = count - 2; i >= 0; i-- )
1929 args[i + 1] = args[i];
1930 args[0] = tmp;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001931 idx--;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001932 }
1933 }
1934 else
1935 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001936 while ( idx < 0 )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001937 {
1938 FT_Fixed tmp = args[0];
1939 FT_Int i;
1940
1941
1942 for ( i = 0; i < count - 1; i++ )
1943 args[i] = args[i + 1];
1944 args[count - 1] = tmp;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001945 idx++;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001946 }
1947 }
1948 args += count;
1949 }
1950 break;
1951
1952 case cff_op_dup:
1953 FT_TRACE4(( " dup" ));
1954
1955 args[1] = args[0];
1956 args++;
1957 break;
1958
1959 case cff_op_put:
1960 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001961 FT_Fixed val = args[0];
1962 FT_Int idx = (FT_Int)( args[1] >> 16 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001963
1964
1965 FT_TRACE4(( " put" ));
1966
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001967 if ( idx >= 0 && idx < decoder->len_buildchar )
1968 decoder->buildchar[idx] = val;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001969 }
1970 break;
1971
1972 case cff_op_get:
1973 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001974 FT_Int idx = (FT_Int)( args[0] >> 16 );
1975 FT_Fixed val = 0;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001976
1977
1978 FT_TRACE4(( " get" ));
1979
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001980 if ( idx >= 0 && idx < decoder->len_buildchar )
1981 val = decoder->buildchar[idx];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001982
1983 args[0] = val;
1984 args++;
1985 }
1986 break;
1987
1988 case cff_op_store:
1989 FT_TRACE4(( " store "));
1990
1991 goto Unimplemented;
1992
1993 case cff_op_load:
1994 FT_TRACE4(( " load" ));
1995
1996 goto Unimplemented;
1997
David Turner8d3a4012001-03-20 11:14:24 +00001998 case cff_op_dotsection:
Werner Lemberg521a2d72001-03-20 22:58:56 +00001999 /* this operator is deprecated and ignored by the parser */
2000 FT_TRACE4(( " dotsection" ));
David Turner8d3a4012001-03-20 11:14:24 +00002001 break;
2002
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002003 case cff_op_and:
2004 {
2005 FT_Fixed cond = args[0] && args[1];
2006
2007
2008 FT_TRACE4(( " and" ));
2009
2010 args[0] = cond ? 0x10000L : 0;
2011 args++;
2012 }
2013 break;
2014
2015 case cff_op_or:
2016 {
2017 FT_Fixed cond = args[0] || args[1];
2018
2019
2020 FT_TRACE4(( " or" ));
2021
2022 args[0] = cond ? 0x10000L : 0;
2023 args++;
2024 }
2025 break;
2026
2027 case cff_op_eq:
2028 {
2029 FT_Fixed cond = !args[0];
2030
2031
2032 FT_TRACE4(( " eq" ));
2033
2034 args[0] = cond ? 0x10000L : 0;
2035 args++;
2036 }
2037 break;
2038
2039 case cff_op_ifelse:
2040 {
2041 FT_Fixed cond = (args[2] <= args[3]);
2042
2043
2044 FT_TRACE4(( " ifelse" ));
2045
2046 if ( !cond )
2047 args[0] = args[1];
2048 args++;
2049 }
2050 break;
2051
2052 case cff_op_callsubr:
2053 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002054 FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) +
2055 decoder->locals_bias );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002056
2057
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002058 FT_TRACE4(( " callsubr(%d)", idx ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002059
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002060 if ( idx >= decoder->num_locals )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002061 {
David Turnerb9b2cac2002-07-10 16:52:06 +00002062 FT_ERROR(( "cff_decoder_parse_charstrings:" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002063 FT_ERROR(( " invalid local subr index\n" ));
2064 goto Syntax_Error;
2065 }
2066
2067 if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
2068 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002069 FT_ERROR(( "cff_decoder_parse_charstrings:"
2070 " too many nested subrs\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002071 goto Syntax_Error;
2072 }
2073
2074 zone->cursor = ip; /* save current instruction pointer */
2075
2076 zone++;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002077 zone->base = decoder->locals[idx];
2078 zone->limit = decoder->locals[idx + 1];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002079 zone->cursor = zone->base;
2080
2081 if ( !zone->base )
2082 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002083 FT_ERROR(( "cff_decoder_parse_charstrings:"
2084 " invoking empty subrs!\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002085 goto Syntax_Error;
2086 }
2087
2088 decoder->zone = zone;
2089 ip = zone->base;
2090 limit = zone->limit;
2091 }
2092 break;
2093
2094 case cff_op_callgsubr:
2095 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002096 FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) +
2097 decoder->globals_bias );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002098
2099
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002100 FT_TRACE4(( " callgsubr(%d)", idx ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002101
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002102 if ( idx >= decoder->num_globals )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002103 {
David Turnerb9b2cac2002-07-10 16:52:06 +00002104 FT_ERROR(( "cff_decoder_parse_charstrings:" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002105 FT_ERROR(( " invalid global subr index\n" ));
2106 goto Syntax_Error;
2107 }
2108
2109 if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
2110 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002111 FT_ERROR(( "cff_decoder_parse_charstrings:"
2112 " too many nested subrs\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002113 goto Syntax_Error;
2114 }
2115
2116 zone->cursor = ip; /* save current instruction pointer */
2117
2118 zone++;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002119 zone->base = decoder->globals[idx];
2120 zone->limit = decoder->globals[idx + 1];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002121 zone->cursor = zone->base;
2122
2123 if ( !zone->base )
2124 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002125 FT_ERROR(( "cff_decoder_parse_charstrings:"
2126 " invoking empty subrs!\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002127 goto Syntax_Error;
2128 }
2129
2130 decoder->zone = zone;
2131 ip = zone->base;
2132 limit = zone->limit;
2133 }
2134 break;
2135
2136 case cff_op_return:
2137 FT_TRACE4(( " return" ));
2138
2139 if ( decoder->zone <= decoder->zones )
2140 {
Werner Lemberg7f74a522002-07-26 09:09:10 +00002141 FT_ERROR(( "cff_decoder_parse_charstrings:"
2142 " unexpected return\n" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002143 goto Syntax_Error;
2144 }
2145
2146 decoder->zone--;
2147 zone = decoder->zone;
2148 ip = zone->cursor;
2149 limit = zone->limit;
2150 break;
2151
2152 default:
2153 Unimplemented:
2154 FT_ERROR(( "Unimplemented opcode: %d", ip[-1] ));
2155
2156 if ( ip[-1] == 12 )
2157 FT_ERROR(( " %d", ip[0] ));
2158 FT_ERROR(( "\n" ));
2159
2160 return CFF_Err_Unimplemented_Feature;
2161 }
2162
2163 decoder->top = args;
2164
2165 } /* general operator processing */
2166
2167 } /* while ip < limit */
2168
2169 FT_TRACE4(( "..end..\n\n" ));
2170
2171 return error;
2172
2173 Syntax_Error:
David Turnerb9b2cac2002-07-10 16:52:06 +00002174 FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error!" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002175 return CFF_Err_Invalid_File_Format;
2176
2177 Stack_Underflow:
David Turnerb9b2cac2002-07-10 16:52:06 +00002178 FT_TRACE4(( "cff_decoder_parse_charstrings: stack underflow!" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002179 return CFF_Err_Too_Few_Arguments;
2180
2181 Stack_Overflow:
David Turnerb9b2cac2002-07-10 16:52:06 +00002182 FT_TRACE4(( "cff_decoder_parse_charstrings: stack overflow!" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002183 return CFF_Err_Stack_Overflow;
2184
2185 Memory_Error:
2186 return builder->error;
2187 }
2188
2189
2190 /*************************************************************************/
2191 /*************************************************************************/
2192 /*************************************************************************/
2193 /********** *********/
2194 /********** *********/
2195 /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
2196 /********** *********/
2197 /********** The following code is in charge of computing *********/
2198 /********** the maximum advance width of the font. It *********/
2199 /********** quickly processes each glyph charstring to *********/
2200 /********** extract the value from either a `sbw' or `seac' *********/
2201 /********** operator. *********/
2202 /********** *********/
2203 /*************************************************************************/
2204 /*************************************************************************/
2205 /*************************************************************************/
2206
2207
2208#if 0 /* unused until we support pure CFF fonts */
2209
2210
David Turnerbc82f1b2002-03-01 02:26:22 +00002211 FT_LOCAL_DEF( FT_Error )
David Turnerb9b2cac2002-07-10 16:52:06 +00002212 cff_compute_max_advance( TT_Face face,
Werner Lemberg93616ec2001-06-27 19:46:12 +00002213 FT_Int* max_advance )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002214 {
Werner Lembergd573c7e2001-01-03 07:14:12 +00002215 FT_Error error = 0;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002216 CFF_Decoder decoder;
Werner Lembergd573c7e2001-01-03 07:14:12 +00002217 FT_Int glyph_index;
Werner Lemberg48c984b2002-03-30 16:41:09 +00002218 CFF_Font cff = (CFF_Font)face->other;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002219
2220
2221 *max_advance = 0;
2222
2223 /* Initialize load decoder */
David Turnerd1245c02002-08-27 22:34:20 +00002224 cff_decoder_init( &decoder, face, 0, 0, 0, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002225
2226 decoder.builder.metrics_only = 1;
2227 decoder.builder.load_points = 0;
2228
2229 /* For each glyph, parse the glyph charstring and extract */
2230 /* the advance width. */
2231 for ( glyph_index = 0; glyph_index < face->root.num_glyphs;
2232 glyph_index++ )
2233 {
2234 FT_Byte* charstring;
2235 FT_ULong charstring_len;
2236
2237
2238 /* now get load the unscaled outline */
Graham Asher3fd12f12002-08-15 12:10:48 +00002239 error = cff_get_glyph_data( face, glyph_index,
2240 &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002241 if ( !error )
2242 {
David Turnerb9b2cac2002-07-10 16:52:06 +00002243 cff_decoder_prepare( &decoder, glyph_index );
Werner Lemberg7f74a522002-07-26 09:09:10 +00002244 error = cff_decoder_parse_charstrings( &decoder,
2245 charstring, charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002246
Graham Asher3fd12f12002-08-15 12:10:48 +00002247 cff_free_glyph_data( face, &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002248 }
2249
2250 /* ignore the error if one has occurred -- skip to next glyph */
2251 error = 0;
2252 }
2253
2254 *max_advance = decoder.builder.advance.x;
2255
2256 return CFF_Err_Ok;
2257 }
2258
2259
2260#endif /* 0 */
2261
2262
2263 /*************************************************************************/
2264 /*************************************************************************/
2265 /*************************************************************************/
2266 /********** *********/
2267 /********** *********/
2268 /********** UNHINTED GLYPH LOADER *********/
2269 /********** *********/
2270 /********** The following code is in charge of loading a *********/
2271 /********** single outline. It completely ignores hinting *********/
2272 /********** and is used when FT_LOAD_NO_HINTING is set. *********/
2273 /********** *********/
2274 /*************************************************************************/
2275 /*************************************************************************/
2276 /*************************************************************************/
2277
2278
David Turnerbc82f1b2002-03-01 02:26:22 +00002279 FT_LOCAL_DEF( FT_Error )
David Turnerb9b2cac2002-07-10 16:52:06 +00002280 cff_slot_load( CFF_GlyphSlot glyph,
2281 CFF_Size size,
2282 FT_Int glyph_index,
David Turnerd1245c02002-08-27 22:34:20 +00002283 FT_Int32 load_flags )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002284 {
Werner Lembergd573c7e2001-01-03 07:14:12 +00002285 FT_Error error;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002286 CFF_Decoder decoder;
Werner Lembergd573c7e2001-01-03 07:14:12 +00002287 TT_Face face = (TT_Face)glyph->root.face;
2288 FT_Bool hinting;
Werner Lemberg48c984b2002-03-30 16:41:09 +00002289 CFF_Font cff = (CFF_Font)face->extra.data;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002290
Werner Lembergd573c7e2001-01-03 07:14:12 +00002291 FT_Matrix font_matrix;
2292 FT_Vector font_offset;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002293
2294
2295 if ( load_flags & FT_LOAD_NO_RECURSE )
2296 load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
2297
2298 glyph->x_scale = 0x10000L;
2299 glyph->y_scale = 0x10000L;
2300 if ( size )
2301 {
2302 glyph->x_scale = size->metrics.x_scale;
2303 glyph->y_scale = size->metrics.y_scale;
2304 }
2305
2306 glyph->root.outline.n_points = 0;
2307 glyph->root.outline.n_contours = 0;
2308
David Turner8edbcab2001-06-19 08:28:24 +00002309 hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 &&
2310 ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002311
David Turnerb08fe2d2002-08-27 20:20:29 +00002312 glyph->root.format = FT_GLYPH_FORMAT_OUTLINE; /* by default */
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002313
2314 {
2315 FT_Byte* charstring;
2316 FT_ULong charstring_len;
2317
2318
David Turnerd1245c02002-08-27 22:34:20 +00002319 cff_decoder_init( &decoder, face, size, glyph, hinting,
2320 FT_LOAD_TARGET_MODE(load_flags) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002321
2322 decoder.builder.no_recurse =
2323 (FT_Bool)( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 );
2324
2325 /* now load the unscaled outline */
Graham Asher3fd12f12002-08-15 12:10:48 +00002326 error = cff_get_glyph_data( face, glyph_index,
2327 &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002328 if ( !error )
2329 {
David Turnerb9b2cac2002-07-10 16:52:06 +00002330 cff_decoder_prepare( &decoder, glyph_index );
Werner Lemberg7f74a522002-07-26 09:09:10 +00002331 error = cff_decoder_parse_charstrings( &decoder,
2332 charstring, charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002333
Graham Asher3fd12f12002-08-15 12:10:48 +00002334 cff_free_glyph_data( face, &charstring, charstring_len );
Tom Kacvinskye20035a2001-03-05 16:22:25 +00002335
Graham Asher3fd12f12002-08-15 12:10:48 +00002336
2337#ifdef FT_CONFIG_OPTION_INCREMENTAL
Werner Lemberg6b5c6692002-09-05 15:10:54 +00002338 /* Control data and length may not be available for incremental */
Graham Asher3fd12f12002-08-15 12:10:48 +00002339 /* fonts. */
2340 if ( face->root.internal->incremental_interface )
2341 {
2342 glyph->root.control_data = 0;
2343 glyph->root.control_len = 0;
2344 }
2345 else
Werner Lembergf25ce9d2002-08-15 23:07:18 +00002346#endif /* FT_CONFIG_OPTION_INCREMENTAL */
2347
Tom Kacvinskye20035a2001-03-05 16:22:25 +00002348 /* We set control_data and control_len if charstrings is loaded. */
Werner Lemberg7f74a522002-07-26 09:09:10 +00002349 /* See how charstring loads at cff_index_access_element() in */
2350 /* cffload.c. */
Graham Asher3fd12f12002-08-15 12:10:48 +00002351 {
Werner Lemberg6b5c6692002-09-05 15:10:54 +00002352 CFF_IndexRec csindex = cff->charstrings_index;
2353
2354
2355 glyph->root.control_data =
2356 csindex.bytes + csindex.offsets[glyph_index] - 1;
2357 glyph->root.control_len =
2358 charstring_len;
Graham Asher3fd12f12002-08-15 12:10:48 +00002359 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002360 }
2361
2362 /* save new glyph tables */
David Turnerb9b2cac2002-07-10 16:52:06 +00002363 cff_builder_done( &decoder.builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002364 }
2365
2366 font_matrix = cff->top_font.font_dict.font_matrix;
2367 font_offset = cff->top_font.font_dict.font_offset;
2368
2369 /* Now, set the metrics -- this is rather simple, as */
2370 /* the left side bearing is the xMin, and the top side */
2371 /* bearing the yMax. */
2372 if ( !error )
2373 {
2374 /* For composite glyphs, return only left side bearing and */
2375 /* advance width. */
2376 if ( load_flags & FT_LOAD_NO_RECURSE )
2377 {
2378 FT_Slot_Internal internal = glyph->root.internal;
Werner Lemberg415235d2001-06-28 17:49:10 +00002379
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002380
2381 glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
2382 glyph->root.metrics.horiAdvance = decoder.glyph_width;
2383 internal->glyph_matrix = font_matrix;
2384 internal->glyph_delta = font_offset;
2385 internal->glyph_transformed = 1;
2386 }
2387 else
2388 {
2389 FT_BBox cbox;
2390 FT_Glyph_Metrics* metrics = &glyph->root.metrics;
2391
2392
2393 /* copy the _unscaled_ advance width */
2394 metrics->horiAdvance = decoder.glyph_width;
2395 glyph->root.linearHoriAdvance = decoder.glyph_width;
2396 glyph->root.internal->glyph_transformed = 0;
2397
2398 /* make up vertical metrics */
2399 metrics->vertBearingX = 0;
2400 metrics->vertBearingY = 0;
2401 metrics->vertAdvance = 0;
2402
2403 glyph->root.linearVertAdvance = 0;
2404
David Turnerb08fe2d2002-08-27 20:20:29 +00002405 glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002406
2407 glyph->root.outline.flags = 0;
2408 if ( size && size->metrics.y_ppem < 24 )
David Turnerb08fe2d2002-08-27 20:20:29 +00002409 glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002410
David Turnerb08fe2d2002-08-27 20:20:29 +00002411 glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002412
2413 /* apply the font matrix */
2414 FT_Outline_Transform( &glyph->root.outline, &font_matrix );
2415
2416 FT_Outline_Translate( &glyph->root.outline,
2417 font_offset.x,
2418 font_offset.y );
2419
2420 if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 )
2421 {
2422 /* scale the outline and the metrics */
2423 FT_Int n;
2424 FT_Outline* cur = &glyph->root.outline;
2425 FT_Vector* vec = cur->points;
2426 FT_Fixed x_scale = glyph->x_scale;
2427 FT_Fixed y_scale = glyph->y_scale;
2428
2429
2430 /* First of all, scale the points */
David Turnerc8087482001-12-20 13:14:18 +00002431 if ( !hinting )
2432 for ( n = cur->n_points; n > 0; n--, vec++ )
2433 {
2434 vec->x = FT_MulFix( vec->x, x_scale );
2435 vec->y = FT_MulFix( vec->y, y_scale );
2436 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002437
2438 FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
2439
2440 /* Then scale the metrics */
2441 metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
2442 metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
2443
2444 metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale );
2445 metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale );
David Turnerbce29862001-12-14 14:52:58 +00002446
2447 if ( hinting )
2448 {
Werner Lemberg48c984b2002-03-30 16:41:09 +00002449 metrics->horiAdvance = ( metrics->horiAdvance + 32 ) & -64;
2450 metrics->vertAdvance = ( metrics->vertAdvance + 32 ) & -64;
David Turnerbce29862001-12-14 14:52:58 +00002451
Werner Lemberg5da9dd72001-12-16 08:17:33 +00002452 metrics->vertBearingX = ( metrics->vertBearingX + 32 ) & -64;
2453 metrics->vertBearingY = ( metrics->vertBearingY + 32 ) & -64;
David Turnerbce29862001-12-14 14:52:58 +00002454 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002455 }
2456
2457 /* compute the other metrics */
2458 FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
2459
2460 /* grid fit the bounding box if necessary */
2461 if ( hinting )
2462 {
2463 cbox.xMin &= -64;
2464 cbox.yMin &= -64;
2465 cbox.xMax = ( cbox.xMax + 63 ) & -64;
2466 cbox.yMax = ( cbox.yMax + 63 ) & -64;
2467 }
2468
2469 metrics->width = cbox.xMax - cbox.xMin;
2470 metrics->height = cbox.yMax - cbox.yMin;
2471
2472 metrics->horiBearingX = cbox.xMin;
2473 metrics->horiBearingY = cbox.yMax;
2474 }
2475 }
2476
2477 return error;
2478 }
2479
2480
2481/* END */