1 /***************************************************************************/
5 /* Adobe's CFF Interpreter (body). */
7 /* Copyright 2007-2013 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 = count & 1;
292 /* variable accumulates delta values from operand stack */
293 CF2_Fixed position = hintOffset;
296 for ( i = hasWidthArg ? 1 : 0; i < count; i += 2 )
298 /* construct a CF2_StemHint and push it onto the list */
299 CF2_StemHintRec stemhint;
303 position += cf2_stack_getReal( opStack, i );
305 position += cf2_stack_getReal( opStack, i + 1 );
307 stemhint.used = FALSE;
311 cf2_arrstack_push( stemHintArray, &stemhint ); /* defer error check */
314 if ( hasWidthArg && ! *haveWidth )
315 *width = cf2_stack_getReal( opStack, 0 ) +
316 cf2_getNominalWidthX( font->decoder );
320 cf2_stack_clear( opStack );
325 cf2_doFlex( CF2_Stack opStack,
328 CF2_GlyphPath glyphPath,
329 const FT_Bool* readFromStack,
330 FT_Bool doConditionalLastRead )
341 isHFlex = readFromStack[9] == FALSE;
342 top = isHFlex ? 9 : 10;
344 for ( i = 0; i < top; i++ )
346 vals[i + 2] = vals[i];
347 if ( readFromStack[i] )
348 vals[i + 2] += cf2_stack_getReal( opStack, index++ );
354 if ( doConditionalLastRead )
356 FT_Bool lastIsX = cf2_fixedAbs( vals[10] - *curX ) >
357 cf2_fixedAbs( vals[11] - *curY );
358 CF2_Fixed lastVal = cf2_stack_getReal( opStack, index );
363 vals[12] = vals[10] + lastVal;
369 vals[13] = vals[11] + lastVal;
374 if ( readFromStack[10] )
375 vals[12] = vals[10] + cf2_stack_getReal( opStack, index++ );
379 if ( readFromStack[11] )
380 vals[13] = vals[11] + cf2_stack_getReal( opStack, index );
385 for ( j = 0; j < 2; j++ )
386 cf2_glyphpath_curveTo( glyphPath, vals[j * 6 + 2],
393 cf2_stack_clear( opStack );
401 * `error' is a shared error code used by many objects in this
402 * routine. Before the code continues from an error, it must check and
403 * record the error in `*error'. The idea is that this shared
404 * error code will record the first error encountered. If testing
405 * for an error anyway, the cost of `goto exit' is small, so we do it,
406 * even if continuing would be safe. In this case, `lastError' is
407 * set, so the testing and storing can be done in one place, at `exit'.
409 * Continuing after an error is intended for objects which do their own
410 * testing of `*error', e.g., array stack functions. This allows us to
411 * avoid an extra test after the call.
413 * Unimplemented opcodes are ignored.
417 cf2_interpT2CharString( CF2_Font font,
419 CF2_OutlineCallbacks callbacks,
420 const FT_Vector* translation,
426 /* lastError is used for errors that are immediately tested */
427 FT_Error lastError = FT_Err_Ok;
429 /* pointer to parsed font object */
430 CFF_Decoder* decoder = font->decoder;
432 FT_Error* error = &font->error;
433 FT_Memory memory = font->memory;
435 CF2_Fixed scaleY = font->innerTransform.d;
436 CF2_Fixed nominalWidthX = cf2_getNominalWidthX( decoder );
438 /* save this for hinting seac accents */
439 CF2_Fixed hintOriginY = curY;
441 CF2_Stack opStack = NULL;
442 FT_Byte op1; /* first opcode byte */
444 /* instruction limit; 20,000,000 matches Avalon */
445 FT_UInt32 instructionLimit = 20000000UL;
447 CF2_ArrStackRec subrStack;
450 CF2_Buffer charstring = NULL;
452 CF2_Int charstringIndex = -1; /* initialize to empty */
454 /* TODO: placeholders for hint structures */
456 /* objects used for hinting */
457 CF2_ArrStackRec hStemHintArray;
458 CF2_ArrStackRec vStemHintArray;
460 CF2_HintMaskRec hintMask;
461 CF2_GlyphPathRec glyphPath;
464 /* initialize the remaining objects */
465 cf2_arrstack_init( &subrStack,
468 sizeof ( CF2_BufferRec ) );
469 cf2_arrstack_init( &hStemHintArray,
472 sizeof ( CF2_StemHintRec ) );
473 cf2_arrstack_init( &vStemHintArray,
476 sizeof ( CF2_StemHintRec ) );
478 /* initialize CF2_StemHint arrays */
479 cf2_hintmask_init( &hintMask, error );
481 /* initialize path map to manage drawing operations */
483 /* Note: last 4 params are used to handle `MoveToPermissive', which */
484 /* may need to call `hintMap.Build' */
485 /* TODO: MoveToPermissive is gone; are these still needed? */
486 cf2_glyphpath_init( &glyphPath,
499 * Initialize state for width parsing. From the CFF Spec:
501 * The first stack-clearing operator, which must be one of hstem,
502 * hstemhm, vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto,
503 * rmoveto, or endchar, takes an additional argument - the width (as
504 * described earlier), which may be expressed as zero or one numeric
507 * What we implement here uses the first validly specified width, but
508 * does not detect errors for specifying more than one width.
512 *width = cf2_getDefaultWidthX( decoder );
515 * Note: at this point, all pointers to resources must be NULL
516 * and all local objects must be initialized.
517 * There must be no branches to exit: above this point.
521 /* allocate an operand stack */
522 opStack = cf2_stack_init( memory, error );
525 lastError = FT_THROW( Out_Of_Memory );
529 /* initialize subroutine stack by placing top level charstring as */
530 /* first element (max depth plus one for the charstring) */
531 /* Note: Caller owns and must finalize the first charstring. */
532 /* Our copy of it does not change that requirement. */
533 cf2_arrstack_setCount( &subrStack, CF2_MAX_SUBR + 1 );
535 charstring = (CF2_Buffer)cf2_arrstack_getBuffer( &subrStack );
536 *charstring = *buf; /* structure copy */
538 charstringIndex = 0; /* entry is valid now */
540 /* catch errors so far */
544 /* main interpreter loop */
547 if ( cf2_buf_isEnd( charstring ) )
549 /* If we've reached the end of the charstring, simulate a */
550 /* cf2_cmdRETURN or cf2_cmdENDCHAR. */
551 if ( charstringIndex )
552 op1 = cf2_cmdRETURN; /* end of buffer for subroutine */
554 op1 = cf2_cmdENDCHAR; /* end of buffer for top level charstring */
557 op1 = (FT_Byte)cf2_buf_readByte( charstring );
559 /* check for errors once per loop */
564 if ( instructionLimit == 0 )
566 lastError = FT_THROW( Invalid_Glyph_Format );
572 case cf2_cmdRESERVED_0:
573 case cf2_cmdRESERVED_2:
574 case cf2_cmdRESERVED_9:
575 case cf2_cmdRESERVED_13:
576 case cf2_cmdRESERVED_15:
577 case cf2_cmdRESERVED_16:
578 case cf2_cmdRESERVED_17:
579 /* we may get here if we have a prior error */
580 FT_TRACE4(( " unknown op (%d)\n", op1 ));
585 FT_TRACE4(( op1 == cf2_cmdHSTEMHM ? " hstemhm\n" : " hstem\n" ));
587 /* never add hints after the mask is computed */
588 if ( cf2_hintmask_isValid( &hintMask ) )
589 FT_TRACE4(( "cf2_interpT2CharString:"
590 " invalid horizontal hint mask\n" ));
602 FT_TRACE4(( op1 == cf2_cmdVSTEMHM ? " vstemhm\n" : " vstem\n" ));
604 /* never add hints after the mask is computed */
605 if ( cf2_hintmask_isValid( &hintMask ) )
606 FT_TRACE4(( "cf2_interpT2CharString:"
607 " invalid vertical hint mask\n" ));
618 FT_TRACE4(( " vmoveto\n" ));
620 curY += cf2_stack_popFixed( opStack );
622 cf2_glyphpath_moveTo( &glyphPath, curX, curY );
624 if ( cf2_stack_count( opStack ) > 0 && !haveWidth )
625 *width = cf2_stack_popFixed( opStack ) + nominalWidthX;
633 CF2_UInt count = cf2_stack_count( opStack );
636 FT_TRACE4(( " rlineto\n" ));
638 for ( index = 0; index < count; index += 2 )
640 curX += cf2_stack_getReal( opStack, index + 0 );
641 curY += cf2_stack_getReal( opStack, index + 1 );
643 cf2_glyphpath_lineTo( &glyphPath, curX, curY );
646 cf2_stack_clear( opStack );
648 continue; /* no need to clear stack again */
654 CF2_UInt count = cf2_stack_count( opStack );
656 FT_Bool isX = op1 == cf2_cmdHLINETO;
659 FT_TRACE4(( isX ? " hlineto\n" : " vlineto\n" ));
661 for ( index = 0; index < count; index++ )
663 CF2_Fixed v = cf2_stack_getReal( opStack, index );
673 cf2_glyphpath_lineTo( &glyphPath, curX, curY );
676 cf2_stack_clear( opStack );
680 case cf2_cmdRCURVELINE:
681 case cf2_cmdRRCURVETO:
683 CF2_UInt count = cf2_stack_count( opStack );
687 FT_TRACE4(( op1 == cf2_cmdRCURVELINE ? " rcurveline\n"
690 while ( index + 6 <= count )
692 CF2_Fixed x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
693 CF2_Fixed y1 = cf2_stack_getReal( opStack, index + 1 ) + curY;
694 CF2_Fixed x2 = cf2_stack_getReal( opStack, index + 2 ) + x1;
695 CF2_Fixed y2 = cf2_stack_getReal( opStack, index + 3 ) + y1;
696 CF2_Fixed x3 = cf2_stack_getReal( opStack, index + 4 ) + x2;
697 CF2_Fixed y3 = cf2_stack_getReal( opStack, index + 5 ) + y2;
700 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
707 if ( op1 == cf2_cmdRCURVELINE )
709 curX += cf2_stack_getReal( opStack, index + 0 );
710 curY += cf2_stack_getReal( opStack, index + 1 );
712 cf2_glyphpath_lineTo( &glyphPath, curX, curY );
715 cf2_stack_clear( opStack );
717 continue; /* no need to clear stack again */
719 case cf2_cmdCALLGSUBR:
720 case cf2_cmdCALLSUBR:
725 FT_TRACE4(( op1 == cf2_cmdCALLGSUBR ? " callgsubr"
728 if ( charstringIndex > CF2_MAX_SUBR )
730 /* max subr plus one for charstring */
731 lastError = FT_THROW( Invalid_Glyph_Format );
732 goto exit; /* overflow of stack */
735 /* push our current CFF charstring region on subrStack */
736 charstring = (CF2_Buffer)
737 cf2_arrstack_getPointer( &subrStack,
738 charstringIndex + 1 );
740 /* set up the new CFF region and pointer */
741 subrIndex = cf2_stack_popInt( opStack );
745 case cf2_cmdCALLGSUBR:
746 FT_TRACE4(( "(%d)\n", subrIndex + decoder->globals_bias ));
748 if ( cf2_initGlobalRegionBuffer( decoder,
752 lastError = FT_THROW( Invalid_Glyph_Format );
753 goto exit; /* subroutine lookup or stream error */
758 /* cf2_cmdCALLSUBR */
759 FT_TRACE4(( "(%d)\n", subrIndex + decoder->locals_bias ));
761 if ( cf2_initLocalRegionBuffer( decoder,
765 lastError = FT_THROW( Invalid_Glyph_Format );
766 goto exit; /* subroutine lookup or stream error */
770 charstringIndex += 1; /* entry is valid now */
772 continue; /* do not clear the stack */
775 FT_TRACE4(( " return\n" ));
777 if ( charstringIndex < 1 )
779 /* Note: cannot return from top charstring */
780 lastError = FT_THROW( Invalid_Glyph_Format );
781 goto exit; /* underflow of stack */
784 /* restore position in previous charstring */
785 charstring = (CF2_Buffer)
786 cf2_arrstack_getPointer( &subrStack,
788 continue; /* do not clear the stack */
792 FT_Byte op2 = cf2_buf_readByte( charstring );
797 case cf2_escDOTSECTION:
798 /* something about `flip type of locking' -- ignore it */
799 FT_TRACE4(( " dotsection\n" ));
803 /* TODO: should these operators be supported? */
804 case cf2_escAND: /* in spec */
805 FT_TRACE4(( " and\n" ));
810 case cf2_escOR: /* in spec */
811 FT_TRACE4(( " or\n" ));
816 case cf2_escNOT: /* in spec */
817 FT_TRACE4(( " not\n" ));
822 case cf2_escABS: /* in spec */
823 FT_TRACE4(( " abs\n" ));
828 case cf2_escADD: /* in spec */
829 FT_TRACE4(( " add\n" ));
834 case cf2_escSUB: /* in spec */
835 FT_TRACE4(( " sub\n" ));
840 case cf2_escDIV: /* in spec */
841 FT_TRACE4(( " div\n" ));
846 case cf2_escNEG: /* in spec */
847 FT_TRACE4(( " neg\n" ));
852 case cf2_escEQ: /* in spec */
853 FT_TRACE4(( " eq\n" ));
858 case cf2_escDROP: /* in spec */
859 FT_TRACE4(( " drop\n" ));
864 case cf2_escPUT: /* in spec */
865 FT_TRACE4(( " put\n" ));
870 case cf2_escGET: /* in spec */
871 FT_TRACE4(( " get\n" ));
876 case cf2_escIFELSE: /* in spec */
877 FT_TRACE4(( " ifelse\n" ));
882 case cf2_escRANDOM: /* in spec */
883 FT_TRACE4(( " random\n" ));
888 case cf2_escMUL: /* in spec */
889 FT_TRACE4(( " mul\n" ));
894 case cf2_escSQRT: /* in spec */
895 FT_TRACE4(( " sqrt\n" ));
900 case cf2_escDUP: /* in spec */
901 FT_TRACE4(( " dup\n" ));
906 case cf2_escEXCH: /* in spec */
907 FT_TRACE4(( " exch\n" ));
912 case cf2_escINDEX: /* in spec */
913 FT_TRACE4(( " index\n" ));
918 case cf2_escROLL: /* in spec */
919 FT_TRACE4(( " roll\n" ));
926 static const FT_Bool readFromStack[12] =
928 TRUE /* dx1 */, FALSE /* dy1 */,
929 TRUE /* dx2 */, TRUE /* dy2 */,
930 TRUE /* dx3 */, FALSE /* dy3 */,
931 TRUE /* dx4 */, FALSE /* dy4 */,
932 TRUE /* dx5 */, FALSE /* dy5 */,
933 TRUE /* dx6 */, FALSE /* dy6 */
937 FT_TRACE4(( " hflex\n" ));
944 FALSE /* doConditionalLastRead */ );
950 static const FT_Bool readFromStack[12] =
952 TRUE /* dx1 */, TRUE /* dy1 */,
953 TRUE /* dx2 */, TRUE /* dy2 */,
954 TRUE /* dx3 */, TRUE /* dy3 */,
955 TRUE /* dx4 */, TRUE /* dy4 */,
956 TRUE /* dx5 */, TRUE /* dy5 */,
957 TRUE /* dx6 */, TRUE /* dy6 */
961 FT_TRACE4(( " flex\n" ));
968 FALSE /* doConditionalLastRead */ );
970 break; /* TODO: why is this not a continue? */
974 static const FT_Bool readFromStack[12] =
976 TRUE /* dx1 */, TRUE /* dy1 */,
977 TRUE /* dx2 */, TRUE /* dy2 */,
978 TRUE /* dx3 */, FALSE /* dy3 */,
979 TRUE /* dx4 */, FALSE /* dy4 */,
980 TRUE /* dx5 */, TRUE /* dy5 */,
981 TRUE /* dx6 */, FALSE /* dy6 */
985 FT_TRACE4(( " hflex1\n" ));
992 FALSE /* doConditionalLastRead */ );
998 static const FT_Bool readFromStack[12] =
1000 TRUE /* dx1 */, TRUE /* dy1 */,
1001 TRUE /* dx2 */, TRUE /* dy2 */,
1002 TRUE /* dx3 */, TRUE /* dy3 */,
1003 TRUE /* dx4 */, TRUE /* dy4 */,
1004 TRUE /* dx5 */, TRUE /* dy5 */,
1005 FALSE /* dx6 */, FALSE /* dy6 */
1009 FT_TRACE4(( " flex1\n" ));
1011 cf2_doFlex( opStack,
1016 TRUE /* doConditionalLastRead */ );
1020 case cf2_escRESERVED_1:
1021 case cf2_escRESERVED_2:
1022 case cf2_escRESERVED_6:
1023 case cf2_escRESERVED_7:
1024 case cf2_escRESERVED_8:
1025 case cf2_escRESERVED_13:
1026 case cf2_escRESERVED_16:
1027 case cf2_escRESERVED_17:
1028 case cf2_escRESERVED_19:
1029 case cf2_escRESERVED_25:
1030 case cf2_escRESERVED_31:
1031 case cf2_escRESERVED_32:
1032 case cf2_escRESERVED_33:
1034 FT_TRACE4(( " unknown op (12, %d)\n", op2 ));
1036 }; /* end of switch statement checking `op2' */
1038 } /* case cf2_cmdESC */
1041 case cf2_cmdENDCHAR:
1042 FT_TRACE4(( " endchar\n" ));
1044 if ( cf2_stack_count( opStack ) == 1 ||
1045 cf2_stack_count( opStack ) == 5 )
1048 *width = cf2_stack_getReal( opStack, 0 ) + nominalWidthX;
1053 /* close path if still open */
1054 cf2_glyphpath_closeOpenPath( &glyphPath );
1056 if ( cf2_stack_count( opStack ) > 1 )
1058 /* must be either 4 or 5 -- */
1059 /* this is a (deprecated) implied `seac' operator */
1063 CF2_BufferRec component;
1064 CF2_Fixed dummyWidth; /* ignore component width */
1070 lastError = FT_THROW( Invalid_Glyph_Format );
1071 goto exit; /* nested seac */
1074 achar = cf2_stack_popInt( opStack );
1075 bchar = cf2_stack_popInt( opStack );
1077 curY = cf2_stack_popFixed( opStack );
1078 curX = cf2_stack_popFixed( opStack );
1080 error2 = cf2_getSeacComponent( decoder, achar, &component );
1083 lastError = error2; /* pass FreeType error through */
1086 cf2_interpT2CharString( font,
1094 cf2_freeSeacComponent( decoder, &component );
1096 error2 = cf2_getSeacComponent( decoder, bchar, &component );
1099 lastError = error2; /* pass FreeType error through */
1102 cf2_interpT2CharString( font,
1110 cf2_freeSeacComponent( decoder, &component );
1114 case cf2_cmdCNTRMASK:
1115 case cf2_cmdHINTMASK:
1116 /* the final \n in the tracing message gets added in */
1117 /* `cf2_hintmask_read' (which also traces the mask bytes) */
1118 FT_TRACE4(( op1 == cf2_cmdCNTRMASK ? " cntrmask" : " hintmask" ));
1120 /* if there are arguments on the stack, there this is an */
1121 /* implied cf2_cmdVSTEMHM */
1122 if ( cf2_stack_count( opStack ) != 0 )
1124 /* never add hints after the mask is computed */
1125 if ( cf2_hintmask_isValid( &hintMask ) )
1126 FT_TRACE4(( "cf2_interpT2CharString: invalid hint mask\n" ));
1136 if ( op1 == cf2_cmdHINTMASK )
1138 /* consume the hint mask bytes which follow the operator */
1139 cf2_hintmask_read( &hintMask,
1141 cf2_arrstack_size( &hStemHintArray ) +
1142 cf2_arrstack_size( &vStemHintArray ) );
1147 * Consume the counter mask bytes which follow the operator:
1148 * Build a temporary hint map, just to place and lock those
1149 * stems participating in the counter mask. These are most
1150 * likely the dominant hstems, and are grouped together in a
1151 * few counter groups, not necessarily in correspondence
1152 * with the hint groups. This reduces the chances of
1153 * conflicts between hstems that are initially placed in
1154 * separate hint groups and then brought together. The
1155 * positions are copied back to `hStemHintArray', so we can
1156 * discard `counterMask' and `counterHintMap'.
1159 CF2_HintMapRec counterHintMap;
1160 CF2_HintMaskRec counterMask;
1163 cf2_hintmap_init( &counterHintMap,
1165 &glyphPath.initialHintMap,
1166 &glyphPath.hintMoves,
1168 cf2_hintmask_init( &counterMask, error );
1170 cf2_hintmask_read( &counterMask,
1172 cf2_arrstack_size( &hStemHintArray ) +
1173 cf2_arrstack_size( &vStemHintArray ) );
1174 cf2_hintmap_build( &counterHintMap,
1183 case cf2_cmdRMOVETO:
1184 FT_TRACE4(( " rmoveto\n" ));
1186 curY += cf2_stack_popFixed( opStack );
1187 curX += cf2_stack_popFixed( opStack );
1189 cf2_glyphpath_moveTo( &glyphPath, curX, curY );
1191 if ( cf2_stack_count( opStack ) > 0 && !haveWidth )
1192 *width = cf2_stack_popFixed( opStack ) + nominalWidthX;
1197 case cf2_cmdHMOVETO:
1198 FT_TRACE4(( " hmoveto\n" ));
1200 curX += cf2_stack_popFixed( opStack );
1202 cf2_glyphpath_moveTo( &glyphPath, curX, curY );
1204 if ( cf2_stack_count( opStack ) > 0 && !haveWidth )
1205 *width = cf2_stack_popFixed( opStack ) + nominalWidthX;
1210 case cf2_cmdRLINECURVE:
1212 CF2_UInt count = cf2_stack_count( opStack );
1216 FT_TRACE4(( " rlinecurve\n" ));
1218 while ( index + 6 < count )
1220 curX += cf2_stack_getReal( opStack, index + 0 );
1221 curY += cf2_stack_getReal( opStack, index + 1 );
1223 cf2_glyphpath_lineTo( &glyphPath, curX, curY );
1227 while ( index < count )
1229 CF2_Fixed x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
1230 CF2_Fixed y1 = cf2_stack_getReal( opStack, index + 1 ) + curY;
1231 CF2_Fixed x2 = cf2_stack_getReal( opStack, index + 2 ) + x1;
1232 CF2_Fixed y2 = cf2_stack_getReal( opStack, index + 3 ) + y1;
1233 CF2_Fixed x3 = cf2_stack_getReal( opStack, index + 4 ) + x2;
1234 CF2_Fixed y3 = cf2_stack_getReal( opStack, index + 5 ) + y2;
1237 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1244 cf2_stack_clear( opStack );
1246 continue; /* no need to clear stack again */
1248 case cf2_cmdVVCURVETO:
1250 CF2_UInt count = cf2_stack_count( opStack );
1254 FT_TRACE4(( " vvcurveto\n" ));
1256 while ( index < count )
1258 CF2_Fixed x1, y1, x2, y2, x3, y3;
1261 if ( ( count - index ) & 1 )
1263 x1 = cf2_stack_getReal( opStack, index ) + curX;
1270 y1 = cf2_stack_getReal( opStack, index + 0 ) + curY;
1271 x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1272 y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1274 y3 = cf2_stack_getReal( opStack, index + 3 ) + y2;
1276 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1283 cf2_stack_clear( opStack );
1285 continue; /* no need to clear stack again */
1287 case cf2_cmdHHCURVETO:
1289 CF2_UInt count = cf2_stack_count( opStack );
1293 FT_TRACE4(( " hhcurveto\n" ));
1295 while ( index < count )
1297 CF2_Fixed x1, y1, x2, y2, x3, y3;
1300 if ( ( count - index ) & 1 )
1302 y1 = cf2_stack_getReal( opStack, index ) + curY;
1309 x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
1310 x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1311 y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1312 x3 = cf2_stack_getReal( opStack, index + 3 ) + x2;
1315 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1322 cf2_stack_clear( opStack );
1324 continue; /* no need to clear stack again */
1326 case cf2_cmdVHCURVETO:
1327 case cf2_cmdHVCURVETO:
1329 CF2_UInt count = cf2_stack_count( opStack );
1332 FT_Bool alternate = op1 == cf2_cmdHVCURVETO;
1335 FT_TRACE4(( alternate ? " hvcurveto\n" : " vhcurveto\n" ));
1337 while ( index < count )
1339 CF2_Fixed x1, x2, x3, y1, y2, y3;
1344 x1 = cf2_stack_getReal( opStack, index + 0 ) + curX;
1346 x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1347 y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1348 y3 = cf2_stack_getReal( opStack, index + 3 ) + y2;
1350 if ( count - index == 5 )
1352 x3 = cf2_stack_getReal( opStack, index + 4 ) + x2;
1364 y1 = cf2_stack_getReal( opStack, index + 0 ) + curY;
1365 x2 = cf2_stack_getReal( opStack, index + 1 ) + x1;
1366 y2 = cf2_stack_getReal( opStack, index + 2 ) + y1;
1367 x3 = cf2_stack_getReal( opStack, index + 3 ) + x2;
1369 if ( count - index == 5 )
1371 y3 = cf2_stack_getReal( opStack, index + 4 ) + y2;
1381 cf2_glyphpath_curveTo( &glyphPath, x1, y1, x2, y2, x3, y3 );
1388 cf2_stack_clear( opStack );
1390 continue; /* no need to clear stack again */
1392 case cf2_cmdEXTENDEDNMBR:
1397 v = (FT_Short)( ( cf2_buf_readByte( charstring ) << 8 ) |
1398 cf2_buf_readByte( charstring ) );
1400 FT_TRACE4(( " %d", v ));
1402 cf2_stack_pushInt( opStack, v );
1409 if ( /* op1 >= 32 && */ op1 <= 246 )
1416 FT_TRACE4(( " %d", v ));
1419 cf2_stack_pushInt( opStack, v );
1422 else if ( /* op1 >= 247 && */ op1 <= 250 )
1430 v += cf2_buf_readByte( charstring );
1433 FT_TRACE4(( " %d", v ));
1436 cf2_stack_pushInt( opStack, v );
1439 else if ( /* op1 >= 251 && */ op1 <= 254 )
1447 v += cf2_buf_readByte( charstring );
1450 FT_TRACE4(( " %d", v ));
1453 cf2_stack_pushInt( opStack, v );
1456 else /* op1 == 255 */
1462 ( ( (FT_UInt32)cf2_buf_readByte( charstring ) << 24 ) |
1463 ( (FT_UInt32)cf2_buf_readByte( charstring ) << 16 ) |
1464 ( (FT_UInt32)cf2_buf_readByte( charstring ) << 8 ) |
1465 (FT_UInt32)cf2_buf_readByte( charstring ) );
1467 FT_TRACE4(( " %.2f", v / 65536.0 ));
1469 cf2_stack_pushFixed( opStack, v );
1472 continue; /* don't clear stack */
1474 } /* end of switch statement checking `op1' */
1476 cf2_stack_clear( opStack );
1478 } /* end of main interpreter loop */
1480 /* we get here if the charstring ends without cf2_cmdENDCHAR */
1481 FT_TRACE4(( "cf2_interpT2CharString:"
1482 " charstring ends without ENDCHAR\n" ));
1485 /* check whether last error seen is also the first one */
1486 cf2_setError( error, lastError );
1488 /* free resources from objects we've used */
1489 cf2_glyphpath_finalize( &glyphPath );
1490 cf2_arrstack_finalize( &vStemHintArray );
1491 cf2_arrstack_finalize( &hStemHintArray );
1492 cf2_arrstack_finalize( &subrStack );
1493 cf2_stack_free( opStack );
1495 FT_TRACE4(( "\n" ));