blob: 7ffc99afdf5e0ba985cf6719ddda8764b10c6498 [file] [log] [blame]
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001/***************************************************************************/
2/* */
3/* cffgload.c */
4/* */
5/* OpenType Glyph Loader (body). */
6/* */
Werner Lemberg415235d2001-06-28 17:49:10 +00007/* Copyright 1996-2001 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 Turnerc8087482001-12-20 13:14:18 +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 Turnerc8087482001-12-20 13:14:18 +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
249 builder->hints_globals = 0;
250 builder->hints_funcs = 0;
David Turner4d570242002-02-24 02:59:24 +0000251
David Turnerc8087482001-12-20 13:14:18 +0000252 if ( hinting && size )
253 {
254 builder->hints_globals = size->internal;
255 builder->hints_funcs = glyph->root.internal->glyph_hints;
256 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000257 }
258
259 if ( size )
260 {
261 builder->scale_x = size->metrics.x_scale;
262 builder->scale_y = size->metrics.y_scale;
263 }
264
265 builder->pos_x = 0;
266 builder->pos_y = 0;
267
268 builder->left_bearing.x = 0;
269 builder->left_bearing.y = 0;
270 builder->advance.x = 0;
271 builder->advance.y = 0;
272 }
273
274
275 /*************************************************************************/
276 /* */
277 /* <Function> */
David Turnerc8087482001-12-20 13:14:18 +0000278 /* CFF_Builder_Done */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000279 /* */
280 /* <Description> */
281 /* Finalizes a given glyph builder. Its contents can still be used */
282 /* after the call, but the function saves important information */
283 /* within the corresponding glyph slot. */
284 /* */
285 /* <Input> */
286 /* builder :: A pointer to the glyph builder to finalize. */
287 /* */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000288 static void
David Turnerc8087482001-12-20 13:14:18 +0000289 CFF_Builder_Done( CFF_Builder* builder )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000290 {
291 CFF_GlyphSlot glyph = builder->glyph;
292
293
294 if ( glyph )
295 glyph->root.outline = *builder->base;
296 }
297
298
299 /*************************************************************************/
300 /* */
301 /* <Function> */
Werner Lembergd573c7e2001-01-03 07:14:12 +0000302 /* cff_compute_bias */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000303 /* */
304 /* <Description> */
305 /* Computes the bias value in dependence of the number of glyph */
306 /* subroutines. */
307 /* */
308 /* <Input> */
309 /* num_subrs :: The number of glyph subroutines. */
310 /* */
311 /* <Return> */
312 /* The bias value. */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000313 static FT_Int
314 cff_compute_bias( FT_UInt num_subrs )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000315 {
316 FT_Int result;
317
318
319 if ( num_subrs < 1240 )
320 result = 107;
Werner Lembergcf24d512001-06-18 14:23:45 +0000321 else if ( num_subrs < 33900U )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000322 result = 1131;
323 else
Werner Lembergcf24d512001-06-18 14:23:45 +0000324 result = 32768U;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000325
326 return result;
327 }
328
329
330 /*************************************************************************/
331 /* */
332 /* <Function> */
Werner Lembergd573c7e2001-01-03 07:14:12 +0000333 /* CFF_Init_Decoder */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000334 /* */
335 /* <Description> */
336 /* Initializes a given glyph decoder. */
337 /* */
338 /* <InOut> */
339 /* decoder :: A pointer to the glyph builder to initialize. */
340 /* */
341 /* <Input> */
342 /* face :: The current face object. */
343 /* */
344 /* size :: The current size object. */
345 /* */
346 /* slot :: The current glyph object. */
347 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000348 FT_LOCAL_DEF( void )
Werner Lemberg93616ec2001-06-27 19:46:12 +0000349 CFF_Init_Decoder( CFF_Decoder* decoder,
350 TT_Face face,
351 CFF_Size size,
David Turnerc8087482001-12-20 13:14:18 +0000352 CFF_GlyphSlot slot,
353 FT_Bool hinting )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000354 {
David Turnerab4fc4d2002-03-14 08:57:10 +0000355 CFF_Font cff = (CFF_Font)face->extra.data;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000356
357
358 /* clear everything */
David Turnere459d742002-03-22 13:52:37 +0000359 FT_MEM_SET( decoder, 0, sizeof ( *decoder ) );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000360
361 /* initialize builder */
David Turnerc8087482001-12-20 13:14:18 +0000362 CFF_Builder_Init( &decoder->builder, face, size, slot, hinting );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000363
364 /* initialize Type2 decoder */
365 decoder->num_globals = cff->num_global_subrs;
366 decoder->globals = cff->global_subrs;
367 decoder->globals_bias = cff_compute_bias( decoder->num_globals );
368 }
369
370
371 /* this function is used to select the locals subrs array */
David Turnerbc82f1b2002-03-01 02:26:22 +0000372 FT_LOCAL_DEF( void )
Werner Lemberg93616ec2001-06-27 19:46:12 +0000373 CFF_Prepare_Decoder( CFF_Decoder* decoder,
374 FT_UInt glyph_index )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000375 {
David Turnerab4fc4d2002-03-14 08:57:10 +0000376 CFF_Font cff = (CFF_Font)decoder->builder.face->extra.data;
377 CFF_SubFont sub = &cff->top_font;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000378
379
380 /* manage CID fonts */
381 if ( cff->num_subfonts >= 1 )
382 {
383 FT_Byte fd_index = CFF_Get_FD( &cff->fd_select, glyph_index );
384
385
386 sub = cff->subfonts[fd_index];
387 }
388
389 decoder->num_locals = sub->num_local_subrs;
390 decoder->locals = sub->local_subrs;
391 decoder->locals_bias = cff_compute_bias( decoder->num_locals );
392
393 decoder->glyph_width = sub->private_dict.default_width;
394 decoder->nominal_width = sub->private_dict.nominal_width;
395 }
396
397
398 /* check that there is enough room for `count' more points */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000399 static FT_Error
400 check_points( CFF_Builder* builder,
401 FT_Int count )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000402 {
David Turnereba5ad42002-03-14 12:56:35 +0000403 return FT_GlyphLoader_CheckPoints( builder->loader, count, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000404 }
405
406
407 /* add a new point, do not check space */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000408 static void
409 add_point( CFF_Builder* builder,
410 FT_Pos x,
411 FT_Pos y,
412 FT_Byte flag )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000413 {
414 FT_Outline* outline = builder->current;
415
416
417 if ( builder->load_points )
418 {
419 FT_Vector* point = outline->points + outline->n_points;
420 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points;
421
422
423 point->x = x >> 16;
424 point->y = y >> 16;
Werner Lemberg8eb03532001-06-19 23:03:41 +0000425 *control = (FT_Byte)( flag ? FT_Curve_Tag_On : FT_Curve_Tag_Cubic );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000426
427 builder->last = *point;
428 }
429 outline->n_points++;
430 }
431
432
433 /* check space for a new on-curve point, then add it */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000434 static FT_Error
435 add_point1( CFF_Builder* builder,
436 FT_Pos x,
437 FT_Pos y )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000438 {
439 FT_Error error;
440
441
442 error = check_points( builder, 1 );
443 if ( !error )
444 add_point( builder, x, y, 1 );
445
446 return error;
447 }
448
449
450 /* check room for a new contour, then add it */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000451 static FT_Error
452 add_contour( CFF_Builder* builder )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000453 {
454 FT_Outline* outline = builder->current;
455 FT_Error error;
456
457
458 if ( !builder->load_points )
459 {
460 outline->n_contours++;
461 return CFF_Err_Ok;
462 }
463
David Turnereba5ad42002-03-14 12:56:35 +0000464 error = FT_GlyphLoader_CheckPoints( builder->loader, 0, 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000465 if ( !error )
466 {
467 if ( outline->n_contours > 0 )
Werner Lemberg8eb03532001-06-19 23:03:41 +0000468 outline->contours[outline->n_contours - 1] =
469 (short)( outline->n_points - 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000470
471 outline->n_contours++;
472 }
473
474 return error;
475 }
476
477
478 /* if a path was begun, add its first on-curve point */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000479 static FT_Error
480 start_point( CFF_Builder* builder,
481 FT_Pos x,
482 FT_Pos y )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000483 {
484 FT_Error error = 0;
485
486
487 /* test whether we are building a new contour */
488 if ( !builder->path_begun )
489 {
490 builder->path_begun = 1;
491 error = add_contour( builder );
492 if ( !error )
493 error = add_point1( builder, x, y );
494 }
495 return error;
496 }
497
498
499 /* close the current contour */
Werner Lemberg93616ec2001-06-27 19:46:12 +0000500 static void
501 close_contour( CFF_Builder* builder )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000502 {
503 FT_Outline* outline = builder->current;
504
505 /* XXXX: We must not include the last point in the path if it */
506 /* is located on the first point. */
507 if ( outline->n_points > 1 )
508 {
509 FT_Int first = 0;
510 FT_Vector* p1 = outline->points + first;
511 FT_Vector* p2 = outline->points + outline->n_points - 1;
512 FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1;
513
514
515 if ( outline->n_contours > 1 )
516 {
517 first = outline->contours[outline->n_contours - 2] + 1;
518 p1 = outline->points + first;
519 }
520
521 /* `delete' last point only if it coincides with the first */
522 /* point and it is not a control point (which can happen). */
523 if ( p1->x == p2->x && p1->y == p2->y )
524 if ( *control == FT_Curve_Tag_On )
525 outline->n_points--;
526 }
527
528 if ( outline->n_contours > 0 )
Werner Lemberg8eb03532001-06-19 23:03:41 +0000529 outline->contours[outline->n_contours - 1] =
530 (short)( outline->n_points - 1 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000531 }
532
533
Werner Lemberg93616ec2001-06-27 19:46:12 +0000534 static FT_Int
David Turnerab4fc4d2002-03-14 08:57:10 +0000535 cff_lookup_glyph_by_stdcharcode( CFF_Font cff,
Werner Lemberg93616ec2001-06-27 19:46:12 +0000536 FT_Int charcode )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000537 {
538 FT_UInt n;
539 FT_UShort glyph_sid;
540
541
542 /* check range of standard char code */
543 if ( charcode < 0 || charcode > 255 )
544 return -1;
545
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000546 /* Get code to SID mapping from `cff_standard_encoding'. */
David Turnerc8087482001-12-20 13:14:18 +0000547 glyph_sid = CFF_Get_Standard_Encoding( (FT_UInt)charcode );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000548
549 for ( n = 0; n < cff->num_glyphs; n++ )
550 {
551 if ( cff->charset.sids[n] == glyph_sid )
552 return n;
553 }
554
555 return -1;
556 }
557
558
Werner Lemberg93616ec2001-06-27 19:46:12 +0000559 static FT_Error
560 cff_operator_seac( CFF_Decoder* decoder,
561 FT_Pos adx,
562 FT_Pos ady,
563 FT_Int bchar,
564 FT_Int achar )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000565 {
566 FT_Error error;
567 FT_Int bchar_index, achar_index, n_base_points;
568 FT_Outline* base = decoder->builder.base;
569 TT_Face face = decoder->builder.face;
David Turnerab4fc4d2002-03-14 08:57:10 +0000570 CFF_Font cff = (CFF_Font)(face->extra.data);
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000571 FT_Vector left_bearing, advance;
572 FT_Byte* charstring;
573 FT_ULong charstring_len;
574
575
576 bchar_index = cff_lookup_glyph_by_stdcharcode( cff, bchar );
577 achar_index = cff_lookup_glyph_by_stdcharcode( cff, achar );
578
579 if ( bchar_index < 0 || achar_index < 0 )
580 {
581 FT_ERROR(( "cff_operator_seac:" ));
582 FT_ERROR(( " invalid seac character code arguments\n" ));
583 return CFF_Err_Syntax_Error;
584 }
585
586 /* If we are trying to load a composite glyph, do not load the */
587 /* accent character and return the array of subglyphs. */
588 if ( decoder->builder.no_recurse )
589 {
590 FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph;
David Turner4d570242002-02-24 02:59:24 +0000591 FT_GlyphLoader loader = glyph->internal->loader;
David Turnereba5ad42002-03-14 12:56:35 +0000592 FT_SubGlyph subg;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000593
594
595 /* reallocate subglyph array if necessary */
David Turnereba5ad42002-03-14 12:56:35 +0000596 error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000597 if ( error )
598 goto Exit;
599
600 subg = loader->current.subglyphs;
601
602 /* subglyph 0 = base character */
603 subg->index = bchar_index;
604 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES |
605 FT_SUBGLYPH_FLAG_USE_MY_METRICS;
606 subg->arg1 = 0;
607 subg->arg2 = 0;
608 subg++;
609
610 /* subglyph 1 = accent character */
611 subg->index = achar_index;
612 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
613 subg->arg1 = adx;
614 subg->arg2 = ady;
615
616 /* set up remaining glyph fields */
617 glyph->num_subglyphs = 2;
618 glyph->subglyphs = loader->base.subglyphs;
619 glyph->format = ft_glyph_format_composite;
620
621 loader->current.num_subglyphs = 2;
622 }
623
624 /* First load `bchar' in builder */
625 error = CFF_Access_Element( &cff->charstrings_index, bchar_index,
626 &charstring, &charstring_len );
627 if ( !error )
628 {
629 error = CFF_Parse_CharStrings( decoder, charstring, charstring_len );
630
631 if ( error )
632 goto Exit;
633
634 CFF_Forget_Element( &cff->charstrings_index, &charstring );
635 }
636
637 n_base_points = base->n_points;
638
639 /* Save the left bearing and width of the base character */
640 /* as they will be erased by the next load. */
641
642 left_bearing = decoder->builder.left_bearing;
643 advance = decoder->builder.advance;
644
645 decoder->builder.left_bearing.x = 0;
646 decoder->builder.left_bearing.y = 0;
647
648 /* Now load `achar' on top of the base outline. */
649 error = CFF_Access_Element( &cff->charstrings_index, achar_index,
650 &charstring, &charstring_len );
651 if ( !error )
652 {
653 error = CFF_Parse_CharStrings( decoder, charstring, charstring_len );
654
655 if ( error )
656 goto Exit;
657
658 CFF_Forget_Element( &cff->charstrings_index, &charstring );
659 }
660
661 /* Restore the left side bearing and advance width */
662 /* of the base character. */
663 decoder->builder.left_bearing = left_bearing;
664 decoder->builder.advance = advance;
665
666 /* Finally, move the accent. */
667 if ( decoder->builder.load_points )
668 {
669 FT_Outline dummy;
670
671
Werner Lemberg8eb03532001-06-19 23:03:41 +0000672 dummy.n_points = (short)( base->n_points - n_base_points );
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000673 dummy.points = base->points + n_base_points;
674
675 FT_Outline_Translate( &dummy, adx, ady );
676 }
677
678 Exit:
679 return error;
680 }
681
682
683 /*************************************************************************/
684 /* */
685 /* <Function> */
Werner Lembergd573c7e2001-01-03 07:14:12 +0000686 /* CFF_Parse_CharStrings */
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000687 /* */
688 /* <Description> */
689 /* Parses a given Type 2 charstrings program. */
690 /* */
691 /* <InOut> */
692 /* decoder :: The current Type 1 decoder. */
693 /* */
694 /* <Input> */
695 /* charstring_base :: The base of the charstring stream. */
696 /* */
697 /* charstring_len :: The length in bytes of the charstring stream. */
698 /* */
699 /* <Return> */
700 /* FreeType error code. 0 means success. */
701 /* */
David Turnerbc82f1b2002-03-01 02:26:22 +0000702 FT_LOCAL_DEF( FT_Error )
Werner Lemberg93616ec2001-06-27 19:46:12 +0000703 CFF_Parse_CharStrings( CFF_Decoder* decoder,
704 FT_Byte* charstring_base,
705 FT_Int charstring_len )
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000706 {
Werner Lembergd573c7e2001-01-03 07:14:12 +0000707 FT_Error error;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000708 CFF_Decoder_Zone* zone;
Werner Lembergd573c7e2001-01-03 07:14:12 +0000709 FT_Byte* ip;
710 FT_Byte* limit;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000711 CFF_Builder* builder = &decoder->builder;
Werner Lembergd573c7e2001-01-03 07:14:12 +0000712 FT_Pos x, y;
713 FT_Fixed seed;
714 FT_Fixed* stack;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000715
David Turner2b30c172001-12-12 16:07:29 +0000716 T2_Hints_Funcs hinter;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000717
Werner Lemberg5da9dd72001-12-16 08:17:33 +0000718
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000719 /* set default width */
720 decoder->num_hints = 0;
721 decoder->read_width = 1;
722
723 /* compute random seed from stack address of parameter */
724 seed = (FT_Fixed)(char*)&seed ^
725 (FT_Fixed)(char*)&decoder ^
726 (FT_Fixed)(char*)&charstring_base;
727 seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFF;
728 if ( seed == 0 )
729 seed = 0x7384;
730
731 /* initialize the decoder */
732 decoder->top = decoder->stack;
733 decoder->zone = decoder->zones;
734 zone = decoder->zones;
735 stack = decoder->top;
736
David Turner2b30c172001-12-12 16:07:29 +0000737 hinter = (T2_Hints_Funcs) builder->hints_funcs;
738
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000739 builder->path_begun = 0;
740
741 zone->base = charstring_base;
742 limit = zone->limit = charstring_base + charstring_len;
743 ip = zone->cursor = zone->base;
744
Werner Lembergcf24d512001-06-18 14:23:45 +0000745 error = CFF_Err_Ok;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000746
747 x = builder->pos_x;
748 y = builder->pos_y;
749
David Turner2b30c172001-12-12 16:07:29 +0000750 /* begin hints recording session, if any */
751 if ( hinter )
752 hinter->open( hinter->hints );
753
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000754 /* now, execute loop */
755 while ( ip < limit )
756 {
757 CFF_Operator op;
Werner Lembergd573c7e2001-01-03 07:14:12 +0000758 FT_Byte v;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000759
760
761 /********************************************************************/
762 /* */
763 /* Decode operator or operand */
764 /* */
765 v = *ip++;
766 if ( v >= 32 || v == 28 )
767 {
768 FT_Int shift = 16;
769 FT_Int32 val;
770
771
772 /* this is an operand, push it on the stack */
773 if ( v == 28 )
774 {
775 if ( ip + 1 >= limit )
776 goto Syntax_Error;
777 val = (FT_Short)( ( (FT_Short)ip[0] << 8 ) | ip[1] );
778 ip += 2;
779 }
780 else if ( v < 247 )
781 val = (FT_Long)v - 139;
782 else if ( v < 251 )
783 {
784 if ( ip >= limit )
785 goto Syntax_Error;
786 val = ( (FT_Long)v - 247 ) * 256 + *ip++ + 108;
787 }
788 else if ( v < 255 )
789 {
790 if ( ip >= limit )
791 goto Syntax_Error;
792 val = -( (FT_Long)v - 251 ) * 256 - *ip++ - 108;
793 }
794 else
795 {
796 if ( ip + 3 >= limit )
797 goto Syntax_Error;
798 val = ( (FT_Int32)ip[0] << 24 ) |
799 ( (FT_Int32)ip[1] << 16 ) |
800 ( (FT_Int32)ip[2] << 8 ) |
801 ip[3];
802 ip += 4;
803 shift = 0;
804 }
805 if ( decoder->top - stack >= CFF_MAX_OPERANDS )
806 goto Stack_Overflow;
807
808 val <<= shift;
809 *decoder->top++ = val;
810
811#ifdef FT_DEBUG_LEVEL_TRACE
812 if ( !( val & 0xFFFF ) )
813 FT_TRACE4(( " %d", (FT_Int32)( val >> 16 ) ));
814 else
Tom Kacvinsky8316bc52001-03-16 13:35:56 +0000815 FT_TRACE4(( " %.2f", val / 65536.0 ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000816#endif
817
818 }
819 else
820 {
821 FT_Fixed* args = decoder->top;
822 FT_Int num_args = args - decoder->stack;
823 FT_Int req_args;
824
825
826 /* find operator */
827 op = cff_op_unknown;
828
829 switch ( v )
830 {
831 case 1:
832 op = cff_op_hstem;
833 break;
834 case 3:
835 op = cff_op_vstem;
836 break;
837 case 4:
838 op = cff_op_vmoveto;
839 break;
840 case 5:
841 op = cff_op_rlineto;
842 break;
843 case 6:
844 op = cff_op_hlineto;
845 break;
846 case 7:
847 op = cff_op_vlineto;
848 break;
849 case 8:
850 op = cff_op_rrcurveto;
851 break;
852 case 10:
853 op = cff_op_callsubr;
854 break;
855 case 11:
856 op = cff_op_return;
857 break;
858 case 12:
859 {
860 if ( ip >= limit )
861 goto Syntax_Error;
862 v = *ip++;
863
864 switch ( v )
865 {
Tom Kacvinsky8316bc52001-03-16 13:35:56 +0000866 case 0:
867 op = cff_op_dotsection;
868 break;
Tom Kacvinskycd92b112001-01-03 00:15:00 +0000869 case 3:
870 op = cff_op_and;
871 break;
872 case 4:
873 op = cff_op_or;
874 break;
875 case 5:
876 op = cff_op_not;
877 break;
878 case 8:
879 op = cff_op_store;
880 break;
881 case 9:
882 op = cff_op_abs;
883 break;
884 case 10:
885 op = cff_op_add;
886 break;
887 case 11:
888 op = cff_op_sub;
889 break;
890 case 12:
891 op = cff_op_div;
892 break;
893 case 13:
894 op = cff_op_load;
895 break;
896 case 14:
897 op = cff_op_neg;
898 break;
899 case 15:
900 op = cff_op_eq;
901 break;
902 case 18:
903 op = cff_op_drop;
904 break;
905 case 20:
906 op = cff_op_put;
907 break;
908 case 21:
909 op = cff_op_get;
910 break;
911 case 22:
912 op = cff_op_ifelse;
913 break;
914 case 23:
915 op = cff_op_random;
916 break;
917 case 24:
918 op = cff_op_mul;
919 break;
920 case 26:
921 op = cff_op_sqrt;
922 break;
923 case 27:
924 op = cff_op_dup;
925 break;
926 case 28:
927 op = cff_op_exch;
928 break;
929 case 29:
930 op = cff_op_index;
931 break;
932 case 30:
933 op = cff_op_roll;
934 break;
935 case 34:
936 op = cff_op_hflex;
937 break;
938 case 35:
939 op = cff_op_flex;
940 break;
941 case 36:
942 op = cff_op_hflex1;
943 break;
944 case 37:
945 op = cff_op_flex1;
946 break;
947 default:
948 /* decrement ip for syntax error message */
949 ip--;
950 }
951 }
952 break;
953 case 14:
954 op = cff_op_endchar;
955 break;
956 case 16:
957 op = cff_op_blend;
958 break;
959 case 18:
960 op = cff_op_hstemhm;
961 break;
962 case 19:
963 op = cff_op_hintmask;
964 break;
965 case 20:
966 op = cff_op_cntrmask;
967 break;
968 case 21:
969 op = cff_op_rmoveto;
970 break;
971 case 22:
972 op = cff_op_hmoveto;
973 break;
974 case 23:
975 op = cff_op_vstemhm;
976 break;
977 case 24:
978 op = cff_op_rcurveline;
979 break;
980 case 25:
981 op = cff_op_rlinecurve;
982 break;
983 case 26:
984 op = cff_op_vvcurveto;
985 break;
986 case 27:
987 op = cff_op_hhcurveto;
988 break;
989 case 29:
990 op = cff_op_callgsubr;
991 break;
992 case 30:
993 op = cff_op_vhcurveto;
994 break;
995 case 31:
996 op = cff_op_hvcurveto;
997 break;
998 default:
999 ;
1000 }
1001 if ( op == cff_op_unknown )
1002 goto Syntax_Error;
1003
1004 /* check arguments */
1005 req_args = cff_argument_counts[op];
1006 if ( req_args & CFF_COUNT_CHECK_WIDTH )
1007 {
1008 args = stack;
1009
1010 if ( num_args > 0 && decoder->read_width )
1011 {
1012 /* If `nominal_width' is non-zero, the number is really a */
1013 /* difference against `nominal_width'. Else, the number here */
1014 /* is truly a width, not a difference against `nominal_width'. */
1015 /* If the font does not set `nominal_width', then */
1016 /* `nominal_width' defaults to zero, and so we can set */
1017 /* `glyph_width' to `nominal_width' plus number on the stack */
1018 /* -- for either case. */
1019
1020 FT_Int set_width_ok;
1021
1022
1023 switch ( op )
1024 {
1025 case cff_op_hmoveto:
1026 case cff_op_vmoveto:
1027 set_width_ok = num_args & 2;
1028 break;
1029
1030 case cff_op_hstem:
1031 case cff_op_vstem:
1032 case cff_op_hstemhm:
1033 case cff_op_vstemhm:
1034 case cff_op_rmoveto:
1035 set_width_ok = num_args & 1;
1036 break;
1037
1038 case cff_op_endchar:
1039 /* If there is a width specified for endchar, we either have */
1040 /* 1 argument or 5 arguments. We like to argue. */
1041 set_width_ok = ( ( num_args == 5 ) || ( num_args == 1 ) );
1042 break;
1043
1044 default:
1045 set_width_ok = 0;
1046 break;
1047 }
1048
1049 if ( set_width_ok )
1050 {
1051 decoder->glyph_width = decoder->nominal_width +
1052 ( stack[0] >> 16 );
1053
1054 /* Consumed an argument. */
1055 num_args--;
1056 args++;
1057 }
1058 }
1059
1060 decoder->read_width = 0;
1061 req_args = 0;
1062 }
1063
1064 req_args &= 15;
1065 if ( num_args < req_args )
1066 goto Stack_Underflow;
1067 args -= req_args;
1068 num_args -= req_args;
1069
1070 switch ( op )
1071 {
1072 case cff_op_hstem:
1073 case cff_op_vstem:
1074 case cff_op_hstemhm:
1075 case cff_op_vstemhm:
David Turner2b30c172001-12-12 16:07:29 +00001076 /* the number of arguments is always even here */
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001077 FT_TRACE4(( op == cff_op_hstem ? " hstem" :
David Turner2b30c172001-12-12 16:07:29 +00001078 ( op == cff_op_vstem ? " vstem" :
Werner Lemberg5da9dd72001-12-16 08:17:33 +00001079 ( op == cff_op_hstemhm ? " hstemhm" : " vstemhm" ) ) ));
David Turnerbce29862001-12-14 14:52:58 +00001080
David Turner2b30c172001-12-12 16:07:29 +00001081 if ( hinter )
1082 hinter->stems( hinter->hints,
David Turner7c0d2082001-12-21 15:59:43 +00001083 ( op == cff_op_hstem || op == cff_op_hstemhm ),
Werner Lemberg5da9dd72001-12-16 08:17:33 +00001084 num_args / 2,
David Turner2b30c172001-12-12 16:07:29 +00001085 args );
David Turnerbce29862001-12-14 14:52:58 +00001086
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001087 decoder->num_hints += num_args / 2;
1088 args = stack;
1089 break;
David Turnerbce29862001-12-14 14:52:58 +00001090
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001091 case cff_op_hintmask:
1092 case cff_op_cntrmask:
David Turner2b30c172001-12-12 16:07:29 +00001093 FT_TRACE4(( op == cff_op_hintmask ? " hintmask" : " cntrmask" ));
David Turner4d570242002-02-24 02:59:24 +00001094
Werner Lembergaf594e62001-12-22 14:38:40 +00001095 /* implement vstem when needed -- */
David Turnerb5c7de52001-12-21 21:21:13 +00001096 /* the specification doesn't say it, but this also works */
Werner Lembergaf594e62001-12-22 14:38:40 +00001097 /* with the 'cntrmask' operator */
David Turnerb5c7de52001-12-21 21:21:13 +00001098 /* */
David Turnerc8087482001-12-20 13:14:18 +00001099 if ( num_args > 0 )
1100 {
1101 if ( hinter )
1102 hinter->stems( hinter->hints,
David Turner7c0d2082001-12-21 15:59:43 +00001103 0,
David Turnerc8087482001-12-20 13:14:18 +00001104 num_args / 2,
1105 args );
David Turner4d570242002-02-24 02:59:24 +00001106
David Turnerc8087482001-12-20 13:14:18 +00001107 decoder->num_hints += num_args / 2;
1108 }
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001109
David Turner2b30c172001-12-12 16:07:29 +00001110 if ( hinter )
1111 {
1112 if ( op == cff_op_hintmask )
1113 hinter->hintmask( hinter->hints,
1114 builder->current->n_points,
David Turnerc8087482001-12-20 13:14:18 +00001115 decoder->num_hints,
David Turner2b30c172001-12-12 16:07:29 +00001116 ip );
1117 else
1118 hinter->counter( hinter->hints,
David Turnerc8087482001-12-20 13:14:18 +00001119 decoder->num_hints,
David Turner2b30c172001-12-12 16:07:29 +00001120 ip );
1121 }
David Turnerbce29862001-12-14 14:52:58 +00001122
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001123#ifdef FT_DEBUG_LEVEL_TRACE
1124 {
1125 FT_UInt maskbyte;
1126
1127 FT_TRACE4(( " " ));
1128
Werner Lemberg521a2d72001-03-20 22:58:56 +00001129 for ( maskbyte = 0;
David Turner6d4fbec2001-04-20 08:50:36 +00001130 maskbyte < (FT_UInt)(( decoder->num_hints + 7 ) >> 3);
Werner Lemberg521a2d72001-03-20 22:58:56 +00001131 maskbyte++, ip++ )
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001132 {
1133 FT_TRACE4(( "%02X", *ip ));
1134 }
1135
1136 }
1137#else
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001138 ip += ( decoder->num_hints + 7 ) >> 3;
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001139#endif
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001140 if ( ip >= limit )
1141 goto Syntax_Error;
1142 args = stack;
1143 break;
1144
1145 case cff_op_rmoveto:
1146 FT_TRACE4(( " rmoveto" ));
1147
1148 close_contour( builder );
1149 builder->path_begun = 0;
1150 x += args[0];
1151 y += args[1];
1152 args = stack;
1153 break;
1154
1155 case cff_op_vmoveto:
1156 FT_TRACE4(( " vmoveto" ));
1157
1158 close_contour( builder );
1159 builder->path_begun = 0;
1160 y += args[0];
1161 args = stack;
1162 break;
1163
1164 case cff_op_hmoveto:
1165 FT_TRACE4(( " hmoveto" ));
1166
1167 close_contour( builder );
1168 builder->path_begun = 0;
1169 x += args[0];
1170 args = stack;
1171 break;
1172
1173 case cff_op_rlineto:
1174 FT_TRACE4(( " rlineto" ));
1175
1176 if ( start_point ( builder, x, y ) ||
1177 check_points( builder, num_args / 2 ) )
1178 goto Memory_Error;
1179
1180 if ( num_args < 2 || num_args & 1 )
1181 goto Stack_Underflow;
1182
1183 args = stack;
1184 while ( args < decoder->top )
1185 {
1186 x += args[0];
1187 y += args[1];
1188 add_point( builder, x, y, 1 );
1189 args += 2;
1190 }
1191 args = stack;
1192 break;
1193
1194 case cff_op_hlineto:
1195 case cff_op_vlineto:
1196 {
1197 FT_Int phase = ( op == cff_op_hlineto );
1198
1199
1200 FT_TRACE4(( op == cff_op_hlineto ? " hlineto"
Werner Lembergd573c7e2001-01-03 07:14:12 +00001201 : " vlineto" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001202
1203 if ( start_point ( builder, x, y ) ||
1204 check_points( builder, num_args ) )
1205 goto Memory_Error;
1206
1207 args = stack;
1208 while (args < decoder->top )
1209 {
1210 if ( phase )
1211 x += args[0];
1212 else
1213 y += args[0];
1214
1215 if ( add_point1( builder, x, y ) )
1216 goto Memory_Error;
1217
1218 args++;
1219 phase ^= 1;
1220 }
1221 args = stack;
1222 }
1223 break;
1224
1225 case cff_op_rrcurveto:
1226 FT_TRACE4(( " rrcurveto" ));
1227
1228 /* check number of arguments; must be a multiple of 6 */
1229 if ( num_args % 6 != 0 )
1230 goto Stack_Underflow;
1231
1232 if ( start_point ( builder, x, y ) ||
1233 check_points( builder, num_args / 2 ) )
1234 goto Memory_Error;
1235
1236 args = stack;
1237 while ( args < decoder->top )
1238 {
1239 x += args[0];
1240 y += args[1];
1241 add_point( builder, x, y, 0 );
1242 x += args[2];
1243 y += args[3];
1244 add_point( builder, x, y, 0 );
1245 x += args[4];
1246 y += args[5];
1247 add_point( builder, x, y, 1 );
1248 args += 6;
1249 }
1250 args = stack;
1251 break;
1252
1253 case cff_op_vvcurveto:
1254 FT_TRACE4(( " vvcurveto" ));
1255
1256 if ( start_point ( builder, x, y ) )
1257 goto Memory_Error;
1258
1259 args = stack;
1260 if ( num_args & 1 )
1261 {
1262 x += args[0];
1263 args++;
1264 num_args--;
1265 }
1266
1267 if ( num_args % 4 != 0 )
1268 goto Stack_Underflow;
1269
1270 if ( check_points( builder, 3 * ( num_args / 4 ) ) )
1271 goto Memory_Error;
1272
1273 while ( args < decoder->top )
1274 {
1275 y += args[0];
1276 add_point( builder, x, y, 0 );
1277 x += args[1];
1278 y += args[2];
1279 add_point( builder, x, y, 0 );
1280 y += args[3];
1281 add_point( builder, x, y, 1 );
1282 args += 4;
1283 }
1284 args = stack;
1285 break;
1286
1287 case cff_op_hhcurveto:
1288 FT_TRACE4(( " hhcurveto" ));
1289
1290 if ( start_point ( builder, x, y ) )
1291 goto Memory_Error;
1292
1293 args = stack;
1294 if ( num_args & 1 )
1295 {
1296 y += args[0];
1297 args++;
1298 num_args--;
1299 }
1300
1301 if ( num_args % 4 != 0 )
1302 goto Stack_Underflow;
1303
1304 if ( check_points( builder, 3 * ( num_args / 4 ) ) )
1305 goto Memory_Error;
1306
1307 while ( args < decoder->top )
1308 {
1309 x += args[0];
1310 add_point( builder, x, y, 0 );
1311 x += args[1];
1312 y += args[2];
1313 add_point( builder, x, y, 0 );
1314 x += args[3];
1315 add_point( builder, x, y, 1 );
1316 args += 4;
1317 }
1318 args = stack;
1319 break;
1320
1321 case cff_op_vhcurveto:
1322 case cff_op_hvcurveto:
1323 {
1324 FT_Int phase;
1325
1326
1327 FT_TRACE4(( op == cff_op_vhcurveto ? " vhcurveto"
Werner Lembergd573c7e2001-01-03 07:14:12 +00001328 : " hvcurveto" ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001329
1330 if ( start_point ( builder, x, y ) )
1331 goto Memory_Error;
1332
1333 args = stack;
1334 if (num_args < 4 || ( num_args % 4 ) > 1 )
1335 goto Stack_Underflow;
1336
1337 if ( check_points( builder, ( num_args / 4 ) * 3 ) )
1338 goto Stack_Underflow;
1339
1340 phase = ( op == cff_op_hvcurveto );
1341
1342 while ( num_args >= 4 )
1343 {
1344 num_args -= 4;
1345 if ( phase )
1346 {
1347 x += args[0];
1348 add_point( builder, x, y, 0 );
1349 x += args[1];
1350 y += args[2];
1351 add_point( builder, x, y, 0 );
1352 y += args[3];
1353 if ( num_args == 1 )
1354 x += args[4];
1355 add_point( builder, x, y, 1 );
1356 }
1357 else
1358 {
1359 y += args[0];
1360 add_point( builder, x, y, 0 );
1361 x += args[1];
1362 y += args[2];
1363 add_point( builder, x, y, 0 );
1364 x += args[3];
1365 if ( num_args == 1 )
1366 y += args[4];
1367 add_point( builder, x, y, 1 );
1368 }
1369 args += 4;
1370 phase ^= 1;
1371 }
1372 args = stack;
1373 }
1374 break;
1375
1376 case cff_op_rlinecurve:
1377 {
1378 FT_Int num_lines = ( num_args - 6 ) / 2;
1379
1380
1381 FT_TRACE4(( " rlinecurve" ));
1382
1383 if ( num_args < 8 || ( num_args - 6 ) & 1 )
1384 goto Stack_Underflow;
1385
1386 if ( start_point( builder, x, y ) ||
1387 check_points( builder, num_lines + 3 ) )
1388 goto Memory_Error;
1389
1390 args = stack;
1391
1392 /* first, add the line segments */
1393 while ( num_lines > 0 )
1394 {
1395 x += args[0];
1396 y += args[1];
1397 add_point( builder, x, y, 1 );
1398 args += 2;
1399 num_lines--;
1400 }
1401
1402 /* then the curve */
1403 x += args[0];
1404 y += args[1];
1405 add_point( builder, x, y, 0 );
1406 x += args[2];
1407 y += args[3];
1408 add_point( builder, x, y, 0 );
1409 x += args[4];
1410 y += args[5];
1411 add_point( builder, x, y, 1 );
1412 args = stack;
1413 }
1414 break;
1415
1416 case cff_op_rcurveline:
1417 {
1418 FT_Int num_curves = ( num_args - 2 ) / 6;
1419
1420
1421 FT_TRACE4(( " rcurveline" ));
1422
1423 if ( num_args < 8 || ( num_args - 2 ) % 6 )
1424 goto Stack_Underflow;
1425
1426 if ( start_point ( builder, x, y ) ||
1427 check_points( builder, num_curves*3 + 2 ) )
1428 goto Memory_Error;
1429
1430 args = stack;
1431
1432 /* first, add the curves */
1433 while ( num_curves > 0 )
1434 {
1435 x += args[0];
1436 y += args[1];
1437 add_point( builder, x, y, 0 );
1438 x += args[2];
1439 y += args[3];
1440 add_point( builder, x, y, 0 );
1441 x += args[4];
1442 y += args[5];
1443 add_point( builder, x, y, 1 );
1444 args += 6;
1445 num_curves--;
1446 }
1447
1448 /* then the final line */
1449 x += args[0];
1450 y += args[1];
1451 add_point( builder, x, y, 1 );
1452 args = stack;
1453 }
1454 break;
1455
1456 case cff_op_hflex1:
1457 {
1458 FT_Pos start_y;
1459
1460
1461 FT_TRACE4(( " hflex1" ));
1462
1463 args = stack;
1464
1465 /* adding five more points; 4 control points, 1 on-curve point */
1466 /* make sure we have enough space for the start point if it */
1467 /* needs to be added.. */
1468 if ( start_point( builder, x, y ) ||
1469 check_points( builder, 6 ) )
1470 goto Memory_Error;
1471
1472 /* Record the starting point's y postion for later use */
1473 start_y = y;
1474
1475 /* first control point */
1476 x += args[0];
1477 y += args[1];
1478 add_point( builder, x, y, 0 );
1479
1480 /* second control point */
1481 x += args[2];
1482 y += args[3];
1483 add_point( builder, x, y, 0 );
1484
1485 /* join point; on curve, with y-value the same as the last */
1486 /* control point's y-value */
1487 x += args[4];
1488 add_point( builder, x, y, 1 );
1489
1490 /* third control point, with y-value the same as the join */
1491 /* point's y-value */
1492 x += args[5];
1493 add_point( builder, x, y, 0 );
1494
1495 /* fourth control point */
1496 x += args[6];
1497 y += args[7];
1498 add_point( builder, x, y, 0 );
1499
1500 /* ending point, with y-value the same as the start */
1501 x += args[8];
1502 y = start_y;
1503 add_point( builder, x, y, 1 );
1504
1505 args = stack;
1506 break;
1507 }
1508
1509 case cff_op_hflex:
1510 {
1511 FT_Pos start_y;
1512
1513
1514 FT_TRACE4(( " hflex" ));
1515
1516 args = stack;
1517
1518 /* adding six more points; 4 control points, 2 on-curve points */
1519 if ( start_point( builder, x, y ) ||
1520 check_points ( builder, 6 ) )
1521 goto Memory_Error;
1522
1523 /* record the starting point's y-position for later use */
1524 start_y = y;
1525
1526 /* first control point */
1527 x += args[0];
1528 add_point( builder, x, y, 0 );
1529
1530 /* second control point */
1531 x += args[1];
1532 y += args[2];
1533 add_point( builder, x, y, 0 );
1534
1535 /* join point; on curve, with y-value the same as the last */
1536 /* control point's y-value */
1537 x += args[3];
1538 add_point( builder, x, y, 1 );
1539
1540 /* third control point, with y-value the same as the join */
1541 /* point's y-value */
1542 x += args[4];
1543 add_point( builder, x, y, 0 );
1544
1545 /* fourth control point */
1546 x += args[5];
1547 y = start_y;
1548 add_point( builder, x, y, 0 );
1549
1550 /* ending point, with y-value the same as the start point's */
1551 /* y-value -- we don't add this point, though */
1552 x += args[6];
1553 add_point( builder, x, y, 1 );
1554
1555 args = stack;
1556 break;
1557 }
1558
1559 case cff_op_flex1:
1560 {
1561 FT_Pos start_x, start_y; /* record start x, y values for alter */
1562 /* use */
1563 FT_Int dx = 0, dy = 0; /* used in horizontal/vertical */
1564 /* algorithm below */
1565 FT_Int horizontal, count;
1566
1567
1568 FT_TRACE4(( " flex1" ));
1569
1570 /* adding six more points; 4 control points, 2 on-curve points */
1571 if ( start_point( builder, x, y ) ||
1572 check_points( builder, 6 ) )
1573 goto Memory_Error;
1574
1575 /* record the starting point's x, y postion for later use */
1576 start_x = x;
1577 start_y = y;
1578
1579 /* XXX: figure out whether this is supposed to be a horizontal */
1580 /* or vertical flex; the Type 2 specification is vague... */
1581
1582 args = stack;
1583
1584 /* grab up to the last argument */
1585 for ( count = 5; count > 0; count-- )
1586 {
1587 dx += args[0];
1588 dy += args[1];
1589 args += 2;
1590 }
1591
1592 /* rewind */
1593 args = stack;
1594
1595 if ( dx < 0 ) dx = -dx;
1596 if ( dy < 0 ) dy = -dy;
1597
1598 /* strange test, but here it is... */
1599 horizontal = ( dx > dy );
1600
1601 for ( count = 5; count > 0; count-- )
1602 {
1603 x += args[0];
1604 y += args[1];
1605 add_point( builder, x, y, (FT_Bool)( count == 3 ) );
1606 args += 2;
1607 }
1608
1609 /* is last operand an x- or y-delta? */
1610 if ( horizontal )
1611 {
1612 x += args[0];
1613 y = start_y;
1614 }
1615 else
1616 {
1617 x = start_x;
1618 y += args[0];
1619 }
1620
1621 add_point( builder, x, y, 1 );
1622
1623 args = stack;
1624 break;
1625 }
1626
1627 case cff_op_flex:
1628 {
1629 FT_UInt count;
1630
1631
1632 FT_TRACE4(( " flex" ));
1633
1634 if ( start_point( builder, x, y ) ||
1635 check_points( builder, 6 ) )
1636 goto Memory_Error;
1637
1638 args = stack;
1639 for ( count = 6; count > 0; count-- )
1640 {
1641 x += args[0];
1642 y += args[1];
1643 add_point( builder, x, y,
1644 (FT_Bool)( count == 3 || count == 0 ) );
1645 args += 2;
1646 }
1647
1648 args = stack;
1649 }
1650 break;
1651
1652 case cff_op_endchar:
1653 FT_TRACE4(( " endchar" ));
1654
1655 /* We are going to emulate the seac operator. */
1656 if ( num_args == 4 )
1657 {
Werner Lembergd573c7e2001-01-03 07:14:12 +00001658 error = cff_operator_seac( decoder,
1659 args[0] >> 16, args[1] >> 16,
1660 args[2] >> 16, args[3] >> 16 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001661 args += 4;
1662 }
1663
1664 if ( !error )
1665 error = CFF_Err_Ok;
1666
1667 close_contour( builder );
1668
David Turner2b30c172001-12-12 16:07:29 +00001669 /* close hints recording session */
1670 if ( hinter )
1671 {
Werner Lemberg5da9dd72001-12-16 08:17:33 +00001672 if (hinter->close( hinter->hints, builder->current->n_points ) )
David Turner2b30c172001-12-12 16:07:29 +00001673 goto Syntax_Error;
David Turnerbce29862001-12-14 14:52:58 +00001674
David Turner2b30c172001-12-12 16:07:29 +00001675 /* apply hints to the loaded glyph outline now */
1676 hinter->apply( hinter->hints,
1677 builder->current,
1678 (PSH_Globals)builder->hints_globals );
1679 }
1680
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001681 /* add current outline to the glyph slot */
1682 FT_GlyphLoader_Add( builder->loader );
1683
1684 /* return now! */
1685 FT_TRACE4(( "\n\n" ));
1686 return error;
1687
1688 case cff_op_abs:
1689 FT_TRACE4(( " abs" ));
1690
1691 if ( args[0] < 0 )
1692 args[0] = -args[0];
1693 args++;
1694 break;
1695
1696 case cff_op_add:
1697 FT_TRACE4(( " add" ));
1698
1699 args[0] += args[1];
1700 args++;
1701 break;
1702
1703 case cff_op_sub:
1704 FT_TRACE4(( " sub" ));
1705
1706 args[0] -= args[1];
1707 args++;
1708 break;
1709
1710 case cff_op_div:
1711 FT_TRACE4(( " div" ));
1712
1713 args[0] = FT_DivFix( args[0], args[1] );
1714 args++;
1715 break;
1716
1717 case cff_op_neg:
1718 FT_TRACE4(( " neg" ));
1719
1720 args[0] = -args[0];
1721 args++;
1722 break;
1723
1724 case cff_op_random:
1725 {
1726 FT_Fixed rand;
1727
1728
1729 FT_TRACE4(( " rand" ));
1730
1731 rand = seed;
1732 if ( rand >= 0x8000 )
1733 rand++;
1734
1735 args[0] = rand;
1736 seed = FT_MulFix( seed, 0x10000L - seed );
1737 if ( seed == 0 )
1738 seed += 0x2873;
1739 args++;
1740 }
1741 break;
1742
1743 case cff_op_mul:
1744 FT_TRACE4(( " mul" ));
1745
1746 args[0] = FT_MulFix( args[0], args[1] );
1747 args++;
1748 break;
1749
1750 case cff_op_sqrt:
1751 FT_TRACE4(( " sqrt" ));
1752
1753 if ( args[0] > 0 )
1754 {
1755 FT_Int count = 9;
1756 FT_Fixed root = args[0];
1757 FT_Fixed new_root;
1758
1759
1760 for (;;)
1761 {
Tom Kacvinsky8316bc52001-03-16 13:35:56 +00001762 new_root = ( root + FT_DivFix( args[0], root ) + 1 ) >> 1;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001763 if ( new_root == root || count <= 0 )
1764 break;
1765 root = new_root;
1766 }
1767 args[0] = new_root;
1768 }
1769 else
1770 args[0] = 0;
1771 args++;
1772 break;
1773
1774 case cff_op_drop:
1775 /* nothing */
1776 FT_TRACE4(( " drop" ));
1777
1778 break;
1779
1780 case cff_op_exch:
1781 {
1782 FT_Fixed tmp;
1783
1784
1785 FT_TRACE4(( " exch" ));
1786
1787 tmp = args[0];
1788 args[0] = args[1];
1789 args[1] = tmp;
1790 args += 2;
1791 }
1792 break;
1793
1794 case cff_op_index:
1795 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001796 FT_Int idx = args[0] >> 16;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001797
1798
1799 FT_TRACE4(( " index" ));
1800
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001801 if ( idx < 0 )
1802 idx = 0;
1803 else if ( idx > num_args - 2 )
1804 idx = num_args - 2;
1805 args[0] = args[-( idx + 1 )];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001806 args++;
1807 }
1808 break;
1809
1810 case cff_op_roll:
1811 {
1812 FT_Int count = (FT_Int)( args[0] >> 16 );
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001813 FT_Int idx = (FT_Int)( args[1] >> 16 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001814
1815
1816 FT_TRACE4(( " roll" ));
1817
1818 if ( count <= 0 )
1819 count = 1;
1820
1821 args -= count;
1822 if ( args < stack )
1823 goto Stack_Underflow;
1824
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001825 if ( idx >= 0 )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001826 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001827 while ( idx > 0 )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001828 {
1829 FT_Fixed tmp = args[count - 1];
1830 FT_Int i;
1831
1832
1833 for ( i = count - 2; i >= 0; i-- )
1834 args[i + 1] = args[i];
1835 args[0] = tmp;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001836 idx--;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001837 }
1838 }
1839 else
1840 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001841 while ( idx < 0 )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001842 {
1843 FT_Fixed tmp = args[0];
1844 FT_Int i;
1845
1846
1847 for ( i = 0; i < count - 1; i++ )
1848 args[i] = args[i + 1];
1849 args[count - 1] = tmp;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001850 idx++;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001851 }
1852 }
1853 args += count;
1854 }
1855 break;
1856
1857 case cff_op_dup:
1858 FT_TRACE4(( " dup" ));
1859
1860 args[1] = args[0];
1861 args++;
1862 break;
1863
1864 case cff_op_put:
1865 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001866 FT_Fixed val = args[0];
1867 FT_Int idx = (FT_Int)( args[1] >> 16 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001868
1869
1870 FT_TRACE4(( " put" ));
1871
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001872 if ( idx >= 0 && idx < decoder->len_buildchar )
1873 decoder->buildchar[idx] = val;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001874 }
1875 break;
1876
1877 case cff_op_get:
1878 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001879 FT_Int idx = (FT_Int)( args[0] >> 16 );
1880 FT_Fixed val = 0;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001881
1882
1883 FT_TRACE4(( " get" ));
1884
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001885 if ( idx >= 0 && idx < decoder->len_buildchar )
1886 val = decoder->buildchar[idx];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001887
1888 args[0] = val;
1889 args++;
1890 }
1891 break;
1892
1893 case cff_op_store:
1894 FT_TRACE4(( " store "));
1895
1896 goto Unimplemented;
1897
1898 case cff_op_load:
1899 FT_TRACE4(( " load" ));
1900
1901 goto Unimplemented;
1902
David Turner8d3a4012001-03-20 11:14:24 +00001903 case cff_op_dotsection:
Werner Lemberg521a2d72001-03-20 22:58:56 +00001904 /* this operator is deprecated and ignored by the parser */
1905 FT_TRACE4(( " dotsection" ));
David Turner8d3a4012001-03-20 11:14:24 +00001906 break;
1907
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001908 case cff_op_and:
1909 {
1910 FT_Fixed cond = args[0] && args[1];
1911
1912
1913 FT_TRACE4(( " and" ));
1914
1915 args[0] = cond ? 0x10000L : 0;
1916 args++;
1917 }
1918 break;
1919
1920 case cff_op_or:
1921 {
1922 FT_Fixed cond = args[0] || args[1];
1923
1924
1925 FT_TRACE4(( " or" ));
1926
1927 args[0] = cond ? 0x10000L : 0;
1928 args++;
1929 }
1930 break;
1931
1932 case cff_op_eq:
1933 {
1934 FT_Fixed cond = !args[0];
1935
1936
1937 FT_TRACE4(( " eq" ));
1938
1939 args[0] = cond ? 0x10000L : 0;
1940 args++;
1941 }
1942 break;
1943
1944 case cff_op_ifelse:
1945 {
1946 FT_Fixed cond = (args[2] <= args[3]);
1947
1948
1949 FT_TRACE4(( " ifelse" ));
1950
1951 if ( !cond )
1952 args[0] = args[1];
1953 args++;
1954 }
1955 break;
1956
1957 case cff_op_callsubr:
1958 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001959 FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) +
1960 decoder->locals_bias );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001961
1962
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001963 FT_TRACE4(( " callsubr(%d)", idx ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001964
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001965 if ( idx >= decoder->num_locals )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001966 {
1967 FT_ERROR(( "CFF_Parse_CharStrings:" ));
1968 FT_ERROR(( " invalid local subr index\n" ));
1969 goto Syntax_Error;
1970 }
1971
1972 if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
1973 {
1974 FT_ERROR(( "CFF_Parse_CharStrings: too many nested subrs\n" ));
1975 goto Syntax_Error;
1976 }
1977
1978 zone->cursor = ip; /* save current instruction pointer */
1979
1980 zone++;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001981 zone->base = decoder->locals[idx];
1982 zone->limit = decoder->locals[idx + 1];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00001983 zone->cursor = zone->base;
1984
1985 if ( !zone->base )
1986 {
1987 FT_ERROR(( "CFF_Parse_CharStrings: invoking empty subrs!\n" ));
1988 goto Syntax_Error;
1989 }
1990
1991 decoder->zone = zone;
1992 ip = zone->base;
1993 limit = zone->limit;
1994 }
1995 break;
1996
1997 case cff_op_callgsubr:
1998 {
Werner Lemberg0d9165e2002-03-07 21:59:59 +00001999 FT_UInt idx = (FT_UInt)( ( args[0] >> 16 ) +
2000 decoder->globals_bias );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002001
2002
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002003 FT_TRACE4(( " callgsubr(%d)", idx ));
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002004
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002005 if ( idx >= decoder->num_globals )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002006 {
2007 FT_ERROR(( "CFF_Parse_CharStrings:" ));
2008 FT_ERROR(( " invalid global subr index\n" ));
2009 goto Syntax_Error;
2010 }
2011
2012 if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
2013 {
2014 FT_ERROR(( "CFF_Parse_CharStrings: too many nested subrs\n" ));
2015 goto Syntax_Error;
2016 }
2017
2018 zone->cursor = ip; /* save current instruction pointer */
2019
2020 zone++;
Werner Lemberg0d9165e2002-03-07 21:59:59 +00002021 zone->base = decoder->globals[idx];
2022 zone->limit = decoder->globals[idx + 1];
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002023 zone->cursor = zone->base;
2024
2025 if ( !zone->base )
2026 {
2027 FT_ERROR(( "CFF_Parse_CharStrings: invoking empty subrs!\n" ));
2028 goto Syntax_Error;
2029 }
2030
2031 decoder->zone = zone;
2032 ip = zone->base;
2033 limit = zone->limit;
2034 }
2035 break;
2036
2037 case cff_op_return:
2038 FT_TRACE4(( " return" ));
2039
2040 if ( decoder->zone <= decoder->zones )
2041 {
2042 FT_ERROR(( "CFF_Parse_CharStrings: unexpected return\n" ));
2043 goto Syntax_Error;
2044 }
2045
2046 decoder->zone--;
2047 zone = decoder->zone;
2048 ip = zone->cursor;
2049 limit = zone->limit;
2050 break;
2051
2052 default:
2053 Unimplemented:
2054 FT_ERROR(( "Unimplemented opcode: %d", ip[-1] ));
2055
2056 if ( ip[-1] == 12 )
2057 FT_ERROR(( " %d", ip[0] ));
2058 FT_ERROR(( "\n" ));
2059
2060 return CFF_Err_Unimplemented_Feature;
2061 }
2062
2063 decoder->top = args;
2064
2065 } /* general operator processing */
2066
2067 } /* while ip < limit */
2068
2069 FT_TRACE4(( "..end..\n\n" ));
2070
2071 return error;
2072
2073 Syntax_Error:
2074 FT_TRACE4(( "CFF_Parse_CharStrings: syntax error!" ));
2075 return CFF_Err_Invalid_File_Format;
2076
2077 Stack_Underflow:
2078 FT_TRACE4(( "CFF_Parse_CharStrings: stack underflow!" ));
2079 return CFF_Err_Too_Few_Arguments;
2080
2081 Stack_Overflow:
2082 FT_TRACE4(( "CFF_Parse_CharStrings: stack overflow!" ));
2083 return CFF_Err_Stack_Overflow;
2084
2085 Memory_Error:
2086 return builder->error;
2087 }
2088
2089
2090 /*************************************************************************/
2091 /*************************************************************************/
2092 /*************************************************************************/
2093 /********** *********/
2094 /********** *********/
2095 /********** COMPUTE THE MAXIMUM ADVANCE WIDTH *********/
2096 /********** *********/
2097 /********** The following code is in charge of computing *********/
2098 /********** the maximum advance width of the font. It *********/
2099 /********** quickly processes each glyph charstring to *********/
2100 /********** extract the value from either a `sbw' or `seac' *********/
2101 /********** operator. *********/
2102 /********** *********/
2103 /*************************************************************************/
2104 /*************************************************************************/
2105 /*************************************************************************/
2106
2107
2108#if 0 /* unused until we support pure CFF fonts */
2109
2110
David Turnerbc82f1b2002-03-01 02:26:22 +00002111 FT_LOCAL_DEF( FT_Error )
Werner Lemberg93616ec2001-06-27 19:46:12 +00002112 CFF_Compute_Max_Advance( TT_Face face,
2113 FT_Int* max_advance )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002114 {
Werner Lembergd573c7e2001-01-03 07:14:12 +00002115 FT_Error error = 0;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002116 CFF_Decoder decoder;
Werner Lembergd573c7e2001-01-03 07:14:12 +00002117 FT_Int glyph_index;
David Turnerab4fc4d2002-03-14 08:57:10 +00002118 CFF_Font cff = (CFF_Font)face->other;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002119
2120
2121 *max_advance = 0;
2122
2123 /* Initialize load decoder */
David Turnerc8087482001-12-20 13:14:18 +00002124 CFF_Init_Decoder( &decoder, face, 0, 0, 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002125
2126 decoder.builder.metrics_only = 1;
2127 decoder.builder.load_points = 0;
2128
2129 /* For each glyph, parse the glyph charstring and extract */
2130 /* the advance width. */
2131 for ( glyph_index = 0; glyph_index < face->root.num_glyphs;
2132 glyph_index++ )
2133 {
2134 FT_Byte* charstring;
2135 FT_ULong charstring_len;
2136
2137
2138 /* now get load the unscaled outline */
2139 error = CFF_Access_Element( &cff->charstrings_index, glyph_index,
Werner Lembergd573c7e2001-01-03 07:14:12 +00002140 &charstring, &charstring_len );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002141 if ( !error )
2142 {
2143 CFF_Prepare_Decoder( &decoder, glyph_index );
2144 error = CFF_Parse_CharStrings( &decoder, charstring, charstring_len );
2145
2146 CFF_Forget_Element( &cff->charstrings_index, &charstring );
2147 }
2148
2149 /* ignore the error if one has occurred -- skip to next glyph */
2150 error = 0;
2151 }
2152
2153 *max_advance = decoder.builder.advance.x;
2154
2155 return CFF_Err_Ok;
2156 }
2157
2158
2159#endif /* 0 */
2160
2161
2162 /*************************************************************************/
2163 /*************************************************************************/
2164 /*************************************************************************/
2165 /********** *********/
2166 /********** *********/
2167 /********** UNHINTED GLYPH LOADER *********/
2168 /********** *********/
2169 /********** The following code is in charge of loading a *********/
2170 /********** single outline. It completely ignores hinting *********/
2171 /********** and is used when FT_LOAD_NO_HINTING is set. *********/
2172 /********** *********/
2173 /*************************************************************************/
2174 /*************************************************************************/
2175 /*************************************************************************/
2176
2177
David Turnerbc82f1b2002-03-01 02:26:22 +00002178 FT_LOCAL_DEF( FT_Error )
Werner Lemberg93616ec2001-06-27 19:46:12 +00002179 CFF_Load_Glyph( CFF_GlyphSlot glyph,
2180 CFF_Size size,
2181 FT_Int glyph_index,
2182 FT_Int load_flags )
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002183 {
Werner Lembergd573c7e2001-01-03 07:14:12 +00002184 FT_Error error;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002185 CFF_Decoder decoder;
Werner Lembergd573c7e2001-01-03 07:14:12 +00002186 TT_Face face = (TT_Face)glyph->root.face;
2187 FT_Bool hinting;
David Turnerab4fc4d2002-03-14 08:57:10 +00002188 CFF_Font cff = (CFF_Font)face->extra.data;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002189
Werner Lembergd573c7e2001-01-03 07:14:12 +00002190 FT_Matrix font_matrix;
2191 FT_Vector font_offset;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002192
2193
2194 if ( load_flags & FT_LOAD_NO_RECURSE )
2195 load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
2196
2197 glyph->x_scale = 0x10000L;
2198 glyph->y_scale = 0x10000L;
2199 if ( size )
2200 {
2201 glyph->x_scale = size->metrics.x_scale;
2202 glyph->y_scale = size->metrics.y_scale;
2203 }
2204
2205 glyph->root.outline.n_points = 0;
2206 glyph->root.outline.n_contours = 0;
2207
David Turner8edbcab2001-06-19 08:28:24 +00002208 hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 &&
2209 ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002210
2211 glyph->root.format = ft_glyph_format_outline; /* by default */
2212
2213 {
2214 FT_Byte* charstring;
2215 FT_ULong charstring_len;
2216
2217
David Turnerc8087482001-12-20 13:14:18 +00002218 CFF_Init_Decoder( &decoder, face, size, glyph, hinting );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002219
2220 decoder.builder.no_recurse =
2221 (FT_Bool)( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 );
2222
2223 /* now load the unscaled outline */
2224 error = CFF_Access_Element( &cff->charstrings_index, glyph_index,
2225 &charstring, &charstring_len );
2226 if ( !error )
2227 {
David Turner29644172002-02-28 18:59:37 +00002228 CFF_IndexRec csindex = cff->charstrings_index;
Tom Kacvinskye20035a2001-03-05 16:22:25 +00002229
Werner Lemberg2e35c9b2001-03-06 13:56:42 +00002230
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002231 CFF_Prepare_Decoder( &decoder, glyph_index );
2232 error = CFF_Parse_CharStrings( &decoder, charstring, charstring_len );
2233
2234 CFF_Forget_Element( &cff->charstrings_index, &charstring );
Tom Kacvinskye20035a2001-03-05 16:22:25 +00002235
2236 /* We set control_data and control_len if charstrings is loaded. */
2237 /* See how charstring loads at CFF_Access_Element() in cffload.c. */
2238
Werner Lemberg2e35c9b2001-03-06 13:56:42 +00002239 glyph->root.control_data =
2240 csindex.bytes + csindex.offsets[glyph_index] - 1;
2241 glyph->root.control_len =
2242 charstring_len;
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002243 }
2244
2245 /* save new glyph tables */
David Turnerc8087482001-12-20 13:14:18 +00002246 CFF_Builder_Done( &decoder.builder );
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002247 }
2248
2249 font_matrix = cff->top_font.font_dict.font_matrix;
2250 font_offset = cff->top_font.font_dict.font_offset;
2251
2252 /* Now, set the metrics -- this is rather simple, as */
2253 /* the left side bearing is the xMin, and the top side */
2254 /* bearing the yMax. */
2255 if ( !error )
2256 {
2257 /* For composite glyphs, return only left side bearing and */
2258 /* advance width. */
2259 if ( load_flags & FT_LOAD_NO_RECURSE )
2260 {
2261 FT_Slot_Internal internal = glyph->root.internal;
Werner Lemberg415235d2001-06-28 17:49:10 +00002262
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002263
2264 glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
2265 glyph->root.metrics.horiAdvance = decoder.glyph_width;
2266 internal->glyph_matrix = font_matrix;
2267 internal->glyph_delta = font_offset;
2268 internal->glyph_transformed = 1;
2269 }
2270 else
2271 {
2272 FT_BBox cbox;
2273 FT_Glyph_Metrics* metrics = &glyph->root.metrics;
2274
2275
2276 /* copy the _unscaled_ advance width */
2277 metrics->horiAdvance = decoder.glyph_width;
2278 glyph->root.linearHoriAdvance = decoder.glyph_width;
2279 glyph->root.internal->glyph_transformed = 0;
2280
2281 /* make up vertical metrics */
2282 metrics->vertBearingX = 0;
2283 metrics->vertBearingY = 0;
2284 metrics->vertAdvance = 0;
2285
2286 glyph->root.linearVertAdvance = 0;
2287
2288 glyph->root.format = ft_glyph_format_outline;
2289
2290 glyph->root.outline.flags = 0;
2291 if ( size && size->metrics.y_ppem < 24 )
2292 glyph->root.outline.flags |= ft_outline_high_precision;
2293
2294 glyph->root.outline.flags |= ft_outline_reverse_fill;
2295
2296 /* apply the font matrix */
2297 FT_Outline_Transform( &glyph->root.outline, &font_matrix );
2298
2299 FT_Outline_Translate( &glyph->root.outline,
2300 font_offset.x,
2301 font_offset.y );
2302
2303 if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 )
2304 {
2305 /* scale the outline and the metrics */
2306 FT_Int n;
2307 FT_Outline* cur = &glyph->root.outline;
2308 FT_Vector* vec = cur->points;
2309 FT_Fixed x_scale = glyph->x_scale;
2310 FT_Fixed y_scale = glyph->y_scale;
2311
2312
2313 /* First of all, scale the points */
David Turnerc8087482001-12-20 13:14:18 +00002314 if ( !hinting )
2315 for ( n = cur->n_points; n > 0; n--, vec++ )
2316 {
2317 vec->x = FT_MulFix( vec->x, x_scale );
2318 vec->y = FT_MulFix( vec->y, y_scale );
2319 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002320
2321 FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
2322
2323 /* Then scale the metrics */
2324 metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
2325 metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
2326
2327 metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale );
2328 metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale );
David Turnerbce29862001-12-14 14:52:58 +00002329
2330 if ( hinting )
2331 {
Werner Lemberg5da9dd72001-12-16 08:17:33 +00002332 metrics->horiAdvance = ( metrics->horiAdvance + 32 ) & -64;
2333 metrics->vertAdvance = ( metrics->vertAdvance + 32 ) & -64;
David Turnerbce29862001-12-14 14:52:58 +00002334
Werner Lemberg5da9dd72001-12-16 08:17:33 +00002335 metrics->vertBearingX = ( metrics->vertBearingX + 32 ) & -64;
2336 metrics->vertBearingY = ( metrics->vertBearingY + 32 ) & -64;
David Turnerbce29862001-12-14 14:52:58 +00002337 }
Tom Kacvinskycd92b112001-01-03 00:15:00 +00002338 }
2339
2340 /* compute the other metrics */
2341 FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
2342
2343 /* grid fit the bounding box if necessary */
2344 if ( hinting )
2345 {
2346 cbox.xMin &= -64;
2347 cbox.yMin &= -64;
2348 cbox.xMax = ( cbox.xMax + 63 ) & -64;
2349 cbox.yMax = ( cbox.yMax + 63 ) & -64;
2350 }
2351
2352 metrics->width = cbox.xMax - cbox.xMin;
2353 metrics->height = cbox.yMax - cbox.yMin;
2354
2355 metrics->horiBearingX = cbox.xMin;
2356 metrics->horiBearingY = cbox.yMax;
2357 }
2358 }
2359
2360 return error;
2361 }
2362
2363
2364/* END */