1 /***************************************************************************/
5 /* Adobe's CFF Interpreter (body). */
7 /* Copyright 2007-2014 Adobe Systems Incorporated. */
9 /* This software, and all works of authorship, whether in source or */
10 /* object code form as indicated by the copyright notice(s) included */
11 /* herein (collectively, the "Work") is made available, and may only be */
12 /* used, modified, and distributed under the FreeType Project License, */
13 /* LICENSE.TXT. Additionally, subject to the terms and conditions of the */
14 /* FreeType Project License, each contributor to the Work hereby grants */
15 /* to any individual or legal entity exercising permissions granted by */
16 /* the FreeType Project License and this section (hereafter, "You" or */
17 /* "Your") a perpetual, worldwide, non-exclusive, no-charge, */
18 /* royalty-free, irrevocable (except as stated in this section) patent */
19 /* license to make, have made, use, offer to sell, sell, import, and */
20 /* otherwise transfer the Work, where such license applies only to those */
21 /* patent claims licensable by such contributor that are necessarily */
22 /* infringed by their contribution(s) alone or by combination of their */
23 /* contribution(s) with the Work to which such contribution(s) was */
24 /* submitted. If You institute patent litigation against any entity */
25 /* (including a cross-claim or counterclaim in a lawsuit) alleging that */
26 /* the Work or a contribution incorporated within the Work constitutes */
27 /* direct or contributory patent infringement, then any patent licenses */
28 /* granted to You under this License for that Work shall terminate as of */
29 /* the date such litigation is filed. */
31 /* By using, modifying, or distributing the Work you indicate that you */
32 /* have read and understood the terms and conditions of the */
33 /* FreeType Project License as well as those provided in this section, */
34 /* and you accept them fully. */
36 /***************************************************************************/
40 #include FT_INTERNAL_DEBUG_H
50 /*************************************************************************/
52 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
53 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
54 /* messages during execution. */
57 #define FT_COMPONENT trace_cf2interp
60 /* some operators are not implemented yet */
61 #define CF2_FIXME FT_TRACE4(( "cf2_interpT2CharString:" \
62 " operator not implemented yet\n" ))
67 cf2_hintmask_init( CF2_HintMask hintmask,
72 hintmask->error = error;
76 FT_LOCAL_DEF( FT_Bool )
77 cf2_hintmask_isValid( const CF2_HintMask hintmask )
79 return hintmask->isValid;
83 FT_LOCAL_DEF( FT_Bool )
84 cf2_hintmask_isNew( const CF2_HintMask hintmask )
86 return hintmask->isNew;
91 cf2_hintmask_setNew( CF2_HintMask hintmask,
94 hintmask->isNew = val;
98 /* clients call `getMaskPtr' in order to iterate */
99 /* through hint mask */
101 FT_LOCAL_DEF( FT_Byte* )
102 cf2_hintmask_getMaskPtr( CF2_HintMask hintmask )
104 return hintmask->mask;
109 cf2_hintmask_setCounts( CF2_HintMask hintmask,
112 if ( bitCount > CF2_MAX_HINTS )
114 /* total of h and v stems must be <= 96 */
115 CF2_SET_ERROR( hintmask->error, Invalid_Glyph_Format );
119 hintmask->bitCount = bitCount;
120 hintmask->byteCount = ( hintmask->bitCount + 7 ) / 8;
122 hintmask->isValid = TRUE;
123 hintmask->isNew = TRUE;
129 /* consume the hintmask bytes from the charstring, advancing the src */
132 cf2_hintmask_read( CF2_HintMask hintmask,
133 CF2_Buffer charstring,
139 /* these are the bits in the final mask byte that should be zero */
140 /* Note: this variable is only used in an assert expression below */
141 /* and then only if CF2_NDEBUG is not defined */
142 CF2_UInt mask = ( 1 << ( -(CF2_Int)bitCount & 7 ) ) - 1;
146 /* initialize counts and isValid */
147 if ( cf2_hintmask_setCounts( hintmask, bitCount ) == 0 )
150 FT_ASSERT( hintmask->byteCount > 0 );
152 FT_TRACE4(( " (maskbytes:" ));
154 /* set mask and advance interpreter's charstring pointer */
155 for ( i = 0; i < hintmask->byteCount; i++ )
157 hintmask->mask[i] = (FT_Byte)cf2_buf_readByte( charstring );
158 FT_TRACE4(( " 0x%02X", hintmask->mask[i] ));
161 FT_TRACE4(( ")\n" ));
163 /* assert any unused bits in last byte are zero unless there's a prior */
165 /* bitCount -> mask, 0 -> 0, 1 -> 7f, 2 -> 3f, ... 6 -> 3, 7 -> 1 */
167 FT_ASSERT( ( hintmask->mask[hintmask->byteCount - 1] & mask ) == 0 ||
174 cf2_hintmask_setAll( CF2_HintMask hintmask,
178 CF2_UInt mask = ( 1 << ( -(CF2_Int)bitCount & 7 ) ) - 1;
181 /* initialize counts and isValid */
182 if ( cf2_hintmask_setCounts( hintmask, bitCount ) == 0 )
185 FT_ASSERT( hintmask->byteCount > 0 );
186 FT_ASSERT( hintmask->byteCount <
187 sizeof ( hintmask->mask ) / sizeof ( hintmask->mask[0] ) );
189 /* set mask to all ones */
190 for ( i = 0; i < hintmask->byteCount; i++ )
191 hintmask->mask[i] = 0xFF;
193 /* clear unused bits */
194 /* bitCount -> mask, 0 -> 0, 1 -> 7f, 2 -> 3f, ... 6 -> 3, 7 -> 1 */
195 hintmask->mask[hintmask->byteCount - 1] &= ~mask;
199 /* Type2 charstring opcodes */
202 cf2_cmdRESERVED_0, /* 0 */
203 cf2_cmdHSTEM, /* 1 */
204 cf2_cmdRESERVED_2, /* 2 */
205 cf2_cmdVSTEM, /* 3 */
206 cf2_cmdVMOVETO, /* 4 */
207 cf2_cmdRLINETO, /* 5 */
208 cf2_cmdHLINETO, /* 6 */
209 cf2_cmdVLINETO, /* 7 */
210 cf2_cmdRRCURVETO, /* 8 */
211 cf2_cmdRESERVED_9, /* 9 */
212 cf2_cmdCALLSUBR, /* 10 */
213 cf2_cmdRETURN, /* 11 */
215 cf2_cmdRESERVED_13, /* 13 */
216 cf2_cmdENDCHAR, /* 14 */
217 cf2_cmdRESERVED_15, /* 15 */
218 cf2_cmdRESERVED_16, /* 16 */
219 cf2_cmdRESERVED_17, /* 17 */
220 cf2_cmdHSTEMHM, /* 18 */
221 cf2_cmdHINTMASK, /* 19 */
222 cf2_cmdCNTRMASK, /* 20 */
223 cf2_cmdRMOVETO, /* 21 */
224 cf2_cmdHMOVETO, /* 22 */
225 cf2_cmdVSTEMHM, /* 23 */
226 cf2_cmdRCURVELINE, /* 24 */
227 cf2_cmdRLINECURVE, /* 25 */
228 cf2_cmdVVCURVETO, /* 26 */
229 cf2_cmdHHCURVETO, /* 27 */
230 cf2_cmdEXTENDEDNMBR, /* 28 */
231 cf2_cmdCALLGSUBR, /* 29 */
232 cf2_cmdVHCURVETO, /* 30 */
233 cf2_cmdHVCURVETO /* 31 */
238 cf2_escDOTSECTION, /* 0 */
239 cf2_escRESERVED_1, /* 1 */
240 cf2_escRESERVED_2, /* 2 */
244 cf2_escRESERVED_6, /* 6 */
245 cf2_escRESERVED_7, /* 7 */
246 cf2_escRESERVED_8, /* 8 */
248 cf2_escADD, /* 10 like otherADD */
249 cf2_escSUB, /* 11 like otherSUB */
251 cf2_escRESERVED_13, /* 13 */
254 cf2_escRESERVED_16, /* 16 */
255 cf2_escRESERVED_17, /* 17 */
256 cf2_escDROP, /* 18 */
257 cf2_escRESERVED_19, /* 19 */
258 cf2_escPUT, /* 20 like otherPUT */
259 cf2_escGET, /* 21 like otherGET */
260 cf2_escIFELSE, /* 22 like otherIFELSE */
261 cf2_escRANDOM, /* 23 like otherRANDOM */
262 cf2_escMUL, /* 24 like otherMUL */
263 cf2_escRESERVED_25, /* 25 */
264 cf2_escSQRT, /* 26 */
265 cf2_escDUP, /* 27 like otherDUP */
266 cf2_escEXCH, /* 28 like otherEXCH */
267 cf2_escINDEX, /* 29 */
268 cf2_escROLL, /* 30 */
269 cf2_escRESERVED_31, /* 31 */
270 cf2_escRESERVED_32, /* 32 */
271 cf2_escRESERVED_33, /* 33 */
272 cf2_escHFLEX, /* 34 */
273 cf2_escFLEX, /* 35 */
274 cf2_escHFLEX1, /* 36 */
275 cf2_escFLEX1 /* 37 */
279 /* `stemHintArray' does not change once we start drawing the outline. */
281 cf2_doStems( const CF2_Font font,
283 CF2_ArrStack stemHintArray,
286 CF2_Fixed hintOffset )
289 CF2_UInt count = cf2_stack_count( opStack );
290 FT_Bool hasWidthArg = (FT_Bool)( count & 1 );
292 /* variable accumulates delta values from operand stack */
293 CF2_Fixed position = hintOffset;
295 if ( hasWidthArg && ! *haveWidth )
296 *width = cf2_stack_getReal( opStack, 0 ) +
297 cf2_getNominalWidthX( font->decoder );
299 if ( font->decoder->width_only )
302 for ( i = hasWidthArg ? 1 : 0; i < count; i += 2 )
304 /* construct a CF2_StemHint and push it onto the list */
305 CF2_StemHintRec stemhint;
309 position += cf2_stack_getReal( opStack, i );
311 position += cf2_stack_getReal( opStack, i + 1 );
313 stemhint.used = FALSE;
317 cf2_arrstack_push( stemHintArray, &stemhint ); /* defer error check */
320 cf2_stack_clear( opStack );
323 /* cf2_doStems must define a width (may be default) */
329 cf2_doFlex( CF2_Stack opStack,
332 CF2_GlyphPath glyphPath,
333 const FT_Bool* readFromStack,
334 FT_Bool doConditionalLastRead )
345 isHFlex = readFromStack[9] == FALSE;
346 top = isHFlex ? 9 : 10;
348 for ( i = 0; i < top; i++ )
350 vals[i + 2] = vals[i];
351 if ( readFromStack[i] )
352 vals[i + 2] += cf2_stack_getReal( opStack, index++ );
358 if ( doConditionalLastRead )
360 FT_Bool lastIsX = (FT_Bool)( cf2_fixedAbs( vals[10] - *curX ) >
361 cf2_fixedAbs( vals[11] - *curY ) );
362 CF2_Fixed lastVal = cf2_stack_getReal( opStack, index );
367 vals[12] = vals[10] + lastVal;
373 vals[13] = vals[11] + lastVal;
378 if ( readFromStack[10] )
379 vals[12] = vals[10] + cf2_stack_getReal( opStack, index++ );
383 if ( readFromStack[11] )
384 vals[13] = vals[11] + cf2_stack_getReal( opStack, index );
389 for ( j = 0; j < 2; j++ )
390 cf2_glyphpath_curveTo( glyphPath, vals[j * 6 + 2],
397 cf2_stack_clear( opStack );
405 * `error' is a shared error code used by many objects in this
406 * routine. Before the code continues from an error, it must check and
407 * record the error in `*error'. The idea is that this shared
408 * error code will record the first error encountered. If testing
409 * for an error anyway, the cost of `goto exit' is small, so we do it,
410 * even if continuing would be safe. In this case, `lastError' is
411 * set, so the testing and storing can be done in one place, at `exit'.
413 * Continuing after an error is intended for objects which do their own
414 * testing of `*error', e.g., array stack functions. This allows us to
415 * avoid an extra test after the call.
417 * Unimplemented opcodes are ignored.
421 cf2_interpT2CharString( CF2_Font font,
423 CF2_OutlineCallbacks callbacks,
424 const FT_Vector* translation,
430 /* lastError is used for errors that are immediately tested */
431 FT_Error lastError = FT_Err_Ok;
433 /* pointer to parsed font object */
434 CFF_Decoder* decoder = font->decoder;
436 FT_Error* error = &font->error;
437 FT_Memory memory = font->memory;
439 CF2_Fixed scaleY = font->innerTransform.d;
440 CF2_Fixed nominalWidthX = cf2_getNominalWidthX( decoder );
442 /* save this for hinting seac accents */
443 CF2_Fixed hintOriginY = curY;
445 CF2_Stack opStack = NULL;
446 FT_Byte op1; /* first opcode byte */
448 /* instruction limit; 20,000,000 matches Avalon */
449 FT_UInt32 instructionLimit = 20000000UL;
451 CF2_ArrStackRec subrStack;
454 CF2_Buffer charstring = NULL;
456 CF2_Int charstringIndex = -1; /* initialize to empty */
458 /* TODO: placeholders for hint structures */
460 /* objects used for hinting */
461 CF2_ArrStackRec hStemHintArray;
462 CF2_ArrStackRec vStemHintArray;
464 CF2_HintMaskRec hintMask;
465 CF2_GlyphPathRec glyphPath;
468 /* initialize the remaining objects */
469 cf2_arrstack_init( &subrStack,
472 sizeof ( CF2_BufferRec ) );
473 cf2_arrstack_init( &hStemHintArray,
476 sizeof ( CF2_StemHintRec ) );
477 cf2_arrstack_init( &vStemHintArray,
480 sizeof ( CF2_StemHintRec ) );
482 /* initialize CF2_StemHint arrays */
483 cf2_hintmask_init( &hintMask, error );
485 /* initialize path map to manage drawing operations */
487 /* Note: last 4 params are used to handle `MoveToPermissive', which */
488 /* may need to call `hintMap.Build' */
489 /* TODO: MoveToPermissive is gone; are these still needed? */
490 cf2_glyphpath_init( &glyphPath,
503 * Initialize state for width parsing. From the CFF Spec:
505 * The first stack-clearing operator, which must be one of hstem,
506 * hstemhm, vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto,
507 * rmoveto, or endchar, takes an additional argument - the width (as
508 * described earlier), which may be expressed as zero or one numeric
511 * What we implement here uses the first validly specified width, but
512 * does not detect errors for specifying more than one width.
514 * If one of the above operators occurs without explicitly specifying
515 * a width, we assume the default width.
519 *width = cf2_getDefaultWidthX( decoder );
522 * Note: at this point, all pointers to resources must be NULL
523 * and all local objects must be initialized.
524 * There must be no branches to exit: above this point.
528 /* allocate an operand stack */
529 opStack = cf2_stack_init( memory, error );
532 lastError = FT_THROW( Out_Of_Memory );
536 /* initialize subroutine stack by placing top level charstring as */
537 /* first element (max depth plus one for the charstring) */
538 /* Note: Caller owns and must finalize the first charstring. */
539 /* Our copy of it does not change that requirement. */
540 cf2_arrstack_setCount( &subrStack, CF2_MAX_SUBR + 1 );
542 charstring = (CF2_Buffer)cf2_arrstack_getBuffer( &subrStack );
543 *charstring = *buf; /* structure copy */
545 charstringIndex = 0; /* entry is valid now */
547 /* catch errors so far */
551 /* main interpreter loop */
554 if ( cf2_buf_isEnd( charstring ) )
556 /* If we've reached the end of the charstring, simulate a */
557 /* cf2_cmdRETURN or cf2_cmdENDCHAR. */
558 if ( charstringIndex )
559 op1 = cf2_cmdRETURN; /* end of buffer for subroutine */
561 op1 = cf2_cmdENDCHAR; /* end of buffer for top level charstring */
564 op1 = (FT_Byte)cf2_buf_readByte( charstring );
566 /* check for errors once per loop */
571 if ( instructionLimit == 0 )
573 lastError = FT_THROW( Invalid_Glyph_Format );
579 case cf2_cmdRESERVED_0:
580 case cf2_cmdRESERVED_2:
581 case cf2_cmdRESERVED_9:
582 case cf2_cmdRESERVED_13:
583 case cf2_cmdRESERVED_15:
584 case cf2_cmdRESERVED_16:
585 case cf2_cmdRESERVED_17:
586 /* we may get here if we have a prior error */
587 FT_TRACE4(( " unknown op (%d)\n", op1 ));
592 FT_TRACE4(( op1 == cf2_cmdHSTEMHM ? " hstemhm\n" : " hstem\n" ));
594 /* never add hints after the mask is computed */
595 if ( cf2_hintmask_isValid( &hintMask ) )
597 FT_TRACE4(( "cf2_interpT2CharString:"
598 " invalid horizontal hint mask\n" ));
609 if ( font->decoder->width_only )
616 FT_TRACE4(( op1 == cf2_cmdVSTEMHM ? " vstemhm\n" : " vstem\n" ));
618 /* never add hints after the mask is computed */
619 if ( cf2_hintmask_isValid( &hintMask ) )
621 FT_TRACE4(( "cf2_interpT2CharString:"
622 " invalid vertical hint mask\n" ));
633 if ( font->decoder->width_only )
639 FT_TRACE4(( " vmoveto\n" ));
641 if ( cf2_stack_count( opStack ) > 1 && !haveWidth )
642 *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
644 /* width is defined or default after this */
647 if ( font->decoder->width_only )
650 curY += cf2_stack_popFixed( opStack );
652 cf2_glyphpath_moveTo( &glyphPath, curX, curY );
659 CF2_UInt count = cf2_stack_count( opStack );
662 FT_TRACE4(( " rlineto\n" ));
664 for ( index = 0; index < count; index += 2 )
666 curX += cf2_stack_getReal( opStack, index + 0 );
667 curY += cf2_stack_getReal( opStack, index + 1 );
669 cf2_glyphpath_lineTo( &glyphPath, curX, curY );
672 cf2_stack_clear( opStack );
674 continue; /* no need to clear stack again */
680 CF2_UInt count = cf2_stack_count( opStack );
682 FT_Bool isX = op1 == cf2_cmdHLINETO;
685 FT_TRACE4(( isX ? " hlineto\n" : " vlineto\n" ));
687 for ( index = 0; index < count; index++ )
689 CF2_Fixed v = cf2_stack_getReal( opStack, index );
699 cf2_glyphpath_lineTo( &glyphPath, curX, curY );
702 cf2_stack_clear( opStack );
706 case cf2_cmdRCURVELINE:
707 case cf2_cmdRRCURVETO:
709 CF2_UInt count = cf2_stack_count( opStack );
713 FT_TRACE4(( op1 == cf2_cmdRCURVELINE ? " rcurveline\n"
716 while ( index + 6 <= count )
718 CF2_Fixed x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
719 CF2_Fixed y1 = cf2_stack_getReal( opStack, index + 1 ) + curY;
720 CF2_Fixed x2 = cf2_stack_getReal( opStack, index + 2 ) + x1;
721 CF2_Fixed y2 = cf2_stack_getReal( opStack, index + 3 ) + y1;
722 CF2_Fixed x3 = cf2_stack_getReal( opStack, index + 4 ) + x2;
723 CF2_Fixed y3 = cf2_stack_getReal( opStack, index + 5 ) + y2;
726 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
733 if ( op1 == cf2_cmdRCURVELINE )
735 curX += cf2_stack_getReal( opStack, index + 0 );
736 curY += cf2_stack_getReal( opStack, index + 1 );
738 cf2_glyphpath_lineTo( &glyphPath, curX, curY );
741 cf2_stack_clear( opStack );
743 continue; /* no need to clear stack again */
745 case cf2_cmdCALLGSUBR:
746 case cf2_cmdCALLSUBR:
751 FT_TRACE4(( op1 == cf2_cmdCALLGSUBR ? " callgsubr"
754 if ( charstringIndex > CF2_MAX_SUBR )
756 /* max subr plus one for charstring */
757 lastError = FT_THROW( Invalid_Glyph_Format );
758 goto exit; /* overflow of stack */
761 /* push our current CFF charstring region on subrStack */
762 charstring = (CF2_Buffer)
763 cf2_arrstack_getPointer( &subrStack,
764 charstringIndex + 1 );
766 /* set up the new CFF region and pointer */
767 subrIndex = cf2_stack_popInt( opStack );
771 case cf2_cmdCALLGSUBR:
772 FT_TRACE4(( "(%d)\n", subrIndex + decoder->globals_bias ));
774 if ( cf2_initGlobalRegionBuffer( decoder,
778 lastError = FT_THROW( Invalid_Glyph_Format );
779 goto exit; /* subroutine lookup or stream error */
784 /* cf2_cmdCALLSUBR */
785 FT_TRACE4(( "(%d)\n", subrIndex + decoder->locals_bias ));
787 if ( cf2_initLocalRegionBuffer( decoder,
791 lastError = FT_THROW( Invalid_Glyph_Format );
792 goto exit; /* subroutine lookup or stream error */
796 charstringIndex += 1; /* entry is valid now */
798 continue; /* do not clear the stack */
801 FT_TRACE4(( " return\n" ));
803 if ( charstringIndex < 1 )
805 /* Note: cannot return from top charstring */
806 lastError = FT_THROW( Invalid_Glyph_Format );
807 goto exit; /* underflow of stack */
810 /* restore position in previous charstring */
811 charstring = (CF2_Buffer)
812 cf2_arrstack_getPointer( &subrStack,
814 continue; /* do not clear the stack */
818 FT_Byte op2 = (FT_Byte)cf2_buf_readByte( charstring );
823 case cf2_escDOTSECTION:
824 /* something about `flip type of locking' -- ignore it */
825 FT_TRACE4(( " dotsection\n" ));
829 /* TODO: should these operators be supported? */
830 case cf2_escAND: /* in spec */
831 FT_TRACE4(( " and\n" ));
836 case cf2_escOR: /* in spec */
837 FT_TRACE4(( " or\n" ));
842 case cf2_escNOT: /* in spec */
843 FT_TRACE4(( " not\n" ));
848 case cf2_escABS: /* in spec */
849 FT_TRACE4(( " abs\n" ));
854 case cf2_escADD: /* in spec */
855 FT_TRACE4(( " add\n" ));
860 case cf2_escSUB: /* in spec */
861 FT_TRACE4(( " sub\n" ));
866 case cf2_escDIV: /* in spec */
867 FT_TRACE4(( " div\n" ));
872 case cf2_escNEG: /* in spec */
873 FT_TRACE4(( " neg\n" ));
878 case cf2_escEQ: /* in spec */
879 FT_TRACE4(( " eq\n" ));
884 case cf2_escDROP: /* in spec */
885 FT_TRACE4(( " drop\n" ));
890 case cf2_escPUT: /* in spec */
891 FT_TRACE4(( " put\n" ));
896 case cf2_escGET: /* in spec */
897 FT_TRACE4(( " get\n" ));
902 case cf2_escIFELSE: /* in spec */
903 FT_TRACE4(( " ifelse\n" ));
908 case cf2_escRANDOM: /* in spec */
909 FT_TRACE4(( " random\n" ));
914 case cf2_escMUL: /* in spec */
915 FT_TRACE4(( " mul\n" ));
920 case cf2_escSQRT: /* in spec */
921 FT_TRACE4(( " sqrt\n" ));
926 case cf2_escDUP: /* in spec */
927 FT_TRACE4(( " dup\n" ));
932 case cf2_escEXCH: /* in spec */
933 FT_TRACE4(( " exch\n" ));
938 case cf2_escINDEX: /* in spec */
939 FT_TRACE4(( " index\n" ));
944 case cf2_escROLL: /* in spec */
945 FT_TRACE4(( " roll\n" ));
952 static const FT_Bool readFromStack[12] =
954 TRUE /* dx1 */, FALSE /* dy1 */,
955 TRUE /* dx2 */, TRUE /* dy2 */,
956 TRUE /* dx3 */, FALSE /* dy3 */,
957 TRUE /* dx4 */, FALSE /* dy4 */,
958 TRUE /* dx5 */, FALSE /* dy5 */,
959 TRUE /* dx6 */, FALSE /* dy6 */
963 FT_TRACE4(( " hflex\n" ));
970 FALSE /* doConditionalLastRead */ );
976 static const FT_Bool readFromStack[12] =
978 TRUE /* dx1 */, TRUE /* dy1 */,
979 TRUE /* dx2 */, TRUE /* dy2 */,
980 TRUE /* dx3 */, TRUE /* dy3 */,
981 TRUE /* dx4 */, TRUE /* dy4 */,
982 TRUE /* dx5 */, TRUE /* dy5 */,
983 TRUE /* dx6 */, TRUE /* dy6 */
987 FT_TRACE4(( " flex\n" ));
994 FALSE /* doConditionalLastRead */ );
996 break; /* TODO: why is this not a continue? */
1000 static const FT_Bool readFromStack[12] =
1002 TRUE /* dx1 */, TRUE /* dy1 */,
1003 TRUE /* dx2 */, TRUE /* dy2 */,
1004 TRUE /* dx3 */, FALSE /* dy3 */,
1005 TRUE /* dx4 */, FALSE /* dy4 */,
1006 TRUE /* dx5 */, TRUE /* dy5 */,
1007 TRUE /* dx6 */, FALSE /* dy6 */
1011 FT_TRACE4(( " hflex1\n" ));
1013 cf2_doFlex( opStack,
1018 FALSE /* doConditionalLastRead */ );
1024 static const FT_Bool readFromStack[12] =
1026 TRUE /* dx1 */, TRUE /* dy1 */,
1027 TRUE /* dx2 */, TRUE /* dy2 */,
1028 TRUE /* dx3 */, TRUE /* dy3 */,
1029 TRUE /* dx4 */, TRUE /* dy4 */,
1030 TRUE /* dx5 */, TRUE /* dy5 */,
1031 FALSE /* dx6 */, FALSE /* dy6 */
1035 FT_TRACE4(( " flex1\n" ));
1037 cf2_doFlex( opStack,
1042 TRUE /* doConditionalLastRead */ );
1046 case cf2_escRESERVED_1:
1047 case cf2_escRESERVED_2:
1048 case cf2_escRESERVED_6:
1049 case cf2_escRESERVED_7:
1050 case cf2_escRESERVED_8:
1051 case cf2_escRESERVED_13:
1052 case cf2_escRESERVED_16:
1053 case cf2_escRESERVED_17:
1054 case cf2_escRESERVED_19:
1055 case cf2_escRESERVED_25:
1056 case cf2_escRESERVED_31:
1057 case cf2_escRESERVED_32:
1058 case cf2_escRESERVED_33:
1060 FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
1062 }; /* end of switch statement checking `op2' */
1064 } /* case cf2_cmdESC */
1067 case cf2_cmdENDCHAR:
1068 FT_TRACE4(( " endchar\n" ));
1070 if ( cf2_stack_count( opStack ) == 1 ||
1071 cf2_stack_count( opStack ) == 5 )
1074 *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
1077 /* width is defined or default after this */
1080 if ( font->decoder->width_only )
1083 /* close path if still open */
1084 cf2_glyphpath_closeOpenPath( &glyphPath );
1086 if ( cf2_stack_count( opStack ) > 1 )
1088 /* must be either 4 or 5 -- */
1089 /* this is a (deprecated) implied `seac' operator */
1093 CF2_BufferRec component;
1094 CF2_Fixed dummyWidth; /* ignore component width */
1100 lastError = FT_THROW( Invalid_Glyph_Format );
1101 goto exit; /* nested seac */
1104 achar = cf2_stack_popInt( opStack );
1105 bchar = cf2_stack_popInt( opStack );
1107 curY = cf2_stack_popFixed( opStack );
1108 curX = cf2_stack_popFixed( opStack );
1110 error2 = cf2_getSeacComponent( decoder, achar, &component );
1113 lastError = error2; /* pass FreeType error through */
1116 cf2_interpT2CharString( font,
1124 cf2_freeSeacComponent( decoder, &component );
1126 error2 = cf2_getSeacComponent( decoder, bchar, &component );
1129 lastError = error2; /* pass FreeType error through */
1132 cf2_interpT2CharString( font,
1140 cf2_freeSeacComponent( decoder, &component );
1144 case cf2_cmdCNTRMASK:
1145 case cf2_cmdHINTMASK:
1146 /* the final \n in the tracing message gets added in */
1147 /* `cf2_hintmask_read' (which also traces the mask bytes) */
1148 FT_TRACE4(( op1 == cf2_cmdCNTRMASK ? " cntrmask" : " hintmask" ));
1150 /* never add hints after the mask is computed */
1151 if ( cf2_stack_count( opStack ) > 1 &&
1152 cf2_hintmask_isValid( &hintMask ) )
1154 FT_TRACE4(( "cf2_interpT2CharString: invalid hint mask\n" ));
1158 /* if there are arguments on the stack, there this is an */
1159 /* implied cf2_cmdVSTEMHM */
1167 if ( font->decoder->width_only )
1170 if ( op1 == cf2_cmdHINTMASK )
1172 /* consume the hint mask bytes which follow the operator */
1173 cf2_hintmask_read( &hintMask,
1175 cf2_arrstack_size( &hStemHintArray ) +
1176 cf2_arrstack_size( &vStemHintArray ) );
1181 * Consume the counter mask bytes which follow the operator:
1182 * Build a temporary hint map, just to place and lock those
1183 * stems participating in the counter mask. These are most
1184 * likely the dominant hstems, and are grouped together in a
1185 * few counter groups, not necessarily in correspondence
1186 * with the hint groups. This reduces the chances of
1187 * conflicts between hstems that are initially placed in
1188 * separate hint groups and then brought together. The
1189 * positions are copied back to `hStemHintArray', so we can
1190 * discard `counterMask' and `counterHintMap'.
1193 CF2_HintMapRec counterHintMap;
1194 CF2_HintMaskRec counterMask;
1197 cf2_hintmap_init( &counterHintMap,
1199 &glyphPath.initialHintMap,
1200 &glyphPath.hintMoves,
1202 cf2_hintmask_init( &counterMask, error );
1204 cf2_hintmask_read( &counterMask,
1206 cf2_arrstack_size( &hStemHintArray ) +
1207 cf2_arrstack_size( &vStemHintArray ) );
1208 cf2_hintmap_build( &counterHintMap,
1217 case cf2_cmdRMOVETO:
1218 FT_TRACE4(( " rmoveto\n" ));
1220 if ( cf2_stack_count( opStack ) > 2 && !haveWidth )
1221 *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
1223 /* width is defined or default after this */
1226 if ( font->decoder->width_only )
1229 curY += cf2_stack_popFixed( opStack );
1230 curX += cf2_stack_popFixed( opStack );
1232 cf2_glyphpath_moveTo( &glyphPath, curX, curY );
1236 case cf2_cmdHMOVETO:
1237 FT_TRACE4(( " hmoveto\n" ));
1239 if ( cf2_stack_count( opStack ) > 1 && !haveWidth )
1240 *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
1242 /* width is defined or default after this */
1245 if ( font->decoder->width_only )
1248 curX += cf2_stack_popFixed( opStack );
1250 cf2_glyphpath_moveTo( &glyphPath, curX, curY );
1254 case cf2_cmdRLINECURVE:
1256 CF2_UInt count = cf2_stack_count( opStack );
1260 FT_TRACE4(( " rlinecurve\n" ));
1262 while ( index + 6 < count )
1264 curX += cf2_stack_getReal( opStack, index + 0 );
1265 curY += cf2_stack_getReal( opStack, index + 1 );
1267 cf2_glyphpath_lineTo( &glyphPath, curX, curY );
1271 while ( index < count )
1273 CF2_Fixed x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
1274 CF2_Fixed y1 = cf2_stack_getReal( opStack, index + 1 ) + curY;
1275 CF2_Fixed x2 = cf2_stack_getReal( opStack, index + 2 ) + x1;
1276 CF2_Fixed y2 = cf2_stack_getReal( opStack, index + 3 ) + y1;
1277 CF2_Fixed x3 = cf2_stack_getReal( opStack, index + 4 ) + x2;
1278 CF2_Fixed y3 = cf2_stack_getReal( opStack, index + 5 ) + y2;
1281 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1288 cf2_stack_clear( opStack );
1290 continue; /* no need to clear stack again */
1292 case cf2_cmdVVCURVETO:
1294 CF2_UInt count = cf2_stack_count( opStack );
1298 FT_TRACE4(( " vvcurveto\n" ));
1300 while ( index < count )
1302 CF2_Fixed x1, y1, x2, y2, x3, y3;
1305 if ( ( count - index ) & 1 )
1307 x1 = cf2_stack_getReal( opStack, index ) + curX;
1314 y1 = cf2_stack_getReal( opStack, index + 0 ) + curY;
1315 x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1316 y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1318 y3 = cf2_stack_getReal( opStack, index + 3 ) + y2;
1320 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1327 cf2_stack_clear( opStack );
1329 continue; /* no need to clear stack again */
1331 case cf2_cmdHHCURVETO:
1333 CF2_UInt count = cf2_stack_count( opStack );
1337 FT_TRACE4(( " hhcurveto\n" ));
1339 while ( index < count )
1341 CF2_Fixed x1, y1, x2, y2, x3, y3;
1344 if ( ( count - index ) & 1 )
1346 y1 = cf2_stack_getReal( opStack, index ) + curY;
1353 x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
1354 x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1355 y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1356 x3 = cf2_stack_getReal( opStack, index + 3 ) + x2;
1359 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1366 cf2_stack_clear( opStack );
1368 continue; /* no need to clear stack again */
1370 case cf2_cmdVHCURVETO:
1371 case cf2_cmdHVCURVETO:
1373 CF2_UInt count = cf2_stack_count( opStack );
1376 FT_Bool alternate = op1 == cf2_cmdHVCURVETO;
1379 FT_TRACE4(( alternate ? " hvcurveto\n" : " vhcurveto\n" ));
1381 while ( index < count )
1383 CF2_Fixed x1, x2, x3, y1, y2, y3;
1388 x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
1390 x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1391 y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1392 y3 = cf2_stack_getReal( opStack, index + 3 ) + y2;
1394 if ( count - index == 5 )
1396 x3 = cf2_stack_getReal( opStack, index + 4 ) + x2;
1408 y1 = cf2_stack_getReal( opStack, index + 0 ) + curY;
1409 x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1410 y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1411 x3 = cf2_stack_getReal( opStack, index + 3 ) + x2;
1413 if ( count - index == 5 )
1415 y3 = cf2_stack_getReal( opStack, index + 4 ) + y2;
1425 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1432 cf2_stack_clear( opStack );
1434 continue; /* no need to clear stack again */
1436 case cf2_cmdEXTENDEDNMBR:
1441 v = (FT_Short)( ( cf2_buf_readByte( charstring ) << 8 ) |
1442 cf2_buf_readByte( charstring ) );
1444 FT_TRACE4(( " %d", v ));
1446 cf2_stack_pushInt( opStack, v );
1453 if ( /* op1 >= 32 && */ op1 <= 246 )
1460 FT_TRACE4(( " %d", v ));
1463 cf2_stack_pushInt( opStack, v );
1466 else if ( /* op1 >= 247 && */ op1 <= 250 )
1474 v += cf2_buf_readByte( charstring );
1477 FT_TRACE4(( " %d", v ));
1480 cf2_stack_pushInt( opStack, v );
1483 else if ( /* op1 >= 251 && */ op1 <= 254 )
1491 v += cf2_buf_readByte( charstring );
1494 FT_TRACE4(( " %d", v ));
1497 cf2_stack_pushInt( opStack, v );
1500 else /* op1 == 255 */
1506 ( ( (FT_UInt32)cf2_buf_readByte( charstring ) << 24 ) |
1507 ( (FT_UInt32)cf2_buf_readByte( charstring ) << 16 ) |
1508 ( (FT_UInt32)cf2_buf_readByte( charstring ) << 8 ) |
1509 (FT_UInt32)cf2_buf_readByte( charstring ) );
1511 FT_TRACE4(( " %.2f", v / 65536.0 ));
1513 cf2_stack_pushFixed( opStack, v );
1516 continue; /* don't clear stack */
1518 } /* end of switch statement checking `op1' */
1520 cf2_stack_clear( opStack );
1522 } /* end of main interpreter loop */
1524 /* we get here if the charstring ends without cf2_cmdENDCHAR */
1525 FT_TRACE4(( "cf2_interpT2CharString:"
1526 " charstring ends without ENDCHAR\n" ));
1529 /* check whether last error seen is also the first one */
1530 cf2_setError( error, lastError );
1532 /* free resources from objects we've used */
1533 cf2_glyphpath_finalize( &glyphPath );
1534 cf2_arrstack_finalize( &vStemHintArray );
1535 cf2_arrstack_finalize( &hStemHintArray );
1536 cf2_arrstack_finalize( &subrStack );
1537 cf2_stack_free( opStack );
1539 FT_TRACE4(( "\n" ));