- Remove svn:needs-lock, svn:eol-type, and svn:eol-tyle properties.
[reactos.git] / reactos / lib / 3rdparty / freetype / src / psaux / t1decode.c
1 /***************************************************************************/
2 /* */
3 /* t1decode.c */
4 /* */
5 /* PostScript Type 1 decoding routines (body). */
6 /* */
7 /* Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2007 by */
8 /* 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_POSTSCRIPT_HINTS_H
22 #include FT_OUTLINE_H
23
24 #include "t1decode.h"
25 #include "psobjs.h"
26
27 #include "psauxerr.h"
28
29
30 /*************************************************************************/
31 /* */
32 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
33 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
34 /* messages during execution. */
35 /* */
36 #undef FT_COMPONENT
37 #define FT_COMPONENT trace_t1decode
38
39
40 typedef enum T1_Operator_
41 {
42 op_none = 0,
43 op_endchar,
44 op_hsbw,
45 op_seac,
46 op_sbw,
47 op_closepath,
48 op_hlineto,
49 op_hmoveto,
50 op_hvcurveto,
51 op_rlineto,
52 op_rmoveto,
53 op_rrcurveto,
54 op_vhcurveto,
55 op_vlineto,
56 op_vmoveto,
57 op_dotsection,
58 op_hstem,
59 op_hstem3,
60 op_vstem,
61 op_vstem3,
62 op_div,
63 op_callothersubr,
64 op_callsubr,
65 op_pop,
66 op_return,
67 op_setcurrentpoint,
68 op_unknown15,
69
70 op_max /* never remove this one */
71
72 } T1_Operator;
73
74
75 static
76 const FT_Int t1_args_count[op_max] =
77 {
78 0, /* none */
79 0, /* endchar */
80 2, /* hsbw */
81 5, /* seac */
82 4, /* sbw */
83 0, /* closepath */
84 1, /* hlineto */
85 1, /* hmoveto */
86 4, /* hvcurveto */
87 2, /* rlineto */
88 2, /* rmoveto */
89 6, /* rrcurveto */
90 4, /* vhcurveto */
91 1, /* vlineto */
92 1, /* vmoveto */
93 0, /* dotsection */
94 2, /* hstem */
95 6, /* hstem3 */
96 2, /* vstem */
97 6, /* vstem3 */
98 2, /* div */
99 -1, /* callothersubr */
100 1, /* callsubr */
101 0, /* pop */
102 0, /* return */
103 2, /* setcurrentpoint */
104 2 /* opcode 15 (undocumented and obsolete) */
105 };
106
107
108 /*************************************************************************/
109 /* */
110 /* <Function> */
111 /* t1_lookup_glyph_by_stdcharcode */
112 /* */
113 /* <Description> */
114 /* Looks up a given glyph by its StandardEncoding charcode. Used to */
115 /* implement the SEAC Type 1 operator. */
116 /* */
117 /* <Input> */
118 /* face :: The current face object. */
119 /* */
120 /* charcode :: The character code to look for. */
121 /* */
122 /* <Return> */
123 /* A glyph index in the font face. Returns -1 if the corresponding */
124 /* glyph wasn't found. */
125 /* */
126 static FT_Int
127 t1_lookup_glyph_by_stdcharcode( T1_Decoder decoder,
128 FT_Int charcode )
129 {
130 FT_UInt n;
131 const FT_String* glyph_name;
132 FT_Service_PsCMaps psnames = decoder->psnames;
133
134
135 /* check range of standard char code */
136 if ( charcode < 0 || charcode > 255 )
137 return -1;
138
139 glyph_name = psnames->adobe_std_strings(
140 psnames->adobe_std_encoding[charcode]);
141
142 for ( n = 0; n < decoder->num_glyphs; n++ )
143 {
144 FT_String* name = (FT_String*)decoder->glyph_names[n];
145
146
147 if ( name && name[0] == glyph_name[0] &&
148 ft_strcmp( name, glyph_name ) == 0 )
149 return n;
150 }
151
152 return -1;
153 }
154
155
156 /*************************************************************************/
157 /* */
158 /* <Function> */
159 /* t1operator_seac */
160 /* */
161 /* <Description> */
162 /* Implements the `seac' Type 1 operator for a Type 1 decoder. */
163 /* */
164 /* <Input> */
165 /* decoder :: The current CID decoder. */
166 /* */
167 /* asb :: The accent's side bearing. */
168 /* */
169 /* adx :: The horizontal offset of the accent. */
170 /* */
171 /* ady :: The vertical offset of the accent. */
172 /* */
173 /* bchar :: The base character's StandardEncoding charcode. */
174 /* */
175 /* achar :: The accent character's StandardEncoding charcode. */
176 /* */
177 /* <Return> */
178 /* FreeType error code. 0 means success. */
179 /* */
180 static FT_Error
181 t1operator_seac( T1_Decoder decoder,
182 FT_Pos asb,
183 FT_Pos adx,
184 FT_Pos ady,
185 FT_Int bchar,
186 FT_Int achar )
187 {
188 FT_Error error;
189 FT_Int bchar_index, achar_index;
190 #if 0
191 FT_Int n_base_points;
192 FT_Outline* base = decoder->builder.base;
193 #endif
194 FT_Vector left_bearing, advance;
195
196
197 /* seac weirdness */
198 adx += decoder->builder.left_bearing.x;
199
200 /* `glyph_names' is set to 0 for CID fonts which do not */
201 /* include an encoding. How can we deal with these? */
202 if ( decoder->glyph_names == 0 )
203 {
204 FT_ERROR(( "t1operator_seac:" ));
205 FT_ERROR(( " glyph names table not available in this font!\n" ));
206 return PSaux_Err_Syntax_Error;
207 }
208
209 bchar_index = t1_lookup_glyph_by_stdcharcode( decoder, bchar );
210 achar_index = t1_lookup_glyph_by_stdcharcode( decoder, achar );
211
212 if ( bchar_index < 0 || achar_index < 0 )
213 {
214 FT_ERROR(( "t1operator_seac:" ));
215 FT_ERROR(( " invalid seac character code arguments\n" ));
216 return PSaux_Err_Syntax_Error;
217 }
218
219 /* if we are trying to load a composite glyph, do not load the */
220 /* accent character and return the array of subglyphs. */
221 if ( decoder->builder.no_recurse )
222 {
223 FT_GlyphSlot glyph = (FT_GlyphSlot)decoder->builder.glyph;
224 FT_GlyphLoader loader = glyph->internal->loader;
225 FT_SubGlyph subg;
226
227
228 /* reallocate subglyph array if necessary */
229 error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 );
230 if ( error )
231 goto Exit;
232
233 subg = loader->current.subglyphs;
234
235 /* subglyph 0 = base character */
236 subg->index = bchar_index;
237 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES |
238 FT_SUBGLYPH_FLAG_USE_MY_METRICS;
239 subg->arg1 = 0;
240 subg->arg2 = 0;
241 subg++;
242
243 /* subglyph 1 = accent character */
244 subg->index = achar_index;
245 subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
246 subg->arg1 = (FT_Int)( adx - asb );
247 subg->arg2 = (FT_Int)ady;
248
249 /* set up remaining glyph fields */
250 glyph->num_subglyphs = 2;
251 glyph->subglyphs = loader->base.subglyphs;
252 glyph->format = FT_GLYPH_FORMAT_COMPOSITE;
253
254 loader->current.num_subglyphs = 2;
255 goto Exit;
256 }
257
258 /* First load `bchar' in builder */
259 /* now load the unscaled outline */
260
261 FT_GlyphLoader_Prepare( decoder->builder.loader ); /* prepare loader */
262
263 error = t1_decoder_parse_glyph( decoder, bchar_index );
264 if ( error )
265 goto Exit;
266
267 /* save the left bearing and width of the base character */
268 /* as they will be erased by the next load. */
269
270 left_bearing = decoder->builder.left_bearing;
271 advance = decoder->builder.advance;
272
273 decoder->builder.left_bearing.x = 0;
274 decoder->builder.left_bearing.y = 0;
275
276 decoder->builder.pos_x = adx - asb;
277 decoder->builder.pos_y = ady;
278
279 /* Now load `achar' on top of */
280 /* the base outline */
281 error = t1_decoder_parse_glyph( decoder, achar_index );
282 if ( error )
283 goto Exit;
284
285 /* restore the left side bearing and */
286 /* advance width of the base character */
287
288 decoder->builder.left_bearing = left_bearing;
289 decoder->builder.advance = advance;
290
291 decoder->builder.pos_x = 0;
292 decoder->builder.pos_y = 0;
293
294 Exit:
295 return error;
296 }
297
298
299 /*************************************************************************/
300 /* */
301 /* <Function> */
302 /* t1_decoder_parse_charstrings */
303 /* */
304 /* <Description> */
305 /* Parses a given Type 1 charstrings program. */
306 /* */
307 /* <Input> */
308 /* decoder :: The current Type 1 decoder. */
309 /* */
310 /* charstring_base :: The base address of the charstring stream. */
311 /* */
312 /* charstring_len :: The length in bytes of the charstring stream. */
313 /* */
314 /* <Return> */
315 /* FreeType error code. 0 means success. */
316 /* */
317 FT_LOCAL_DEF( FT_Error )
318 t1_decoder_parse_charstrings( T1_Decoder decoder,
319 FT_Byte* charstring_base,
320 FT_UInt charstring_len )
321 {
322 FT_Error error;
323 T1_Decoder_Zone zone;
324 FT_Byte* ip;
325 FT_Byte* limit;
326 T1_Builder builder = &decoder->builder;
327 FT_Pos x, y, orig_x, orig_y;
328 FT_Int known_othersubr_result_cnt = 0;
329 FT_Int unknown_othersubr_result_cnt = 0;
330
331 T1_Hints_Funcs hinter;
332
333
334 /* we don't want to touch the source code -- use macro trick */
335 #define start_point t1_builder_start_point
336 #define check_points t1_builder_check_points
337 #define add_point t1_builder_add_point
338 #define add_point1 t1_builder_add_point1
339 #define add_contour t1_builder_add_contour
340 #define close_contour t1_builder_close_contour
341
342 /* First of all, initialize the decoder */
343 decoder->top = decoder->stack;
344 decoder->zone = decoder->zones;
345 zone = decoder->zones;
346
347 builder->parse_state = T1_Parse_Start;
348
349 hinter = (T1_Hints_Funcs)builder->hints_funcs;
350
351 /* a font that reads BuildCharArray without setting */
352 /* its values first is buggy, but ... */
353 FT_ASSERT( ( decoder->len_buildchar == 0 ) ==
354 ( decoder->buildchar == NULL ) );
355
356 if ( decoder->len_buildchar > 0 )
357 memset( &decoder->buildchar[0],
358 0,
359 sizeof( decoder->buildchar[0] ) *
360 decoder->len_buildchar );
361
362 FT_TRACE4(( "\nStart charstring\n" ));
363
364 zone->base = charstring_base;
365 limit = zone->limit = charstring_base + charstring_len;
366 ip = zone->cursor = zone->base;
367
368 error = PSaux_Err_Ok;
369
370 x = orig_x = builder->pos_x;
371 y = orig_y = builder->pos_y;
372
373 /* begin hints recording session, if any */
374 if ( hinter )
375 hinter->open( hinter->hints );
376
377 /* now, execute loop */
378 while ( ip < limit )
379 {
380 FT_Long* top = decoder->top;
381 T1_Operator op = op_none;
382 FT_Long value = 0;
383
384
385 FT_ASSERT( known_othersubr_result_cnt == 0 ||
386 unknown_othersubr_result_cnt == 0 );
387
388 FT_TRACE5(( " (%d)", decoder->top - decoder->stack ));
389
390 /*********************************************************************/
391 /* */
392 /* Decode operator or operand */
393 /* */
394 /* */
395
396 /* first of all, decompress operator or value */
397 switch ( *ip++ )
398 {
399 case 1:
400 op = op_hstem;
401 break;
402
403 case 3:
404 op = op_vstem;
405 break;
406 case 4:
407 op = op_vmoveto;
408 break;
409 case 5:
410 op = op_rlineto;
411 break;
412 case 6:
413 op = op_hlineto;
414 break;
415 case 7:
416 op = op_vlineto;
417 break;
418 case 8:
419 op = op_rrcurveto;
420 break;
421 case 9:
422 op = op_closepath;
423 break;
424 case 10:
425 op = op_callsubr;
426 break;
427 case 11:
428 op = op_return;
429 break;
430
431 case 13:
432 op = op_hsbw;
433 break;
434 case 14:
435 op = op_endchar;
436 break;
437
438 case 15: /* undocumented, obsolete operator */
439 op = op_unknown15;
440 break;
441
442 case 21:
443 op = op_rmoveto;
444 break;
445 case 22:
446 op = op_hmoveto;
447 break;
448
449 case 30:
450 op = op_vhcurveto;
451 break;
452 case 31:
453 op = op_hvcurveto;
454 break;
455
456 case 12:
457 if ( ip > limit )
458 {
459 FT_ERROR(( "t1_decoder_parse_charstrings: "
460 "invalid escape (12+EOF)\n" ));
461 goto Syntax_Error;
462 }
463
464 switch ( *ip++ )
465 {
466 case 0:
467 op = op_dotsection;
468 break;
469 case 1:
470 op = op_vstem3;
471 break;
472 case 2:
473 op = op_hstem3;
474 break;
475 case 6:
476 op = op_seac;
477 break;
478 case 7:
479 op = op_sbw;
480 break;
481 case 12:
482 op = op_div;
483 break;
484 case 16:
485 op = op_callothersubr;
486 break;
487 case 17:
488 op = op_pop;
489 break;
490 case 33:
491 op = op_setcurrentpoint;
492 break;
493
494 default:
495 FT_ERROR(( "t1_decoder_parse_charstrings: "
496 "invalid escape (12+%d)\n",
497 ip[-1] ));
498 goto Syntax_Error;
499 }
500 break;
501
502 case 255: /* four bytes integer */
503 if ( ip + 4 > limit )
504 {
505 FT_ERROR(( "t1_decoder_parse_charstrings: "
506 "unexpected EOF in integer\n" ));
507 goto Syntax_Error;
508 }
509
510 value = (FT_Int32)( ((FT_Long)ip[0] << 24) |
511 ((FT_Long)ip[1] << 16) |
512 ((FT_Long)ip[2] << 8 ) |
513 ip[3] );
514 ip += 4;
515 break;
516
517 default:
518 if ( ip[-1] >= 32 )
519 {
520 if ( ip[-1] < 247 )
521 value = (FT_Long)ip[-1] - 139;
522 else
523 {
524 if ( ++ip > limit )
525 {
526 FT_ERROR(( "t1_decoder_parse_charstrings: " ));
527 FT_ERROR(( "unexpected EOF in integer\n" ));
528 goto Syntax_Error;
529 }
530
531 if ( ip[-2] < 251 )
532 value = ( ( (FT_Long)ip[-2] - 247 ) << 8 ) + ip[-1] + 108;
533 else
534 value = -( ( ( (FT_Long)ip[-2] - 251 ) << 8 ) + ip[-1] + 108 );
535 }
536 }
537 else
538 {
539 FT_ERROR(( "t1_decoder_parse_charstrings: "
540 "invalid byte (%d)\n", ip[-1] ));
541 goto Syntax_Error;
542 }
543 }
544
545 if ( unknown_othersubr_result_cnt > 0 )
546 {
547 switch ( op )
548 {
549 case op_callsubr:
550 case op_return:
551 case op_none:
552 case op_pop:
553 break;
554
555 default:
556 /* all operands have been transferred by previous pops */
557 unknown_othersubr_result_cnt = 0;
558 break;
559 }
560 }
561
562 /*********************************************************************/
563 /* */
564 /* Push value on stack, or process operator */
565 /* */
566 /* */
567 if ( op == op_none )
568 {
569 if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS )
570 {
571 FT_ERROR(( "t1_decoder_parse_charstrings: stack overflow!\n" ));
572 goto Syntax_Error;
573 }
574
575 FT_TRACE4(( " %ld", value ));
576
577 *top++ = value;
578 decoder->top = top;
579 }
580 else if ( op == op_callothersubr ) /* callothersubr */
581 {
582 FT_Int subr_no;
583 FT_Int arg_cnt;
584
585
586 FT_TRACE4(( " callothersubr" ));
587
588 if ( top - decoder->stack < 2 )
589 goto Stack_Underflow;
590
591 top -= 2;
592
593 subr_no = (FT_Int)top[1];
594 arg_cnt = (FT_Int)top[0];
595
596 /***********************************************************/
597 /* */
598 /* remove all operands to callothersubr from the stack */
599 /* */
600 /* for handled othersubrs, where we know the number of */
601 /* arguments, we increase the stack by the value of */
602 /* known_othersubr_result_cnt */
603 /* */
604 /* for unhandled othersubrs the following pops adjust the */
605 /* stack pointer as necessary */
606
607 if ( arg_cnt > top - decoder->stack )
608 goto Stack_Underflow;
609
610 top -= arg_cnt;
611
612 known_othersubr_result_cnt = 0;
613 unknown_othersubr_result_cnt = 0;
614
615 /* XXX TODO: The checks to `arg_count == <whatever>' */
616 /* might not be correct; an othersubr expects a certain */
617 /* number of operands on the PostScript stack (as opposed */
618 /* to the T1 stack) but it doesn't have to put them there */
619 /* by itself; previous othersubrs might have left the */
620 /* operands there if they were not followed by an */
621 /* appropriate number of pops */
622 /* */
623 /* On the other hand, Adobe Reader 7.0.8 for Linux doesn't */
624 /* accept a font that contains charstrings like */
625 /* */
626 /* 100 200 2 20 callothersubr */
627 /* 300 1 20 callothersubr pop */
628 /* */
629 /* Perhaps this is the reason why BuildCharArray exists. */
630
631 switch ( subr_no )
632 {
633 case 1: /* start flex feature */
634 if ( arg_cnt != 0 )
635 goto Unexpected_OtherSubr;
636
637 decoder->flex_state = 1;
638 decoder->num_flex_vectors = 0;
639 if ( start_point( builder, x, y ) ||
640 check_points( builder, 6 ) )
641 goto Fail;
642 break;
643
644 case 2: /* add flex vectors */
645 {
646 FT_Int idx;
647
648
649 if ( arg_cnt != 0 )
650 goto Unexpected_OtherSubr;
651
652 /* note that we should not add a point for index 0; */
653 /* this will move our current position to the flex */
654 /* point without adding any point to the outline */
655 idx = decoder->num_flex_vectors++;
656 if ( idx > 0 && idx < 7 )
657 add_point( builder,
658 x,
659 y,
660 (FT_Byte)( idx == 3 || idx == 6 ) );
661 }
662 break;
663
664 case 0: /* end flex feature */
665 if ( arg_cnt != 3 )
666 goto Unexpected_OtherSubr;
667
668 if ( decoder->flex_state == 0 ||
669 decoder->num_flex_vectors != 7 )
670 {
671 FT_ERROR(( "t1_decoder_parse_charstrings: "
672 "unexpected flex end\n" ));
673 goto Syntax_Error;
674 }
675
676 /* the two `results' are popped by the following setcurrentpoint */
677 known_othersubr_result_cnt = 2;
678 break;
679
680 case 3: /* change hints */
681 if ( arg_cnt != 1 )
682 goto Unexpected_OtherSubr;
683
684 known_othersubr_result_cnt = 1;
685
686 if ( hinter )
687 hinter->reset( hinter->hints, builder->current->n_points );
688
689 break;
690
691 case 12:
692 case 13:
693 /* counter control hints, clear stack */
694 top = decoder->stack;
695 break;
696
697 case 14:
698 case 15:
699 case 16:
700 case 17:
701 case 18: /* multiple masters */
702 {
703 PS_Blend blend = decoder->blend;
704 FT_UInt num_points, nn, mm;
705 FT_Long* delta;
706 FT_Long* values;
707
708
709 if ( !blend )
710 {
711 FT_ERROR(( "t1_decoder_parse_charstrings: " ));
712 FT_ERROR(( "unexpected multiple masters operator!\n" ));
713 goto Syntax_Error;
714 }
715
716 num_points = (FT_UInt)subr_no - 13 + ( subr_no == 18 );
717 if ( arg_cnt != (FT_Int)( num_points * blend->num_designs ) )
718 {
719 FT_ERROR(( "t1_decoder_parse_charstrings: " ));
720 FT_ERROR(( "incorrect number of mm arguments\n" ));
721 goto Syntax_Error;
722 }
723
724 /* we want to compute: */
725 /* */
726 /* a0*w0 + a1*w1 + ... + ak*wk */
727 /* */
728 /* but we only have the a0, a1-a0, a2-a0, .. ak-a0 */
729 /* however, given that w0 + w1 + ... + wk == 1, we can */
730 /* rewrite it easily as: */
731 /* */
732 /* a0 + (a1-a0)*w1 + (a2-a0)*w2 + .. + (ak-a0)*wk */
733 /* */
734 /* where k == num_designs-1 */
735 /* */
736 /* I guess that's why it's written in this `compact' */
737 /* form. */
738 /* */
739 delta = top + num_points;
740 values = top;
741 for ( nn = 0; nn < num_points; nn++ )
742 {
743 FT_Long tmp = values[0];
744
745
746 for ( mm = 1; mm < blend->num_designs; mm++ )
747 tmp += FT_MulFix( *delta++, blend->weight_vector[mm] );
748
749 *values++ = tmp;
750 }
751
752 known_othersubr_result_cnt = num_points;
753 break;
754 }
755
756 #ifdef CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS
757
758 /* We cannot yet enable these since currently */
759 /* our T1 stack stores integers which lack the */
760 /* precision to express the values */
761
762 case 19:
763 /* <idx> 1 19 callothersubr */
764 /* => replace elements starting from index cvi( <idx> ) */
765 /* of BuildCharArray with WeightVector */
766 {
767 FT_Int idx;
768 PS_Blend blend = decoder->blend;
769
770
771 if ( arg_cnt != 1 || blend == NULL )
772 goto Unexpected_OtherSubr;
773
774 idx = top[0];
775
776 if ( idx < 0 ||
777 idx + blend->num_designs > decoder->face->len_buildchar )
778 goto Unexpected_OtherSubr;
779
780 memcpy( &decoder->buildchar[idx],
781 blend->weight_vector,
782 blend->num_designs *
783 sizeof( blend->weight_vector[ 0 ] ) );
784 }
785 break;
786
787 case 20:
788 /* <arg1> <arg2> 2 20 callothersubr pop */
789 /* ==> push <arg1> + <arg2> onto T1 stack */
790 if ( arg_cnt != 2 )
791 goto Unexpected_OtherSubr;
792
793 top[0] += top[1]; /* XXX (over|under)flow */
794
795 known_othersubr_result_cnt = 1;
796 break;
797
798 case 21:
799 /* <arg1> <arg2> 2 21 callothersubr pop */
800 /* ==> push <arg1> - <arg2> onto T1 stack */
801 if ( arg_cnt != 2 )
802 goto Unexpected_OtherSubr;
803
804 top[0] -= top[1]; /* XXX (over|under)flow */
805
806 known_othersubr_result_cnt = 1;
807 break;
808
809 case 22:
810 /* <arg1> <arg2> 2 22 callothersubr pop */
811 /* ==> push <arg1> * <arg2> onto T1 stack */
812 if ( arg_cnt != 2 )
813 goto Unexpected_OtherSubr;
814
815 top[0] *= top[1]; /* XXX (over|under)flow */
816
817 known_othersubr_result_cnt = 1;
818 break;
819
820 case 23:
821 /* <arg1> <arg2> 2 23 callothersubr pop */
822 /* ==> push <arg1> / <arg2> onto T1 stack */
823 if ( arg_cnt != 2 || top[1] == 0 )
824 goto Unexpected_OtherSubr;
825
826 top[0] /= top[1]; /* XXX (over|under)flow */
827
828 known_othersubr_result_cnt = 1;
829 break;
830
831 #endif /* CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS */
832
833 case 24:
834 /* <val> <idx> 2 24 callothersubr */
835 /* => set BuildCharArray[cvi( <idx> )] = <val> */
836 {
837 FT_Int idx;
838 PS_Blend blend = decoder->blend;
839
840 if ( arg_cnt != 2 || blend == NULL )
841 goto Unexpected_OtherSubr;
842
843 idx = top[1];
844
845 if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar )
846 goto Unexpected_OtherSubr;
847
848 decoder->buildchar[idx] = top[0];
849 }
850 break;
851
852 case 25:
853 /* <idx> 1 25 callothersubr pop */
854 /* => push BuildCharArray[cvi( idx )] */
855 /* onto T1 stack */
856 {
857 FT_Int idx;
858 PS_Blend blend = decoder->blend;
859
860 if ( arg_cnt != 1 || blend == NULL )
861 goto Unexpected_OtherSubr;
862
863 idx = top[0];
864
865 if ( idx < 0 || (FT_UInt) idx >= decoder->len_buildchar )
866 goto Unexpected_OtherSubr;
867
868 top[0] = decoder->buildchar[idx];
869 }
870
871 known_othersubr_result_cnt = 1;
872 break;
873
874 #if 0
875 case 26:
876 /* <val> mark <idx> ==> set BuildCharArray[cvi( <idx> )] = <val>, */
877 /* leave mark on T1 stack */
878 /* <val> <idx> ==> set BuildCharArray[cvi( <idx> )] = <val> */
879 XXX who has left his mark on the (PostScript) stack ?;
880 break;
881 #endif
882
883 case 27:
884 /* <res1> <res2> <val1> <val2> 4 27 callothersubr pop */
885 /* ==> push <res1> onto T1 stack if <val1> <= <val2>, */
886 /* otherwise push <res2> */
887 if ( arg_cnt != 4 )
888 goto Unexpected_OtherSubr;
889
890 if ( top[2] > top[3] )
891 top[0] = top[1];
892
893 known_othersubr_result_cnt = 1;
894 break;
895
896 #ifdef CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS
897 case 28:
898 /* 0 28 callothersubr pop */
899 /* => push random value from interval [0, 1) onto stack */
900 if ( arg_cnt != 0 )
901 goto Unexpected_OtherSubr;
902
903 top[0] = FT_rand();
904 known_othersubr_result_cnt = 1;
905 break;
906 #endif
907
908 default:
909 FT_ERROR(( "t1_decoder_parse_charstrings: "
910 "unknown othersubr [%d %d], wish me luck!\n",
911 arg_cnt, subr_no ));
912 unknown_othersubr_result_cnt = arg_cnt;
913 break;
914
915 Unexpected_OtherSubr:
916 FT_ERROR(( "t1_decoder_parse_charstrings: "
917 "invalid othersubr [%d %d]!\n", arg_cnt, subr_no ));
918 goto Syntax_Error;
919 }
920
921 top += known_othersubr_result_cnt;
922
923 decoder->top = top;
924 }
925 else /* general operator */
926 {
927 FT_Int num_args = t1_args_count[op];
928
929
930 FT_ASSERT( num_args >= 0 );
931
932 if ( top - decoder->stack < num_args )
933 goto Stack_Underflow;
934
935 /* XXX Operators usually take their operands from the */
936 /* bottom of the stack, i.e., the operands are */
937 /* decoder->stack[0], ..., decoder->stack[num_args - 1]; */
938 /* only div, callsubr, and callothersubr are different. */
939 /* In practice it doesn't matter (?). */
940
941 #ifdef FT_DEBUG_LEVEL_TRACE
942
943 switch ( op )
944 {
945 case op_callsubr:
946 case op_div:
947 case op_callothersubr:
948 case op_pop:
949 case op_return:
950 break;
951
952 default:
953 if ( top - decoder->stack != num_args )
954 FT_TRACE0(( "t1_decoder_parse_charstrings: "
955 "too much operands on the stack "
956 "(seen %d, expected %d)\n",
957 top - decoder->stack, num_args ));
958 break;
959 }
960
961 #endif /* FT_DEBUG_LEVEL_TRACE */
962
963 top -= num_args;
964
965 switch ( op )
966 {
967 case op_endchar:
968 FT_TRACE4(( " endchar" ));
969
970 close_contour( builder );
971
972 /* close hints recording session */
973 if ( hinter )
974 {
975 if (hinter->close( hinter->hints, builder->current->n_points ))
976 goto Syntax_Error;
977
978 /* apply hints to the loaded glyph outline now */
979 hinter->apply( hinter->hints,
980 builder->current,
981 (PSH_Globals) builder->hints_globals,
982 decoder->hint_mode );
983 }
984
985 /* add current outline to the glyph slot */
986 FT_GlyphLoader_Add( builder->loader );
987
988 FT_TRACE4(( "\n" ));
989
990 /* the compiler should optimize away this empty loop but ... */
991
992 #ifdef FT_DEBUG_LEVEL_TRACE
993
994 if ( decoder->len_buildchar > 0 )
995 {
996 FT_UInt i;
997
998
999 FT_TRACE4(( "BuildCharArray = [ " ));
1000
1001 for ( i = 0; i < decoder->len_buildchar; ++i )
1002 FT_TRACE4(( "%d ", decoder->buildchar[ i ] ));
1003
1004 FT_TRACE4(( "]\n" ));
1005 }
1006
1007 #endif /* FT_DEBUG_LEVEL_TRACE */
1008
1009 FT_TRACE4(( "\n" ));
1010
1011 /* return now! */
1012 return PSaux_Err_Ok;
1013
1014 case op_hsbw:
1015 FT_TRACE4(( " hsbw" ));
1016
1017 builder->parse_state = T1_Parse_Have_Width;
1018
1019 builder->left_bearing.x += top[0];
1020 builder->advance.x = top[1];
1021 builder->advance.y = 0;
1022
1023 orig_x = builder->last.x = x = builder->pos_x + top[0];
1024 orig_y = builder->last.y = y = builder->pos_y;
1025
1026 FT_UNUSED( orig_y );
1027
1028 /* the `metrics_only' indicates that we only want to compute */
1029 /* the glyph's metrics (lsb + advance width), not load the */
1030 /* rest of it; so exit immediately */
1031 if ( builder->metrics_only )
1032 return PSaux_Err_Ok;
1033
1034 break;
1035
1036 case op_seac:
1037 /* return immediately after the processing */
1038 return t1operator_seac( decoder, top[0], top[1], top[2],
1039 (FT_Int)top[3], (FT_Int)top[4] );
1040
1041 case op_sbw:
1042 FT_TRACE4(( " sbw" ));
1043
1044 builder->parse_state = T1_Parse_Have_Width;
1045
1046 builder->left_bearing.x += top[0];
1047 builder->left_bearing.y += top[1];
1048 builder->advance.x = top[2];
1049 builder->advance.y = top[3];
1050
1051 builder->last.x = x = builder->pos_x + top[0];
1052 builder->last.y = y = builder->pos_y + top[1];
1053
1054 /* the `metrics_only' indicates that we only want to compute */
1055 /* the glyph's metrics (lsb + advance width), not load the */
1056 /* rest of it; so exit immediately */
1057 if ( builder->metrics_only )
1058 return PSaux_Err_Ok;
1059
1060 break;
1061
1062 case op_closepath:
1063 FT_TRACE4(( " closepath" ));
1064
1065 close_contour( builder );
1066 if ( !( builder->parse_state == T1_Parse_Have_Path ||
1067 builder->parse_state == T1_Parse_Have_Moveto ) )
1068 goto Syntax_Error;
1069 builder->parse_state = T1_Parse_Have_Width;
1070 break;
1071
1072 case op_hlineto:
1073 FT_TRACE4(( " hlineto" ));
1074
1075 if ( start_point( builder, x, y ) )
1076 goto Fail;
1077
1078 x += top[0];
1079 goto Add_Line;
1080
1081 case op_hmoveto:
1082 FT_TRACE4(( " hmoveto" ));
1083
1084 x += top[0];
1085 if ( !decoder->flex_state )
1086 {
1087 if ( builder->parse_state == T1_Parse_Start )
1088 goto Syntax_Error;
1089 builder->parse_state = T1_Parse_Have_Moveto;
1090 }
1091 break;
1092
1093 case op_hvcurveto:
1094 FT_TRACE4(( " hvcurveto" ));
1095
1096 if ( start_point( builder, x, y ) ||
1097 check_points( builder, 3 ) )
1098 goto Fail;
1099
1100 x += top[0];
1101 add_point( builder, x, y, 0 );
1102 x += top[1];
1103 y += top[2];
1104 add_point( builder, x, y, 0 );
1105 y += top[3];
1106 add_point( builder, x, y, 1 );
1107 break;
1108
1109 case op_rlineto:
1110 FT_TRACE4(( " rlineto" ));
1111
1112 if ( start_point( builder, x, y ) )
1113 goto Fail;
1114
1115 x += top[0];
1116 y += top[1];
1117
1118 Add_Line:
1119 if ( add_point1( builder, x, y ) )
1120 goto Fail;
1121 break;
1122
1123 case op_rmoveto:
1124 FT_TRACE4(( " rmoveto" ));
1125
1126 x += top[0];
1127 y += top[1];
1128 if ( !decoder->flex_state )
1129 {
1130 if ( builder->parse_state == T1_Parse_Start )
1131 goto Syntax_Error;
1132 builder->parse_state = T1_Parse_Have_Moveto;
1133 }
1134 break;
1135
1136 case op_rrcurveto:
1137 FT_TRACE4(( " rcurveto" ));
1138
1139 if ( start_point( builder, x, y ) ||
1140 check_points( builder, 3 ) )
1141 goto Fail;
1142
1143 x += top[0];
1144 y += top[1];
1145 add_point( builder, x, y, 0 );
1146
1147 x += top[2];
1148 y += top[3];
1149 add_point( builder, x, y, 0 );
1150
1151 x += top[4];
1152 y += top[5];
1153 add_point( builder, x, y, 1 );
1154 break;
1155
1156 case op_vhcurveto:
1157 FT_TRACE4(( " vhcurveto" ));
1158
1159 if ( start_point( builder, x, y ) ||
1160 check_points( builder, 3 ) )
1161 goto Fail;
1162
1163 y += top[0];
1164 add_point( builder, x, y, 0 );
1165 x += top[1];
1166 y += top[2];
1167 add_point( builder, x, y, 0 );
1168 x += top[3];
1169 add_point( builder, x, y, 1 );
1170 break;
1171
1172 case op_vlineto:
1173 FT_TRACE4(( " vlineto" ));
1174
1175 if ( start_point( builder, x, y ) )
1176 goto Fail;
1177
1178 y += top[0];
1179 goto Add_Line;
1180
1181 case op_vmoveto:
1182 FT_TRACE4(( " vmoveto" ));
1183
1184 y += top[0];
1185 if ( !decoder->flex_state )
1186 {
1187 if ( builder->parse_state == T1_Parse_Start )
1188 goto Syntax_Error;
1189 builder->parse_state = T1_Parse_Have_Moveto;
1190 }
1191 break;
1192
1193 case op_div:
1194 FT_TRACE4(( " div" ));
1195
1196 if ( top[1] )
1197 {
1198 *top = top[0] / top[1];
1199 ++top;
1200 }
1201 else
1202 {
1203 FT_ERROR(( "t1_decoder_parse_charstrings: division by 0\n" ));
1204 goto Syntax_Error;
1205 }
1206 break;
1207
1208 case op_callsubr:
1209 {
1210 FT_Int idx;
1211
1212
1213 FT_TRACE4(( " callsubr" ));
1214
1215 idx = (FT_Int)top[0];
1216 if ( idx < 0 || idx >= (FT_Int)decoder->num_subrs )
1217 {
1218 FT_ERROR(( "t1_decoder_parse_charstrings: "
1219 "invalid subrs index\n" ));
1220 goto Syntax_Error;
1221 }
1222
1223 if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS )
1224 {
1225 FT_ERROR(( "t1_decoder_parse_charstrings: "
1226 "too many nested subrs\n" ));
1227 goto Syntax_Error;
1228 }
1229
1230 zone->cursor = ip; /* save current instruction pointer */
1231
1232 zone++;
1233
1234 /* The Type 1 driver stores subroutines without the seed bytes. */
1235 /* The CID driver stores subroutines with seed bytes. This */
1236 /* case is taken care of when decoder->subrs_len == 0. */
1237 zone->base = decoder->subrs[idx];
1238
1239 if ( decoder->subrs_len )
1240 zone->limit = zone->base + decoder->subrs_len[idx];
1241 else
1242 {
1243 /* We are using subroutines from a CID font. We must adjust */
1244 /* for the seed bytes. */
1245 zone->base += ( decoder->lenIV >= 0 ? decoder->lenIV : 0 );
1246 zone->limit = decoder->subrs[idx + 1];
1247 }
1248
1249 zone->cursor = zone->base;
1250
1251 if ( !zone->base )
1252 {
1253 FT_ERROR(( "t1_decoder_parse_charstrings: "
1254 "invoking empty subrs!\n" ));
1255 goto Syntax_Error;
1256 }
1257
1258 decoder->zone = zone;
1259 ip = zone->base;
1260 limit = zone->limit;
1261 break;
1262 }
1263
1264 case op_pop:
1265 FT_TRACE4(( " pop" ));
1266
1267 if ( known_othersubr_result_cnt > 0 )
1268 {
1269 known_othersubr_result_cnt--;
1270 /* ignore, we pushed the operands ourselves */
1271 break;
1272 }
1273
1274 if ( unknown_othersubr_result_cnt == 0 )
1275 {
1276 FT_ERROR(( "t1_decoder_parse_charstrings: "
1277 "no more operands for othersubr!\n" ));
1278 goto Syntax_Error;
1279 }
1280
1281 unknown_othersubr_result_cnt--;
1282 top++; /* `push' the operand to callothersubr onto the stack */
1283 break;
1284
1285 case op_return:
1286 FT_TRACE4(( " return" ));
1287
1288 if ( zone <= decoder->zones )
1289 {
1290 FT_ERROR(( "t1_decoder_parse_charstrings: unexpected return\n" ));
1291 goto Syntax_Error;
1292 }
1293
1294 zone--;
1295 ip = zone->cursor;
1296 limit = zone->limit;
1297 decoder->zone = zone;
1298 break;
1299
1300 case op_dotsection:
1301 FT_TRACE4(( " dotsection" ));
1302
1303 break;
1304
1305 case op_hstem:
1306 FT_TRACE4(( " hstem" ));
1307
1308 /* record horizontal hint */
1309 if ( hinter )
1310 {
1311 /* top[0] += builder->left_bearing.y; */
1312 hinter->stem( hinter->hints, 1, top );
1313 }
1314
1315 break;
1316
1317 case op_hstem3:
1318 FT_TRACE4(( " hstem3" ));
1319
1320 /* record horizontal counter-controlled hints */
1321 if ( hinter )
1322 hinter->stem3( hinter->hints, 1, top );
1323
1324 break;
1325
1326 case op_vstem:
1327 FT_TRACE4(( " vstem" ));
1328
1329 /* record vertical hint */
1330 if ( hinter )
1331 {
1332 top[0] += orig_x;
1333 hinter->stem( hinter->hints, 0, top );
1334 }
1335
1336 break;
1337
1338 case op_vstem3:
1339 FT_TRACE4(( " vstem3" ));
1340
1341 /* record vertical counter-controlled hints */
1342 if ( hinter )
1343 {
1344 FT_Pos dx = orig_x;
1345
1346
1347 top[0] += dx;
1348 top[2] += dx;
1349 top[4] += dx;
1350 hinter->stem3( hinter->hints, 0, top );
1351 }
1352 break;
1353
1354 case op_setcurrentpoint:
1355 FT_TRACE4(( " setcurrentpoint" ));
1356
1357 /* From the T1 specs, section 6.4: */
1358 /* */
1359 /* The setcurrentpoint command is used only in */
1360 /* conjunction with results from OtherSubrs procedures. */
1361
1362 /* known_othersubr_result_cnt != 0 is already handled above */
1363 if ( decoder->flex_state != 1 )
1364 {
1365 FT_ERROR(( "t1_decoder_parse_charstrings: " ));
1366 FT_ERROR(( "unexpected `setcurrentpoint'\n" ));
1367
1368 goto Syntax_Error;
1369 }
1370 else
1371 decoder->flex_state = 0;
1372 break;
1373
1374 case op_unknown15:
1375 FT_TRACE4(( " opcode_15" ));
1376 /* nothing to do except to pop the two arguments */
1377 break;
1378
1379 default:
1380 FT_ERROR(( "t1_decoder_parse_charstrings: "
1381 "unhandled opcode %d\n", op ));
1382 goto Syntax_Error;
1383 }
1384
1385 /* XXX Operators usually clear the operand stack; */
1386 /* only div, callsubr, callothersubr, pop, and */
1387 /* return are different. */
1388 /* In practice it doesn't matter (?). */
1389
1390 decoder->top = top;
1391
1392 } /* general operator processing */
1393
1394 } /* while ip < limit */
1395
1396 FT_TRACE4(( "..end..\n\n" ));
1397
1398 Fail:
1399 return error;
1400
1401 Syntax_Error:
1402 return PSaux_Err_Syntax_Error;
1403
1404 Stack_Underflow:
1405 return PSaux_Err_Stack_Underflow;
1406 }
1407
1408
1409 /* parse a single Type 1 glyph */
1410 FT_LOCAL_DEF( FT_Error )
1411 t1_decoder_parse_glyph( T1_Decoder decoder,
1412 FT_UInt glyph )
1413 {
1414 return decoder->parse_callback( decoder, glyph );
1415 }
1416
1417
1418 /* initialize T1 decoder */
1419 FT_LOCAL_DEF( FT_Error )
1420 t1_decoder_init( T1_Decoder decoder,
1421 FT_Face face,
1422 FT_Size size,
1423 FT_GlyphSlot slot,
1424 FT_Byte** glyph_names,
1425 PS_Blend blend,
1426 FT_Bool hinting,
1427 FT_Render_Mode hint_mode,
1428 T1_Decoder_Callback parse_callback )
1429 {
1430 FT_MEM_ZERO( decoder, sizeof ( *decoder ) );
1431
1432 /* retrieve PSNames interface from list of current modules */
1433 {
1434 FT_Service_PsCMaps psnames = 0;
1435
1436
1437 FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS );
1438 if ( !psnames )
1439 {
1440 FT_ERROR(( "t1_decoder_init: " ));
1441 FT_ERROR(( "the `psnames' module is not available\n" ));
1442 return PSaux_Err_Unimplemented_Feature;
1443 }
1444
1445 decoder->psnames = psnames;
1446 }
1447
1448 t1_builder_init( &decoder->builder, face, size, slot, hinting );
1449
1450 /* decoder->buildchar and decoder->len_buildchar have to be */
1451 /* initialized by the caller since we cannot know the length */
1452 /* of the BuildCharArray */
1453
1454 decoder->num_glyphs = (FT_UInt)face->num_glyphs;
1455 decoder->glyph_names = glyph_names;
1456 decoder->hint_mode = hint_mode;
1457 decoder->blend = blend;
1458 decoder->parse_callback = parse_callback;
1459
1460 decoder->funcs = t1_decoder_funcs;
1461
1462 return PSaux_Err_Ok;
1463 }
1464
1465
1466 /* finalize T1 decoder */
1467 FT_LOCAL_DEF( void )
1468 t1_decoder_done( T1_Decoder decoder )
1469 {
1470 t1_builder_done( &decoder->builder );
1471 }
1472
1473
1474 /* END */