From 27a4f9c4ac45ff65f941964f7351b64b1e6a9f35 Mon Sep 17 00:00:00 2001 From: scuri Date: Tue, 20 Oct 2009 17:20:18 +0000 Subject: *** empty log message *** --- src/freetype2/cff/cffgload.c | 706 ++++++++++++++++++++++++++++--------------- 1 file changed, 456 insertions(+), 250 deletions(-) (limited to 'src/freetype2/cff/cffgload.c') diff --git a/src/freetype2/cff/cffgload.c b/src/freetype2/cff/cffgload.c index 0e2a179..40fa20b 100644 --- a/src/freetype2/cff/cffgload.c +++ b/src/freetype2/cff/cffgload.c @@ -4,7 +4,7 @@ /* */ /* OpenType Glyph Loader (body). */ /* */ -/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */ /* David Turner, Robert Wilhelm, and Werner Lemberg. */ /* */ /* This file is part of the FreeType project, and may only be used, */ @@ -18,11 +18,9 @@ #include #include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_CALC_H #include FT_INTERNAL_STREAM_H #include FT_INTERNAL_SFNT_H #include FT_OUTLINE_H -#include FT_TRUETYPE_TAGS_H #include FT_INTERNAL_POSTSCRIPT_HINTS_H #include "cffobjs.h" @@ -110,6 +108,12 @@ cff_op_callgsubr, cff_op_return, + /* Type 1 opcodes: invalid but seen in real life */ + cff_op_hsbw, + cff_op_closepath, + cff_op_callothersubr, + cff_op_pop, + /* do not remove */ cff_op_max @@ -120,6 +124,11 @@ #define CFF_COUNT_EXACT 0x40 #define CFF_COUNT_CLEAR_STACK 0x20 + /* count values which have the `CFF_COUNT_CHECK_WIDTH' flag set are */ + /* used for checking the width and requested numbers of arguments */ + /* only; they are set to zero afterwards */ + + /* the other two flags are informative only and unused currently */ static const FT_Byte cff_argument_counts[] = { @@ -187,6 +196,11 @@ 1, /* callsubr */ 1, + 0, + + 2, /* hsbw */ + 0, + 0, 0 }; @@ -222,6 +236,8 @@ /* */ /* glyph :: The current glyph object. */ /* */ + /* hinting :: Whether hinting is active. */ + /* */ static void cff_builder_init( CFF_Builder* builder, TT_Face face, @@ -251,17 +267,14 @@ if ( hinting && size ) { - builder->hints_globals = size->root.internal; + CFF_Internal internal = (CFF_Internal)size->root.internal; + + + builder->hints_globals = (void *)internal->topfont; builder->hints_funcs = glyph->root.internal->glyph_hints; } } - if ( size ) - { - builder->scale_x = size->root.metrics.x_scale; - builder->scale_y = size->root.metrics.y_scale; - } - builder->pos_x = 0; builder->pos_y = 0; @@ -339,11 +352,15 @@ /* decoder :: A pointer to the glyph builder to initialize. */ /* */ /* */ - /* face :: The current face object. */ + /* face :: The current face object. */ /* */ - /* size :: The current size object. */ + /* size :: The current size object. */ + /* */ + /* slot :: The current glyph object. */ /* */ - /* slot :: The current glyph object. */ + /* hinting :: Whether hinting is active. */ + /* */ + /* hint_mode :: The hinting mode. */ /* */ FT_LOCAL_DEF( void ) cff_decoder_init( CFF_Decoder* decoder, @@ -371,18 +388,21 @@ } - /* this function is used to select the locals subrs array */ + /* this function is used to select the subfont */ + /* and the locals subrs array */ FT_LOCAL_DEF( FT_Error ) cff_decoder_prepare( CFF_Decoder* decoder, + CFF_Size size, FT_UInt glyph_index ) { - CFF_Font cff = (CFF_Font)decoder->builder.face->extra.data; - CFF_SubFont sub = &cff->top_font; - FT_Error error = CFF_Err_Ok; + CFF_Builder *builder = &decoder->builder; + CFF_Font cff = (CFF_Font)builder->face->extra.data; + CFF_SubFont sub = &cff->top_font; + FT_Error error = CFF_Err_Ok; /* manage CID fonts */ - if ( cff->num_subfonts >= 1 ) + if ( cff->num_subfonts ) { FT_Byte fd_index = cff_fd_select_get( &cff->fd_select, glyph_index ); @@ -393,9 +413,24 @@ error = CFF_Err_Invalid_File_Format; goto Exit; } - + + FT_TRACE4(( "glyph index %d (subfont %d):\n", glyph_index, fd_index )); + sub = cff->subfonts[fd_index]; + + if ( builder->hints_funcs && size ) + { + CFF_Internal internal = (CFF_Internal)size->root.internal; + + + /* for CFFs without subfonts, this value has already been set */ + builder->hints_globals = (void *)internal->subfonts[fd_index]; + } } +#ifdef FT_DEBUG_LEVEL_TRACE + else + FT_TRACE4(( "glyph index %d:\n", glyph_index )); +#endif decoder->num_locals = sub->num_local_subrs; decoder->locals = sub->local_subrs; @@ -437,8 +472,6 @@ point->x = x >> 16; point->y = y >> 16; *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC ); - - builder->last = *point; } outline->n_points++; @@ -517,27 +550,24 @@ cff_builder_close_contour( CFF_Builder* builder ) { FT_Outline* outline = builder->current; + FT_Int first; if ( !outline ) return; - /* XXXX: We must not include the last point in the path if it */ - /* is located on the first point. */ + first = outline->n_contours <= 1 + ? 0 : outline->contours[outline->n_contours - 2] + 1; + + /* We must not include the last point in the path if it */ + /* is located on the first point. */ if ( outline->n_points > 1 ) { - FT_Int first = 0; FT_Vector* p1 = outline->points + first; FT_Vector* p2 = outline->points + outline->n_points - 1; FT_Byte* control = (FT_Byte*)outline->tags + outline->n_points - 1; - if ( outline->n_contours > 1 ) - { - first = outline->contours[outline->n_contours - 2] + 1; - p1 = outline->points + first; - } - /* `delete' last point only if it coincides with the first */ /* point and if it is not a control point (which can happen). */ if ( p1->x == p2->x && p1->y == p2->y ) @@ -546,8 +576,18 @@ } if ( outline->n_contours > 0 ) - outline->contours[outline->n_contours - 1] = - (short)( outline->n_points - 1 ); + { + /* Don't add contours only consisting of one point, i.e., */ + /* check whether begin point and last point are the same. */ + if ( first == outline->n_points - 1 ) + { + outline->n_contours--; + outline->n_points--; + } + else + outline->contours[outline->n_contours - 1] = + (short)( outline->n_points - 1 ); + } } @@ -667,6 +707,12 @@ FT_ULong charstring_len; + if ( decoder->seac ) + { + FT_ERROR(( "cff_operator_seac: invalid nested seac\n" )); + return CFF_Err_Syntax_Error; + } + #ifdef FT_CONFIG_OPTION_INCREMENTAL /* Incremental fonts don't necessarily have valid charsets. */ /* They use the character code, not the glyph index, in this case. */ @@ -687,8 +733,8 @@ if ( bchar_index < 0 || achar_index < 0 ) { - FT_ERROR(( "cff_operator_seac:" )); - FT_ERROR(( " invalid seac character code arguments\n" )); + FT_ERROR(( "cff_operator_seac:" + " invalid seac character code arguments\n" )); return CFF_Err_Syntax_Error; } @@ -737,8 +783,11 @@ &charstring, &charstring_len ); if ( !error ) { + /* the seac operator must not be nested */ + decoder->seac = TRUE; error = cff_decoder_parse_charstrings( decoder, charstring, charstring_len ); + decoder->seac = FALSE; if ( error ) goto Exit; @@ -763,8 +812,11 @@ &charstring, &charstring_len ); if ( !error ) { + /* the seac operator must not be nested */ + decoder->seac = TRUE; error = cff_decoder_parse_charstrings( decoder, charstring, charstring_len ); + decoder->seac = FALSE; if ( error ) goto Exit; @@ -826,9 +878,10 @@ decoder->read_width = 1; /* compute random seed from stack address of parameter */ - seed = (FT_Fixed)(char*)&seed ^ - (FT_Fixed)(char*)&decoder ^ - (FT_Fixed)(char*)&charstring_base; + seed = (FT_Fixed)( ( (FT_PtrDist)(char*)&seed ^ + (FT_PtrDist)(char*)&decoder ^ + (FT_PtrDist)(char*)&charstring_base ) & + FT_ULONG_MAX ) ; seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFFL; if ( seed == 0 ) seed = 0x7384; @@ -883,18 +936,18 @@ ip += 2; } else if ( v < 247 ) - val = (FT_Long)v - 139; + val = (FT_Int32)v - 139; else if ( v < 251 ) { if ( ip >= limit ) goto Syntax_Error; - val = ( (FT_Long)v - 247 ) * 256 + *ip++ + 108; + val = ( (FT_Int32)v - 247 ) * 256 + *ip++ + 108; } else if ( v < 255 ) { if ( ip >= limit ) goto Syntax_Error; - val = -( (FT_Long)v - 251 ) * 256 - *ip++ - 108; + val = -( (FT_Int32)v - 251 ) * 256 - *ip++ - 108; } else { @@ -923,6 +976,11 @@ } else { + /* The specification says that normally arguments are to be taken */ + /* from the bottom of the stack. However, this seems not to be */ + /* correct, at least for Acroread 7.0.8 on GNU/Linux: It pops the */ + /* arguments similar to a PS interpreter. */ + FT_Fixed* args = decoder->top; FT_Int num_args = (FT_Int)( args - decoder->stack ); FT_Int req_args; @@ -954,6 +1012,9 @@ case 8: op = cff_op_rrcurveto; break; + case 9: + op = cff_op_closepath; + break; case 10: op = cff_op_callsubr; break; @@ -1004,6 +1065,12 @@ case 15: op = cff_op_eq; break; + case 16: + op = cff_op_callothersubr; + break; + case 17: + op = cff_op_pop; + break; case 18: op = cff_op_drop; break; @@ -1055,6 +1122,9 @@ } } break; + case 13: + op = cff_op_hsbw; + break; case 14: op = cff_op_endchar; break; @@ -1103,6 +1173,7 @@ default: ; } + if ( op == cff_op_unknown ) goto Syntax_Error; @@ -1110,8 +1181,6 @@ req_args = cff_argument_counts[op]; if ( req_args & CFF_COUNT_CHECK_WIDTH ) { - args = stack; - if ( num_args > 0 && decoder->read_width ) { /* If `nominal_width' is non-zero, the number is really a */ @@ -1145,7 +1214,7 @@ case cff_op_endchar: /* If there is a width specified for endchar, we either have */ /* 1 argument or 5 arguments. We like to argue. */ - set_width_ok = ( ( num_args == 5 ) || ( num_args == 1 ) ); + set_width_ok = ( num_args == 5 ) || ( num_args == 1 ); break; default: @@ -1158,9 +1227,14 @@ decoder->glyph_width = decoder->nominal_width + ( stack[0] >> 16 ); + if ( decoder->width_only ) + { + /* we only want the advance width; stop here */ + break; + } + /* Consumed an argument. */ num_args--; - args++; } } @@ -1168,12 +1242,20 @@ req_args = 0; } - req_args &= 15; + req_args &= 0x000F; if ( num_args < req_args ) goto Stack_Underflow; args -= req_args; num_args -= req_args; + /* At this point, `args' points to the first argument of the */ + /* operand in case `req_args' isn't zero. Otherwise, we have */ + /* to adjust `args' manually. */ + + /* Note that we only pop arguments from the stack which we */ + /* really need and can digest so that we can continue in case */ + /* of superfluous stack elements. */ + switch ( op ) { case cff_op_hstem: @@ -1181,15 +1263,16 @@ case cff_op_hstemhm: case cff_op_vstemhm: /* the number of arguments is always even here */ - FT_TRACE4(( op == cff_op_hstem ? " hstem" : - ( op == cff_op_vstem ? " vstem" : - ( op == cff_op_hstemhm ? " hstemhm" : " vstemhm" ) ) )); + FT_TRACE4(( + op == cff_op_hstem ? " hstem\n" : + ( op == cff_op_vstem ? " vstem\n" : + ( op == cff_op_hstemhm ? " hstemhm\n" : " vstemhm\n" ) ) )); if ( hinter ) hinter->stems( hinter->hints, ( op == cff_op_hstem || op == cff_op_hstemhm ), num_args / 2, - args ); + args - ( num_args & ~1 ) ); decoder->num_hints += num_args / 2; args = stack; @@ -1209,7 +1292,7 @@ hinter->stems( hinter->hints, 0, num_args / 2, - args ); + args - ( num_args & ~1 ) ); decoder->num_hints += num_args / 2; } @@ -1232,12 +1315,14 @@ FT_UInt maskbyte; - FT_TRACE4(( " " )); + FT_TRACE4(( " (maskbytes: " )); for ( maskbyte = 0; maskbyte < (FT_UInt)(( decoder->num_hints + 7 ) >> 3); maskbyte++, ip++ ) FT_TRACE4(( "0x%02X", *ip )); + + FT_TRACE4(( ")\n" )); } #else ip += ( decoder->num_hints + 7 ) >> 3; @@ -1248,44 +1333,44 @@ break; case cff_op_rmoveto: - FT_TRACE4(( " rmoveto" )); + FT_TRACE4(( " rmoveto\n" )); cff_builder_close_contour( builder ); builder->path_begun = 0; - x += args[0]; - y += args[1]; + x += args[-2]; + y += args[-1]; args = stack; break; case cff_op_vmoveto: - FT_TRACE4(( " vmoveto" )); + FT_TRACE4(( " vmoveto\n" )); cff_builder_close_contour( builder ); builder->path_begun = 0; - y += args[0]; + y += args[-1]; args = stack; break; case cff_op_hmoveto: - FT_TRACE4(( " hmoveto" )); + FT_TRACE4(( " hmoveto\n" )); cff_builder_close_contour( builder ); builder->path_begun = 0; - x += args[0]; + x += args[-1]; args = stack; break; case cff_op_rlineto: - FT_TRACE4(( " rlineto" )); + FT_TRACE4(( " rlineto\n" )); if ( cff_builder_start_point ( builder, x, y ) || check_points( builder, num_args / 2 ) ) goto Fail; - if ( num_args < 2 || num_args & 1 ) + if ( num_args < 2 ) goto Stack_Underflow; - args = stack; + args -= num_args & ~1; while ( args < decoder->top ) { x += args[0]; @@ -1302,8 +1387,11 @@ FT_Int phase = ( op == cff_op_hlineto ); - FT_TRACE4(( op == cff_op_hlineto ? " hlineto" - : " vlineto" )); + FT_TRACE4(( op == cff_op_hlineto ? " hlineto\n" + : " vlineto\n" )); + + if ( num_args < 1 ) + goto Stack_Underflow; if ( cff_builder_start_point ( builder, x, y ) || check_points( builder, num_args ) ) @@ -1328,125 +1416,164 @@ break; case cff_op_rrcurveto: - FT_TRACE4(( " rrcurveto" )); + { + FT_Int nargs; - /* check number of arguments; must be a multiple of 6 */ - if ( num_args % 6 != 0 ) - goto Stack_Underflow; - if ( cff_builder_start_point ( builder, x, y ) || - check_points( builder, num_args / 2 ) ) - goto Fail; + FT_TRACE4(( " rrcurveto\n" )); - args = stack; - while ( args < decoder->top ) - { - x += args[0]; - y += args[1]; - cff_builder_add_point( builder, x, y, 0 ); - x += args[2]; - y += args[3]; - cff_builder_add_point( builder, x, y, 0 ); - x += args[4]; - y += args[5]; - cff_builder_add_point( builder, x, y, 1 ); - args += 6; + if ( num_args < 6 ) + goto Stack_Underflow; + + nargs = num_args - num_args % 6; + + if ( cff_builder_start_point ( builder, x, y ) || + check_points( builder, nargs / 2 ) ) + goto Fail; + + args -= nargs; + while ( args < decoder->top ) + { + x += args[0]; + y += args[1]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[2]; + y += args[3]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[4]; + y += args[5]; + cff_builder_add_point( builder, x, y, 1 ); + args += 6; + } + args = stack; } - args = stack; break; case cff_op_vvcurveto: - FT_TRACE4(( " vvcurveto" )); + { + FT_Int nargs; - if ( cff_builder_start_point( builder, x, y ) ) - goto Fail; - args = stack; - if ( num_args & 1 ) - { - x += args[0]; - args++; - num_args--; - } + FT_TRACE4(( " vvcurveto\n" )); - if ( num_args % 4 != 0 ) - goto Stack_Underflow; + if ( num_args < 4 ) + goto Stack_Underflow; - if ( check_points( builder, 3 * ( num_args / 4 ) ) ) - goto Fail; + /* if num_args isn't of the form 4n or 4n+1, */ + /* we reduce it to 4n+1 */ - while ( args < decoder->top ) - { - y += args[0]; - cff_builder_add_point( builder, x, y, 0 ); - x += args[1]; - y += args[2]; - cff_builder_add_point( builder, x, y, 0 ); - y += args[3]; - cff_builder_add_point( builder, x, y, 1 ); - args += 4; + nargs = num_args - num_args % 4; + if ( num_args - nargs > 0 ) + nargs += 1; + + if ( cff_builder_start_point( builder, x, y ) ) + goto Fail; + + args -= nargs; + + if ( nargs & 1 ) + { + x += args[0]; + args++; + nargs--; + } + + if ( check_points( builder, 3 * ( nargs / 4 ) ) ) + goto Fail; + + while ( args < decoder->top ) + { + y += args[0]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[1]; + y += args[2]; + cff_builder_add_point( builder, x, y, 0 ); + y += args[3]; + cff_builder_add_point( builder, x, y, 1 ); + args += 4; + } + args = stack; } - args = stack; break; case cff_op_hhcurveto: - FT_TRACE4(( " hhcurveto" )); + { + FT_Int nargs; - if ( cff_builder_start_point( builder, x, y ) ) - goto Fail; - args = stack; - if ( num_args & 1 ) - { - y += args[0]; - args++; - num_args--; - } + FT_TRACE4(( " hhcurveto\n" )); - if ( num_args % 4 != 0 ) - goto Stack_Underflow; + if ( num_args < 4 ) + goto Stack_Underflow; - if ( check_points( builder, 3 * ( num_args / 4 ) ) ) - goto Fail; + /* if num_args isn't of the form 4n or 4n+1, */ + /* we reduce it to 4n+1 */ - while ( args < decoder->top ) - { - x += args[0]; - cff_builder_add_point( builder, x, y, 0 ); - x += args[1]; - y += args[2]; - cff_builder_add_point( builder, x, y, 0 ); - x += args[3]; - cff_builder_add_point( builder, x, y, 1 ); - args += 4; + nargs = num_args - num_args % 4; + if ( num_args - nargs > 0 ) + nargs += 1; + + if ( cff_builder_start_point( builder, x, y ) ) + goto Fail; + + args -= nargs; + if ( nargs & 1 ) + { + y += args[0]; + args++; + nargs--; + } + + if ( check_points( builder, 3 * ( nargs / 4 ) ) ) + goto Fail; + + while ( args < decoder->top ) + { + x += args[0]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[1]; + y += args[2]; + cff_builder_add_point( builder, x, y, 0 ); + x += args[3]; + cff_builder_add_point( builder, x, y, 1 ); + args += 4; + } + args = stack; } - args = stack; break; case cff_op_vhcurveto: case cff_op_hvcurveto: { FT_Int phase; + FT_Int nargs; - FT_TRACE4(( op == cff_op_vhcurveto ? " vhcurveto" - : " hvcurveto" )); + FT_TRACE4(( op == cff_op_vhcurveto ? " vhcurveto\n" + : " hvcurveto\n" )); if ( cff_builder_start_point( builder, x, y ) ) goto Fail; - args = stack; - if ( num_args < 4 || ( num_args % 4 ) > 1 ) + if ( num_args < 4 ) goto Stack_Underflow; - if ( check_points( builder, ( num_args / 4 ) * 3 ) ) + /* if num_args isn't of the form 8n, 8n+1, 8n+4, or 8n+5, */ + /* we reduce it to the largest one which fits */ + + nargs = num_args - num_args % 4; + if ( num_args - nargs > 0 ) + nargs += 1; + + args -= nargs; + if ( check_points( builder, ( nargs / 4 ) * 3 ) ) goto Stack_Underflow; phase = ( op == cff_op_hvcurveto ); - while ( num_args >= 4 ) + while ( nargs >= 4 ) { - num_args -= 4; + nargs -= 4; if ( phase ) { x += args[0]; @@ -1455,7 +1582,7 @@ y += args[2]; cff_builder_add_point( builder, x, y, 0 ); y += args[3]; - if ( num_args == 1 ) + if ( nargs == 1 ) x += args[4]; cff_builder_add_point( builder, x, y, 1 ); } @@ -1467,7 +1594,7 @@ y += args[2]; cff_builder_add_point( builder, x, y, 0 ); x += args[3]; - if ( num_args == 1 ) + if ( nargs == 1 ) y += args[4]; cff_builder_add_point( builder, x, y, 1 ); } @@ -1480,19 +1607,23 @@ case cff_op_rlinecurve: { - FT_Int num_lines = ( num_args - 6 ) / 2; + FT_Int num_lines; + FT_Int nargs; - FT_TRACE4(( " rlinecurve" )); + FT_TRACE4(( " rlinecurve\n" )); - if ( num_args < 8 || ( num_args - 6 ) & 1 ) + if ( num_args < 8 ) goto Stack_Underflow; + nargs = num_args & ~1; + num_lines = ( nargs - 6 ) / 2; + if ( cff_builder_start_point( builder, x, y ) || check_points( builder, num_lines + 3 ) ) goto Fail; - args = stack; + args -= nargs; /* first, add the line segments */ while ( num_lines > 0 ) @@ -1520,19 +1651,24 @@ case cff_op_rcurveline: { - FT_Int num_curves = ( num_args - 2 ) / 6; + FT_Int num_curves; + FT_Int nargs; - FT_TRACE4(( " rcurveline" )); + FT_TRACE4(( " rcurveline\n" )); - if ( num_args < 8 || ( num_args - 2 ) % 6 ) + if ( num_args < 8 ) goto Stack_Underflow; + nargs = num_args - 2; + nargs = nargs - nargs % 6 + 2; + num_curves = ( nargs - 2 ) / 6; + if ( cff_builder_start_point ( builder, x, y ) || - check_points( builder, num_curves*3 + 2 ) ) + check_points( builder, num_curves * 3 + 2 ) ) goto Fail; - args = stack; + args -= nargs; /* first, add the curves */ while ( num_curves > 0 ) @@ -1563,18 +1699,16 @@ FT_Pos start_y; - FT_TRACE4(( " hflex1" )); - - args = stack; + FT_TRACE4(( " hflex1\n" )); - /* adding five more points; 4 control points, 1 on-curve point */ - /* make sure we have enough space for the start point if it */ + /* adding five more points: 4 control points, 1 on-curve point */ + /* -- make sure we have enough space for the start point if it */ /* needs to be added */ if ( cff_builder_start_point( builder, x, y ) || check_points( builder, 6 ) ) goto Fail; - /* Record the starting point's y position for later use */ + /* record the starting point's y position for later use */ start_y = y; /* first control point */ @@ -1616,9 +1750,7 @@ FT_Pos start_y; - FT_TRACE4(( " hflex" )); - - args = stack; + FT_TRACE4(( " hflex\n" )); /* adding six more points; 4 control points, 2 on-curve points */ if ( cff_builder_start_point( builder, x, y ) || @@ -1663,14 +1795,15 @@ case cff_op_flex1: { - FT_Pos start_x, start_y; /* record start x, y values for */ - /* alter use */ - FT_Fixed dx = 0, dy = 0; /* used in horizontal/vertical */ - /* algorithm below */ - FT_Int horizontal, count; + FT_Pos start_x, start_y; /* record start x, y values for */ + /* alter use */ + FT_Fixed dx = 0, dy = 0; /* used in horizontal/vertical */ + /* algorithm below */ + FT_Int horizontal, count; + FT_Fixed* temp; - FT_TRACE4(( " flex1" )); + FT_TRACE4(( " flex1\n" )); /* adding six more points; 4 control points, 2 on-curve points */ if ( cff_builder_start_point( builder, x, y ) || @@ -1684,21 +1817,20 @@ /* XXX: figure out whether this is supposed to be a horizontal */ /* or vertical flex; the Type 2 specification is vague... */ - args = stack; + temp = args; /* grab up to the last argument */ for ( count = 5; count > 0; count-- ) { - dx += args[0]; - dy += args[1]; - args += 2; + dx += temp[0]; + dy += temp[1]; + temp += 2; } - /* rewind */ - args = stack; - - if ( dx < 0 ) dx = -dx; - if ( dy < 0 ) dy = -dy; + if ( dx < 0 ) + dx = -dx; + if ( dy < 0 ) + dy = -dy; /* strange test, but here it is... */ horizontal = ( dx > dy ); @@ -1707,7 +1839,8 @@ { x += args[0]; y += args[1]; - cff_builder_add_point( builder, x, y, (FT_Bool)( count == 3 ) ); + cff_builder_add_point( builder, x, y, + (FT_Bool)( count == 3 ) ); args += 2; } @@ -1734,13 +1867,12 @@ FT_UInt count; - FT_TRACE4(( " flex" )); + FT_TRACE4(( " flex\n" )); if ( cff_builder_start_point( builder, x, y ) || check_points( builder, 6 ) ) goto Fail; - args = stack; for ( count = 6; count > 0; count-- ) { x += args[0]; @@ -1755,21 +1887,20 @@ break; case cff_op_endchar: - FT_TRACE4(( " endchar" )); + FT_TRACE4(( " endchar\n" )); /* We are going to emulate the seac operator. */ - if ( num_args == 4 ) + if ( num_args >= 4 ) { /* Save glyph width so that the subglyphs don't overwrite it. */ FT_Pos glyph_width = decoder->glyph_width; error = cff_operator_seac( decoder, - args[0], - args[1], - (FT_Int)( args[2] >> 16 ), - (FT_Int)( args[3] >> 16 ) ); - args += 4; + args[-4], + args[-3], + (FT_Int)( args[-2] >> 16 ), + (FT_Int)( args[-1] >> 16 ) ); decoder->glyph_width = glyph_width; } @@ -1799,11 +1930,11 @@ } /* return now! */ - FT_TRACE4(( "\n\n" )); + FT_TRACE4(( "\n" )); return error; case cff_op_abs: - FT_TRACE4(( " abs" )); + FT_TRACE4(( " abs\n" )); if ( args[0] < 0 ) args[0] = -args[0]; @@ -1811,28 +1942,28 @@ break; case cff_op_add: - FT_TRACE4(( " add" )); + FT_TRACE4(( " add\n" )); args[0] += args[1]; args++; break; case cff_op_sub: - FT_TRACE4(( " sub" )); + FT_TRACE4(( " sub\n" )); args[0] -= args[1]; args++; break; case cff_op_div: - FT_TRACE4(( " div" )); + FT_TRACE4(( " div\n" )); args[0] = FT_DivFix( args[0], args[1] ); args++; break; case cff_op_neg: - FT_TRACE4(( " neg" )); + FT_TRACE4(( " neg\n" )); args[0] = -args[0]; args++; @@ -1843,7 +1974,7 @@ FT_Fixed Rand; - FT_TRACE4(( " rand" )); + FT_TRACE4(( " rand\n" )); Rand = seed; if ( Rand >= 0x8000L ) @@ -1858,14 +1989,14 @@ break; case cff_op_mul: - FT_TRACE4(( " mul" )); + FT_TRACE4(( " mul\n" )); args[0] = FT_MulFix( args[0], args[1] ); args++; break; case cff_op_sqrt: - FT_TRACE4(( " sqrt" )); + FT_TRACE4(( " sqrt\n" )); if ( args[0] > 0 ) { @@ -1890,7 +2021,7 @@ case cff_op_drop: /* nothing */ - FT_TRACE4(( " drop" )); + FT_TRACE4(( " drop\n" )); break; @@ -1899,7 +2030,7 @@ FT_Fixed tmp; - FT_TRACE4(( " exch" )); + FT_TRACE4(( " exch\n" )); tmp = args[0]; args[0] = args[1]; @@ -1913,7 +2044,7 @@ FT_Int idx = (FT_Int)( args[0] >> 16 ); - FT_TRACE4(( " index" )); + FT_TRACE4(( " index\n" )); if ( idx < 0 ) idx = 0; @@ -1930,7 +2061,7 @@ FT_Int idx = (FT_Int)( args[1] >> 16 ); - FT_TRACE4(( " roll" )); + FT_TRACE4(( " roll\n" )); if ( count <= 0 ) count = 1; @@ -1972,7 +2103,7 @@ break; case cff_op_dup: - FT_TRACE4(( " dup" )); + FT_TRACE4(( " dup\n" )); args[1] = args[0]; args++; @@ -1984,7 +2115,7 @@ FT_Int idx = (FT_Int)( args[1] >> 16 ); - FT_TRACE4(( " put" )); + FT_TRACE4(( " put\n" )); if ( idx >= 0 && idx < decoder->len_buildchar ) decoder->buildchar[idx] = val; @@ -1997,7 +2128,7 @@ FT_Fixed val = 0; - FT_TRACE4(( " get" )); + FT_TRACE4(( " get\n" )); if ( idx >= 0 && idx < decoder->len_buildchar ) val = decoder->buildchar[idx]; @@ -2008,18 +2139,63 @@ break; case cff_op_store: - FT_TRACE4(( " store ")); + FT_TRACE4(( " store\n")); goto Unimplemented; case cff_op_load: - FT_TRACE4(( " load" )); + FT_TRACE4(( " load\n" )); goto Unimplemented; case cff_op_dotsection: /* this operator is deprecated and ignored by the parser */ - FT_TRACE4(( " dotsection" )); + FT_TRACE4(( " dotsection\n" )); + break; + + case cff_op_closepath: + /* this is an invalid Type 2 operator; however, there */ + /* exist fonts which are incorrectly converted from probably */ + /* Type 1 to CFF, and some parsers seem to accept it */ + + FT_TRACE4(( " closepath (invalid op)\n" )); + + args = stack; + break; + + case cff_op_hsbw: + /* this is an invalid Type 2 operator; however, there */ + /* exist fonts which are incorrectly converted from probably */ + /* Type 1 to CFF, and some parsers seem to accept it */ + + FT_TRACE4(( " hsbw (invalid op)\n" )); + + decoder->glyph_width = decoder->nominal_width + + (args[1] >> 16); + x = args[0]; + y = 0; + args = stack; + break; + + case cff_op_callothersubr: + /* this is an invalid Type 2 operator; however, there */ + /* exist fonts which are incorrectly converted from probably */ + /* Type 1 to CFF, and some parsers seem to accept it */ + + FT_TRACE4(( " callothersubr (invalid op)\n" )); + + /* don't modify stack; handle the subr as `unknown' so that */ + /* following `pop' operands use the arguments on stack */ + break; + + case cff_op_pop: + /* this is an invalid Type 2 operator; however, there */ + /* exist fonts which are incorrectly converted from probably */ + /* Type 1 to CFF, and some parsers seem to accept it */ + + FT_TRACE4(( " pop (invalid op)\n" )); + + args++; break; case cff_op_and: @@ -2027,7 +2203,7 @@ FT_Fixed cond = args[0] && args[1]; - FT_TRACE4(( " and" )); + FT_TRACE4(( " and\n" )); args[0] = cond ? 0x10000L : 0; args++; @@ -2039,7 +2215,7 @@ FT_Fixed cond = args[0] || args[1]; - FT_TRACE4(( " or" )); + FT_TRACE4(( " or\n" )); args[0] = cond ? 0x10000L : 0; args++; @@ -2051,7 +2227,7 @@ FT_Fixed cond = !args[0]; - FT_TRACE4(( " eq" )); + FT_TRACE4(( " eq\n" )); args[0] = cond ? 0x10000L : 0; args++; @@ -2063,7 +2239,7 @@ FT_Fixed cond = ( args[2] <= args[3] ); - FT_TRACE4(( " ifelse" )); + FT_TRACE4(( " ifelse\n" )); if ( !cond ) args[0] = args[1]; @@ -2077,12 +2253,12 @@ decoder->locals_bias ); - FT_TRACE4(( " callsubr(%d)", idx )); + FT_TRACE4(( " callsubr(%d)\n", idx )); if ( idx >= decoder->num_locals ) { - FT_ERROR(( "cff_decoder_parse_charstrings:" )); - FT_ERROR(( " invalid local subr index\n" )); + FT_ERROR(( "cff_decoder_parse_charstrings:" + " invalid local subr index\n" )); goto Syntax_Error; } @@ -2103,7 +2279,7 @@ if ( !zone->base || zone->limit == zone->base ) { FT_ERROR(( "cff_decoder_parse_charstrings:" - " invoking empty subrs!\n" )); + " invoking empty subrs\n" )); goto Syntax_Error; } @@ -2119,12 +2295,12 @@ decoder->globals_bias ); - FT_TRACE4(( " callgsubr(%d)", idx )); + FT_TRACE4(( " callgsubr(%d)\n", idx )); if ( idx >= decoder->num_globals ) { - FT_ERROR(( "cff_decoder_parse_charstrings:" )); - FT_ERROR(( " invalid global subr index\n" )); + FT_ERROR(( "cff_decoder_parse_charstrings:" + " invalid global subr index\n" )); goto Syntax_Error; } @@ -2145,7 +2321,7 @@ if ( !zone->base || zone->limit == zone->base ) { FT_ERROR(( "cff_decoder_parse_charstrings:" - " invoking empty subrs!\n" )); + " invoking empty subrs\n" )); goto Syntax_Error; } @@ -2156,7 +2332,7 @@ break; case cff_op_return: - FT_TRACE4(( " return" )); + FT_TRACE4(( " return\n" )); if ( decoder->zone <= decoder->zones ) { @@ -2194,15 +2370,15 @@ return error; Syntax_Error: - FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error!" )); + FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error\n" )); return CFF_Err_Invalid_File_Format; Stack_Underflow: - FT_TRACE4(( "cff_decoder_parse_charstrings: stack underflow!" )); + FT_TRACE4(( "cff_decoder_parse_charstrings: stack underflow\n" )); return CFF_Err_Too_Few_Arguments; Stack_Overflow: - FT_TRACE4(( "cff_decoder_parse_charstrings: stack overflow!" )); + FT_TRACE4(( "cff_decoder_parse_charstrings: stack overflow\n" )); return CFF_Err_Stack_Overflow; } @@ -2260,7 +2436,7 @@ &charstring, &charstring_len ); if ( !error ) { - error = cff_decoder_prepare( &decoder, glyph_index ); + error = cff_decoder_prepare( &decoder, size, glyph_index ); if ( !error ) error = cff_decoder_parse_charstrings( &decoder, charstring, @@ -2290,23 +2466,30 @@ { FT_Error error; CFF_Decoder decoder; - TT_Face face = (TT_Face)glyph->root.face; - FT_Bool hinting; - CFF_Font cff = (CFF_Font)face->extra.data; + TT_Face face = (TT_Face)glyph->root.face; + FT_Bool hinting, force_scaling; + CFF_Font cff = (CFF_Font)face->extra.data; FT_Matrix font_matrix; FT_Vector font_offset; + force_scaling = FALSE; + /* in a CID-keyed font, consider `glyph_index' as a CID and map */ /* it immediately to the real glyph_index -- if it isn't a */ /* subsetted font, glyph_indices and CIDs are identical, though */ if ( cff->top_font.font_dict.cid_registry != 0xFFFFU && - cff->charset.cids ) + cff->charset.cids ) { - glyph_index = cff_charset_cid_to_gindex( &cff->charset, glyph_index ); - if ( glyph_index == 0 ) - return CFF_Err_Invalid_Argument; + /* don't handle CID 0 (.notdef) which is directly mapped to GID 0 */ + if ( glyph_index != 0 ) + { + glyph_index = cff_charset_cid_to_gindex( &cff->charset, + glyph_index ); + if ( glyph_index == 0 ) + return CFF_Err_Invalid_Argument; + } } else if ( glyph_index >= cff->num_glyphs ) return CFF_Err_Invalid_Argument; @@ -2389,6 +2572,36 @@ if ( load_flags & FT_LOAD_SBITS_ONLY ) return CFF_Err_Invalid_Argument; + /* if we have a CID subfont, use its matrix (which has already */ + /* been multiplied with the root matrix) */ + + /* this scaling is only relevant if the PS hinter isn't active */ + if ( cff->num_subfonts ) + { + FT_Byte fd_index = cff_fd_select_get( &cff->fd_select, + glyph_index ); + + FT_ULong top_upm = cff->top_font.font_dict.units_per_em; + FT_ULong sub_upm = cff->subfonts[fd_index]->font_dict.units_per_em; + + + font_matrix = cff->subfonts[fd_index]->font_dict.font_matrix; + font_offset = cff->subfonts[fd_index]->font_dict.font_offset; + + if ( top_upm != sub_upm ) + { + glyph->x_scale = FT_MulDiv( glyph->x_scale, top_upm, sub_upm ); + glyph->y_scale = FT_MulDiv( glyph->y_scale, top_upm, sub_upm ); + + force_scaling = TRUE; + } + } + else + { + font_matrix = cff->top_font.font_dict.font_matrix; + font_offset = cff->top_font.font_dict.font_offset; + } + glyph->root.outline.n_points = 0; glyph->root.outline.n_contours = 0; @@ -2405,15 +2618,18 @@ cff_decoder_init( &decoder, face, size, glyph, hinting, FT_LOAD_TARGET_MODE( load_flags ) ); + if ( load_flags & FT_LOAD_ADVANCE_ONLY ) + decoder.width_only = TRUE; + decoder.builder.no_recurse = - (FT_Bool)( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 ); + (FT_Bool)( load_flags & FT_LOAD_NO_RECURSE ); /* now load the unscaled outline */ error = cff_get_glyph_data( face, glyph_index, &charstring, &charstring_len ); if ( !error ) { - error = cff_decoder_prepare( &decoder, glyph_index ); + error = cff_decoder_prepare( &decoder, size, glyph_index ); if ( !error ) { error = cff_decoder_parse_charstrings( &decoder, @@ -2481,21 +2697,6 @@ if ( !error ) { - if ( cff->num_subfonts >= 1 ) - { - FT_Byte fd_index = cff_fd_select_get( &cff->fd_select, - glyph_index ); - - - font_matrix = cff->subfonts[fd_index]->font_dict.font_matrix; - font_offset = cff->subfonts[fd_index]->font_dict.font_offset; - } - else - { - font_matrix = cff->top_font.font_dict.font_matrix; - font_offset = cff->top_font.font_dict.font_offset; - } - /* Now, set the metrics -- this is rather simple, as */ /* the left side bearing is the xMin, and the top side */ /* bearing the yMax. */ @@ -2526,9 +2727,14 @@ glyph->root.linearHoriAdvance = decoder.glyph_width; glyph->root.internal->glyph_transformed = 0; +#ifdef FT_CONFIG_OPTION_OLD_INTERNALS has_vertical_info = FT_BOOL( face->vertical_info && face->vertical.number_Of_VMetrics > 0 && - face->vertical.long_metrics != 0 ); + face->vertical.long_metrics ); +#else + has_vertical_info = FT_BOOL( face->vertical_info && + face->vertical.number_Of_VMetrics > 0 ); +#endif /* get the vertical metrics from the vtmx table if we have one */ if ( has_vertical_info ) @@ -2565,7 +2771,6 @@ glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL; - /* apply the font matrix */ if ( !( font_matrix.xx == 0x10000L && font_matrix.yy == 0x10000L && font_matrix.xy == 0 && @@ -2587,7 +2792,7 @@ FT_Vector_Transform( &advance, &font_matrix ); metrics->vertAdvance = advance.y + font_offset.y; - if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 ) + if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 || force_scaling ) { /* scale the outline and the metrics */ FT_Int n; @@ -2620,7 +2825,8 @@ metrics->horiBearingY = cbox.yMax; if ( has_vertical_info ) - metrics->vertBearingX = -metrics->width / 2; + metrics->vertBearingX = metrics->horiBearingX - + metrics->horiAdvance / 2; else ft_synthesize_vertical_metrics( metrics, metrics->vertAdvance ); -- cgit v1.2.3