1 /***************************************************************************/
5 /* PostScript Type 1 decoding routines (body). */
7 /* Copyright 2000-2001, 2002, 2003, 2004, 2005, 2006, 2007 by */
8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */
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. */
16 /***************************************************************************/
20 #include FT_INTERNAL_DEBUG_H
21 #include FT_INTERNAL_POSTSCRIPT_HINTS_H
30 /*************************************************************************/
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. */
37 #define FT_COMPONENT trace_t1decode
40 typedef enum T1_Operator_
70 op_max
/* never remove this one */
76 const FT_Int t1_args_count
[op_max
] =
99 -1, /* callothersubr */
103 2, /* setcurrentpoint */
104 2 /* opcode 15 (undocumented and obsolete) */
108 /*************************************************************************/
111 /* t1_lookup_glyph_by_stdcharcode */
114 /* Looks up a given glyph by its StandardEncoding charcode. Used to */
115 /* implement the SEAC Type 1 operator. */
118 /* face :: The current face object. */
120 /* charcode :: The character code to look for. */
123 /* A glyph index in the font face. Returns -1 if the corresponding */
124 /* glyph wasn't found. */
127 t1_lookup_glyph_by_stdcharcode( T1_Decoder decoder
,
131 const FT_String
* glyph_name
;
132 FT_Service_PsCMaps psnames
= decoder
->psnames
;
135 /* check range of standard char code */
136 if ( charcode
< 0 || charcode
> 255 )
139 glyph_name
= psnames
->adobe_std_strings(
140 psnames
->adobe_std_encoding
[charcode
]);
142 for ( n
= 0; n
< decoder
->num_glyphs
; n
++ )
144 FT_String
* name
= (FT_String
*)decoder
->glyph_names
[n
];
147 if ( name
&& name
[0] == glyph_name
[0] &&
148 ft_strcmp( name
, glyph_name
) == 0 )
156 /*************************************************************************/
159 /* t1operator_seac */
162 /* Implements the `seac' Type 1 operator for a Type 1 decoder. */
165 /* decoder :: The current CID decoder. */
167 /* asb :: The accent's side bearing. */
169 /* adx :: The horizontal offset of the accent. */
171 /* ady :: The vertical offset of the accent. */
173 /* bchar :: The base character's StandardEncoding charcode. */
175 /* achar :: The accent character's StandardEncoding charcode. */
178 /* FreeType error code. 0 means success. */
181 t1operator_seac( T1_Decoder decoder
,
189 FT_Int bchar_index
, achar_index
;
191 FT_Int n_base_points
;
192 FT_Outline
* base
= decoder
->builder
.base
;
194 FT_Vector left_bearing
, advance
;
198 adx
+= decoder
->builder
.left_bearing
.x
;
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 )
204 FT_ERROR(( "t1operator_seac:" ));
205 FT_ERROR(( " glyph names table not available in this font!\n" ));
206 return PSaux_Err_Syntax_Error
;
209 bchar_index
= t1_lookup_glyph_by_stdcharcode( decoder
, bchar
);
210 achar_index
= t1_lookup_glyph_by_stdcharcode( decoder
, achar
);
212 if ( bchar_index
< 0 || achar_index
< 0 )
214 FT_ERROR(( "t1operator_seac:" ));
215 FT_ERROR(( " invalid seac character code arguments\n" ));
216 return PSaux_Err_Syntax_Error
;
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
)
223 FT_GlyphSlot glyph
= (FT_GlyphSlot
)decoder
->builder
.glyph
;
224 FT_GlyphLoader loader
= glyph
->internal
->loader
;
228 /* reallocate subglyph array if necessary */
229 error
= FT_GlyphLoader_CheckSubGlyphs( loader
, 2 );
233 subg
= loader
->current
.subglyphs
;
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
;
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
;
249 /* set up remaining glyph fields */
250 glyph
->num_subglyphs
= 2;
251 glyph
->subglyphs
= loader
->base
.subglyphs
;
252 glyph
->format
= FT_GLYPH_FORMAT_COMPOSITE
;
254 loader
->current
.num_subglyphs
= 2;
258 /* First load `bchar' in builder */
259 /* now load the unscaled outline */
261 FT_GlyphLoader_Prepare( decoder
->builder
.loader
); /* prepare loader */
263 error
= t1_decoder_parse_glyph( decoder
, bchar_index
);
267 /* save the left bearing and width of the base character */
268 /* as they will be erased by the next load. */
270 left_bearing
= decoder
->builder
.left_bearing
;
271 advance
= decoder
->builder
.advance
;
273 decoder
->builder
.left_bearing
.x
= 0;
274 decoder
->builder
.left_bearing
.y
= 0;
276 decoder
->builder
.pos_x
= adx
- asb
;
277 decoder
->builder
.pos_y
= ady
;
279 /* Now load `achar' on top of */
280 /* the base outline */
281 error
= t1_decoder_parse_glyph( decoder
, achar_index
);
285 /* restore the left side bearing and */
286 /* advance width of the base character */
288 decoder
->builder
.left_bearing
= left_bearing
;
289 decoder
->builder
.advance
= advance
;
291 decoder
->builder
.pos_x
= 0;
292 decoder
->builder
.pos_y
= 0;
299 /*************************************************************************/
302 /* t1_decoder_parse_charstrings */
305 /* Parses a given Type 1 charstrings program. */
308 /* decoder :: The current Type 1 decoder. */
310 /* charstring_base :: The base address of the charstring stream. */
312 /* charstring_len :: The length in bytes of the charstring stream. */
315 /* FreeType error code. 0 means success. */
317 FT_LOCAL_DEF( FT_Error
)
318 t1_decoder_parse_charstrings( T1_Decoder decoder
,
319 FT_Byte
* charstring_base
,
320 FT_UInt charstring_len
)
323 T1_Decoder_Zone zone
;
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;
331 T1_Hints_Funcs hinter
;
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
342 /* First of all, initialize the decoder */
343 decoder
->top
= decoder
->stack
;
344 decoder
->zone
= decoder
->zones
;
345 zone
= decoder
->zones
;
347 builder
->parse_state
= T1_Parse_Start
;
349 hinter
= (T1_Hints_Funcs
)builder
->hints_funcs
;
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
) );
356 if ( decoder
->len_buildchar
> 0 )
357 memset( &decoder
->buildchar
[0],
359 sizeof( decoder
->buildchar
[0] ) *
360 decoder
->len_buildchar
);
362 FT_TRACE4(( "\nStart charstring\n" ));
364 zone
->base
= charstring_base
;
365 limit
= zone
->limit
= charstring_base
+ charstring_len
;
366 ip
= zone
->cursor
= zone
->base
;
368 error
= PSaux_Err_Ok
;
370 x
= orig_x
= builder
->pos_x
;
371 y
= orig_y
= builder
->pos_y
;
373 /* begin hints recording session, if any */
375 hinter
->open( hinter
->hints
);
377 /* now, execute loop */
380 FT_Long
* top
= decoder
->top
;
381 T1_Operator op
= op_none
;
385 FT_ASSERT( known_othersubr_result_cnt
== 0 ||
386 unknown_othersubr_result_cnt
== 0 );
388 FT_TRACE5(( " (%d)", decoder
->top
- decoder
->stack
));
390 /*********************************************************************/
392 /* Decode operator or operand */
396 /* first of all, decompress operator or value */
438 case 15: /* undocumented, obsolete operator */
459 FT_ERROR(( "t1_decoder_parse_charstrings: "
460 "invalid escape (12+EOF)\n" ));
485 op
= op_callothersubr
;
491 op
= op_setcurrentpoint
;
495 FT_ERROR(( "t1_decoder_parse_charstrings: "
496 "invalid escape (12+%d)\n",
502 case 255: /* four bytes integer */
503 if ( ip
+ 4 > limit
)
505 FT_ERROR(( "t1_decoder_parse_charstrings: "
506 "unexpected EOF in integer\n" ));
510 value
= (FT_Int32
)( ((FT_Long
)ip
[0] << 24) |
511 ((FT_Long
)ip
[1] << 16) |
512 ((FT_Long
)ip
[2] << 8 ) |
521 value
= (FT_Long
)ip
[-1] - 139;
526 FT_ERROR(( "t1_decoder_parse_charstrings: " ));
527 FT_ERROR(( "unexpected EOF in integer\n" ));
532 value
= ( ( (FT_Long
)ip
[-2] - 247 ) << 8 ) + ip
[-1] + 108;
534 value
= -( ( ( (FT_Long
)ip
[-2] - 251 ) << 8 ) + ip
[-1] + 108 );
539 FT_ERROR(( "t1_decoder_parse_charstrings: "
540 "invalid byte (%d)\n", ip
[-1] ));
545 if ( unknown_othersubr_result_cnt
> 0 )
556 /* all operands have been transferred by previous pops */
557 unknown_othersubr_result_cnt
= 0;
562 /*********************************************************************/
564 /* Push value on stack, or process operator */
569 if ( top
- decoder
->stack
>= T1_MAX_CHARSTRINGS_OPERANDS
)
571 FT_ERROR(( "t1_decoder_parse_charstrings: stack overflow!\n" ));
575 FT_TRACE4(( " %ld", value
));
580 else if ( op
== op_callothersubr
) /* callothersubr */
586 FT_TRACE4(( " callothersubr" ));
588 if ( top
- decoder
->stack
< 2 )
589 goto Stack_Underflow
;
593 subr_no
= (FT_Int
)top
[1];
594 arg_cnt
= (FT_Int
)top
[0];
596 /***********************************************************/
598 /* remove all operands to callothersubr from the stack */
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 */
604 /* for unhandled othersubrs the following pops adjust the */
605 /* stack pointer as necessary */
607 if ( arg_cnt
> top
- decoder
->stack
)
608 goto Stack_Underflow
;
612 known_othersubr_result_cnt
= 0;
613 unknown_othersubr_result_cnt
= 0;
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 */
623 /* On the other hand, Adobe Reader 7.0.8 for Linux doesn't */
624 /* accept a font that contains charstrings like */
626 /* 100 200 2 20 callothersubr */
627 /* 300 1 20 callothersubr pop */
629 /* Perhaps this is the reason why BuildCharArray exists. */
633 case 1: /* start flex feature */
635 goto Unexpected_OtherSubr
;
637 decoder
->flex_state
= 1;
638 decoder
->num_flex_vectors
= 0;
639 if ( start_point( builder
, x
, y
) ||
640 check_points( builder
, 6 ) )
644 case 2: /* add flex vectors */
650 goto Unexpected_OtherSubr
;
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 )
660 (FT_Byte
)( idx
== 3 || idx
== 6 ) );
664 case 0: /* end flex feature */
666 goto Unexpected_OtherSubr
;
668 if ( decoder
->flex_state
== 0 ||
669 decoder
->num_flex_vectors
!= 7 )
671 FT_ERROR(( "t1_decoder_parse_charstrings: "
672 "unexpected flex end\n" ));
676 /* the two `results' are popped by the following setcurrentpoint */
677 known_othersubr_result_cnt
= 2;
680 case 3: /* change hints */
682 goto Unexpected_OtherSubr
;
684 known_othersubr_result_cnt
= 1;
687 hinter
->reset( hinter
->hints
, builder
->current
->n_points
);
693 /* counter control hints, clear stack */
694 top
= decoder
->stack
;
701 case 18: /* multiple masters */
703 PS_Blend blend
= decoder
->blend
;
704 FT_UInt num_points
, nn
, mm
;
711 FT_ERROR(( "t1_decoder_parse_charstrings: " ));
712 FT_ERROR(( "unexpected multiple masters operator!\n" ));
716 num_points
= (FT_UInt
)subr_no
- 13 + ( subr_no
== 18 );
717 if ( arg_cnt
!= (FT_Int
)( num_points
* blend
->num_designs
) )
719 FT_ERROR(( "t1_decoder_parse_charstrings: " ));
720 FT_ERROR(( "incorrect number of mm arguments\n" ));
724 /* we want to compute: */
726 /* a0*w0 + a1*w1 + ... + ak*wk */
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: */
732 /* a0 + (a1-a0)*w1 + (a2-a0)*w2 + .. + (ak-a0)*wk */
734 /* where k == num_designs-1 */
736 /* I guess that's why it's written in this `compact' */
739 delta
= top
+ num_points
;
741 for ( nn
= 0; nn
< num_points
; nn
++ )
743 FT_Long tmp
= values
[0];
746 for ( mm
= 1; mm
< blend
->num_designs
; mm
++ )
747 tmp
+= FT_MulFix( *delta
++, blend
->weight_vector
[mm
] );
752 known_othersubr_result_cnt
= num_points
;
756 #ifdef CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS
758 /* We cannot yet enable these since currently */
759 /* our T1 stack stores integers which lack the */
760 /* precision to express the values */
763 /* <idx> 1 19 callothersubr */
764 /* => replace elements starting from index cvi( <idx> ) */
765 /* of BuildCharArray with WeightVector */
768 PS_Blend blend
= decoder
->blend
;
771 if ( arg_cnt
!= 1 || blend
== NULL
)
772 goto Unexpected_OtherSubr
;
777 idx
+ blend
->num_designs
> decoder
->face
->len_buildchar
)
778 goto Unexpected_OtherSubr
;
780 memcpy( &decoder
->buildchar
[idx
],
781 blend
->weight_vector
,
783 sizeof( blend
->weight_vector
[ 0 ] ) );
788 /* <arg1> <arg2> 2 20 callothersubr pop */
789 /* ==> push <arg1> + <arg2> onto T1 stack */
791 goto Unexpected_OtherSubr
;
793 top
[0] += top
[1]; /* XXX (over|under)flow */
795 known_othersubr_result_cnt
= 1;
799 /* <arg1> <arg2> 2 21 callothersubr pop */
800 /* ==> push <arg1> - <arg2> onto T1 stack */
802 goto Unexpected_OtherSubr
;
804 top
[0] -= top
[1]; /* XXX (over|under)flow */
806 known_othersubr_result_cnt
= 1;
810 /* <arg1> <arg2> 2 22 callothersubr pop */
811 /* ==> push <arg1> * <arg2> onto T1 stack */
813 goto Unexpected_OtherSubr
;
815 top
[0] *= top
[1]; /* XXX (over|under)flow */
817 known_othersubr_result_cnt
= 1;
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
;
826 top
[0] /= top
[1]; /* XXX (over|under)flow */
828 known_othersubr_result_cnt
= 1;
831 #endif /* CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS */
834 /* <val> <idx> 2 24 callothersubr */
835 /* => set BuildCharArray[cvi( <idx> )] = <val> */
838 PS_Blend blend
= decoder
->blend
;
840 if ( arg_cnt
!= 2 || blend
== NULL
)
841 goto Unexpected_OtherSubr
;
845 if ( idx
< 0 || (FT_UInt
) idx
>= decoder
->len_buildchar
)
846 goto Unexpected_OtherSubr
;
848 decoder
->buildchar
[idx
] = top
[0];
853 /* <idx> 1 25 callothersubr pop */
854 /* => push BuildCharArray[cvi( idx )] */
858 PS_Blend blend
= decoder
->blend
;
860 if ( arg_cnt
!= 1 || blend
== NULL
)
861 goto Unexpected_OtherSubr
;
865 if ( idx
< 0 || (FT_UInt
) idx
>= decoder
->len_buildchar
)
866 goto Unexpected_OtherSubr
;
868 top
[0] = decoder
->buildchar
[idx
];
871 known_othersubr_result_cnt
= 1;
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
?;
884 /* <res1> <res2> <val1> <val2> 4 27 callothersubr pop */
885 /* ==> push <res1> onto T1 stack if <val1> <= <val2>, */
886 /* otherwise push <res2> */
888 goto Unexpected_OtherSubr
;
890 if ( top
[2] > top
[3] )
893 known_othersubr_result_cnt
= 1;
896 #ifdef CAN_HANDLE_NON_INTEGRAL_T1_OPERANDS
898 /* 0 28 callothersubr pop */
899 /* => push random value from interval [0, 1) onto stack */
901 goto Unexpected_OtherSubr
;
904 known_othersubr_result_cnt
= 1;
909 FT_ERROR(( "t1_decoder_parse_charstrings: "
910 "unknown othersubr [%d %d], wish me luck!\n",
912 unknown_othersubr_result_cnt
= arg_cnt
;
915 Unexpected_OtherSubr
:
916 FT_ERROR(( "t1_decoder_parse_charstrings: "
917 "invalid othersubr [%d %d]!\n", arg_cnt
, subr_no
));
921 top
+= known_othersubr_result_cnt
;
925 else /* general operator */
927 FT_Int num_args
= t1_args_count
[op
];
930 FT_ASSERT( num_args
>= 0 );
932 if ( top
- decoder
->stack
< num_args
)
933 goto Stack_Underflow
;
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 (?). */
941 #ifdef FT_DEBUG_LEVEL_TRACE
947 case op_callothersubr
:
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
));
961 #endif /* FT_DEBUG_LEVEL_TRACE */
968 FT_TRACE4(( " endchar" ));
970 close_contour( builder
);
972 /* close hints recording session */
975 if (hinter
->close( hinter
->hints
, builder
->current
->n_points
))
978 /* apply hints to the loaded glyph outline now */
979 hinter
->apply( hinter
->hints
,
981 (PSH_Globals
) builder
->hints_globals
,
982 decoder
->hint_mode
);
985 /* add current outline to the glyph slot */
986 FT_GlyphLoader_Add( builder
->loader
);
990 /* the compiler should optimize away this empty loop but ... */
992 #ifdef FT_DEBUG_LEVEL_TRACE
994 if ( decoder
->len_buildchar
> 0 )
999 FT_TRACE4(( "BuildCharArray = [ " ));
1001 for ( i
= 0; i
< decoder
->len_buildchar
; ++i
)
1002 FT_TRACE4(( "%d ", decoder
->buildchar
[ i
] ));
1004 FT_TRACE4(( "]\n" ));
1007 #endif /* FT_DEBUG_LEVEL_TRACE */
1009 FT_TRACE4(( "\n" ));
1012 return PSaux_Err_Ok
;
1015 FT_TRACE4(( " hsbw" ));
1017 builder
->parse_state
= T1_Parse_Have_Width
;
1019 builder
->left_bearing
.x
+= top
[0];
1020 builder
->advance
.x
= top
[1];
1021 builder
->advance
.y
= 0;
1023 orig_x
= builder
->last
.x
= x
= builder
->pos_x
+ top
[0];
1024 orig_y
= builder
->last
.y
= y
= builder
->pos_y
;
1026 FT_UNUSED( orig_y
);
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
;
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] );
1042 FT_TRACE4(( " sbw" ));
1044 builder
->parse_state
= T1_Parse_Have_Width
;
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];
1051 builder
->last
.x
= x
= builder
->pos_x
+ top
[0];
1052 builder
->last
.y
= y
= builder
->pos_y
+ top
[1];
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
;
1063 FT_TRACE4(( " closepath" ));
1065 close_contour( builder
);
1066 if ( !( builder
->parse_state
== T1_Parse_Have_Path
||
1067 builder
->parse_state
== T1_Parse_Have_Moveto
) )
1069 builder
->parse_state
= T1_Parse_Have_Width
;
1073 FT_TRACE4(( " hlineto" ));
1075 if ( start_point( builder
, x
, y
) )
1082 FT_TRACE4(( " hmoveto" ));
1085 if ( !decoder
->flex_state
)
1087 if ( builder
->parse_state
== T1_Parse_Start
)
1089 builder
->parse_state
= T1_Parse_Have_Moveto
;
1094 FT_TRACE4(( " hvcurveto" ));
1096 if ( start_point( builder
, x
, y
) ||
1097 check_points( builder
, 3 ) )
1101 add_point( builder
, x
, y
, 0 );
1104 add_point( builder
, x
, y
, 0 );
1106 add_point( builder
, x
, y
, 1 );
1110 FT_TRACE4(( " rlineto" ));
1112 if ( start_point( builder
, x
, y
) )
1119 if ( add_point1( builder
, x
, y
) )
1124 FT_TRACE4(( " rmoveto" ));
1128 if ( !decoder
->flex_state
)
1130 if ( builder
->parse_state
== T1_Parse_Start
)
1132 builder
->parse_state
= T1_Parse_Have_Moveto
;
1137 FT_TRACE4(( " rcurveto" ));
1139 if ( start_point( builder
, x
, y
) ||
1140 check_points( builder
, 3 ) )
1145 add_point( builder
, x
, y
, 0 );
1149 add_point( builder
, x
, y
, 0 );
1153 add_point( builder
, x
, y
, 1 );
1157 FT_TRACE4(( " vhcurveto" ));
1159 if ( start_point( builder
, x
, y
) ||
1160 check_points( builder
, 3 ) )
1164 add_point( builder
, x
, y
, 0 );
1167 add_point( builder
, x
, y
, 0 );
1169 add_point( builder
, x
, y
, 1 );
1173 FT_TRACE4(( " vlineto" ));
1175 if ( start_point( builder
, x
, y
) )
1182 FT_TRACE4(( " vmoveto" ));
1185 if ( !decoder
->flex_state
)
1187 if ( builder
->parse_state
== T1_Parse_Start
)
1189 builder
->parse_state
= T1_Parse_Have_Moveto
;
1194 FT_TRACE4(( " div" ));
1198 *top
= top
[0] / top
[1];
1203 FT_ERROR(( "t1_decoder_parse_charstrings: division by 0\n" ));
1213 FT_TRACE4(( " callsubr" ));
1215 idx
= (FT_Int
)top
[0];
1216 if ( idx
< 0 || idx
>= (FT_Int
)decoder
->num_subrs
)
1218 FT_ERROR(( "t1_decoder_parse_charstrings: "
1219 "invalid subrs index\n" ));
1223 if ( zone
- decoder
->zones
>= T1_MAX_SUBRS_CALLS
)
1225 FT_ERROR(( "t1_decoder_parse_charstrings: "
1226 "too many nested subrs\n" ));
1230 zone
->cursor
= ip
; /* save current instruction pointer */
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
];
1239 if ( decoder
->subrs_len
)
1240 zone
->limit
= zone
->base
+ decoder
->subrs_len
[idx
];
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];
1249 zone
->cursor
= zone
->base
;
1253 FT_ERROR(( "t1_decoder_parse_charstrings: "
1254 "invoking empty subrs!\n" ));
1258 decoder
->zone
= zone
;
1260 limit
= zone
->limit
;
1265 FT_TRACE4(( " pop" ));
1267 if ( known_othersubr_result_cnt
> 0 )
1269 known_othersubr_result_cnt
--;
1270 /* ignore, we pushed the operands ourselves */
1274 if ( unknown_othersubr_result_cnt
== 0 )
1276 FT_ERROR(( "t1_decoder_parse_charstrings: "
1277 "no more operands for othersubr!\n" ));
1281 unknown_othersubr_result_cnt
--;
1282 top
++; /* `push' the operand to callothersubr onto the stack */
1286 FT_TRACE4(( " return" ));
1288 if ( zone
<= decoder
->zones
)
1290 FT_ERROR(( "t1_decoder_parse_charstrings: unexpected return\n" ));
1296 limit
= zone
->limit
;
1297 decoder
->zone
= zone
;
1301 FT_TRACE4(( " dotsection" ));
1306 FT_TRACE4(( " hstem" ));
1308 /* record horizontal hint */
1311 /* top[0] += builder->left_bearing.y; */
1312 hinter
->stem( hinter
->hints
, 1, top
);
1318 FT_TRACE4(( " hstem3" ));
1320 /* record horizontal counter-controlled hints */
1322 hinter
->stem3( hinter
->hints
, 1, top
);
1327 FT_TRACE4(( " vstem" ));
1329 /* record vertical hint */
1333 hinter
->stem( hinter
->hints
, 0, top
);
1339 FT_TRACE4(( " vstem3" ));
1341 /* record vertical counter-controlled hints */
1350 hinter
->stem3( hinter
->hints
, 0, top
);
1354 case op_setcurrentpoint
:
1355 FT_TRACE4(( " setcurrentpoint" ));
1357 /* From the T1 specs, section 6.4: */
1359 /* The setcurrentpoint command is used only in */
1360 /* conjunction with results from OtherSubrs procedures. */
1362 /* known_othersubr_result_cnt != 0 is already handled above */
1363 if ( decoder
->flex_state
!= 1 )
1365 FT_ERROR(( "t1_decoder_parse_charstrings: " ));
1366 FT_ERROR(( "unexpected `setcurrentpoint'\n" ));
1371 decoder
->flex_state
= 0;
1375 FT_TRACE4(( " opcode_15" ));
1376 /* nothing to do except to pop the two arguments */
1380 FT_ERROR(( "t1_decoder_parse_charstrings: "
1381 "unhandled opcode %d\n", op
));
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 (?). */
1392 } /* general operator processing */
1394 } /* while ip < limit */
1396 FT_TRACE4(( "..end..\n\n" ));
1402 return PSaux_Err_Syntax_Error
;
1405 return PSaux_Err_Stack_Underflow
;
1409 /* parse a single Type 1 glyph */
1410 FT_LOCAL_DEF( FT_Error
)
1411 t1_decoder_parse_glyph( T1_Decoder decoder
,
1414 return decoder
->parse_callback( decoder
, glyph
);
1418 /* initialize T1 decoder */
1419 FT_LOCAL_DEF( FT_Error
)
1420 t1_decoder_init( T1_Decoder decoder
,
1424 FT_Byte
** glyph_names
,
1427 FT_Render_Mode hint_mode
,
1428 T1_Decoder_Callback parse_callback
)
1430 FT_MEM_ZERO( decoder
, sizeof ( *decoder
) );
1432 /* retrieve PSNames interface from list of current modules */
1434 FT_Service_PsCMaps psnames
= 0;
1437 FT_FACE_FIND_GLOBAL_SERVICE( face
, psnames
, POSTSCRIPT_CMAPS
);
1440 FT_ERROR(( "t1_decoder_init: " ));
1441 FT_ERROR(( "the `psnames' module is not available\n" ));
1442 return PSaux_Err_Unimplemented_Feature
;
1445 decoder
->psnames
= psnames
;
1448 t1_builder_init( &decoder
->builder
, face
, size
, slot
, hinting
);
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 */
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
;
1460 decoder
->funcs
= t1_decoder_funcs
;
1462 return PSaux_Err_Ok
;
1466 /* finalize T1 decoder */
1467 FT_LOCAL_DEF( void )
1468 t1_decoder_done( T1_Decoder decoder
)
1470 t1_builder_done( &decoder
->builder
);