static void gx_ttfReader__Reset(gx_ttfReader *self) { if (self->extra_glyph_index != -1) { self->extra_glyph_index = -1; gs_glyph_data_free(&self->glyph_data, "gx_ttfReader__Reset"); } self->error = false; self->pos = 0; }
static void gx_ttfReader__ReleaseGlyph(ttfReader *self, int glyph_index) { gx_ttfReader *r = (gx_ttfReader *)self; if (r->extra_glyph_index != glyph_index) return; r->extra_glyph_index = -1; gs_glyph_data_free(&r->glyph_data, "gx_ttfReader__ReleaseExtraGlyph"); }
/* Get the outline of a CIDFontType 0 glyph. */ static int z9_glyph_outline(gs_font *font, int WMode, gs_glyph glyph, const gs_matrix *pmat, gx_path *ppath, double sbw[4]) { gs_font_cid0 *const pfcid = (gs_font_cid0 *)font; ref gref; gs_glyph_data_t gdata; int code, fidx, ocode; gdata.memory = font->memory; code = pfcid->cidata.glyph_data((gs_font_base *)pfcid, glyph, &gdata, &fidx); if (code < 0) return code; glyph_ref(font->memory, glyph, &gref); ocode = zcharstring_outline(pfcid->cidata.FDArray[fidx], WMode, &gref, &gdata, pmat, ppath, sbw); gs_glyph_data_free(&gdata, "z9_glyph_outline"); return ocode; }
/* Note that pgd may be NULL. */ static int z9_glyph_data(gs_font_base *pbfont, gs_glyph glyph, gs_glyph_data_t *pgd, int *pfidx) { gs_font_cid0 *pfont = (gs_font_cid0 *)pbfont; const font_data *pfdata = pfont_data(pfont); long glyph_index = (long)(glyph - gs_min_cid_glyph); gs_glyph_data_t gdata; ulong fidx; int code; gdata.memory = pfont->memory; if (!r_has_type(&pfdata->u.cid0.GlyphDirectory, t_null)) { code = font_gdir_get_outline(pfont->memory, &pfdata->u.cid0.GlyphDirectory, glyph_index, &gdata); if (code < 0) return code; /* Get the definition from GlyphDirectory. */ if (!gdata.bits.data) return_error(e_rangecheck); code = get_index(&gdata, pfont->cidata.FDBytes, &fidx); if (code < 0) return code; if (fidx >= pfont->cidata.FDArray_size) return_error(e_rangecheck); if (pgd) *pgd = gdata; *pfidx = (int)fidx; return code; } /* Get the definition from the binary data (GlyphData or DataSource). */ if (glyph_index < 0 || glyph_index >= pfont->cidata.common.CIDCount) { *pfidx = 0; if (pgd) gs_glyph_data_from_null(pgd); return_error(e_rangecheck); } { byte fd_gd[(MAX_FDBytes + MAX_GDBytes) * 2]; uint num_bytes = pfont->cidata.FDBytes + pfont->cidata.common.GDBytes; ulong base = pfont->cidata.CIDMapOffset + glyph_index * num_bytes; ulong gidx, fidx_next, gidx_next; int rcode = cid0_read_bytes(pfont, base, (ulong)(num_bytes * 2), fd_gd, &gdata); gs_glyph_data_t orig_data; if (rcode < 0) return rcode; orig_data = gdata; if ((code = get_index(&gdata, pfont->cidata.FDBytes, &fidx)) < 0 || (code = get_index(&gdata, pfont->cidata.common.GDBytes, &gidx)) < 0 || (code = get_index(&gdata, pfont->cidata.FDBytes, &fidx_next)) < 0 || (code = get_index(&gdata, pfont->cidata.common.GDBytes, &gidx_next)) < 0 ) DO_NOTHING; gs_glyph_data_free(&orig_data, "z9_glyph_data"); if (code < 0) return code; /* * Some CID fonts (from Adobe!) have invalid font indexes for * missing glyphs. Handle this now. */ if (gidx_next <= gidx) { /* missing glyph */ *pfidx = 0; if (pgd) gs_glyph_data_from_null(pgd); return_error(e_undefined); } if (fidx >= pfont->cidata.FDArray_size) return_error(e_rangecheck); *pfidx = (int)fidx; if (pgd == 0) return 0; return cid0_read_bytes(pfont, gidx, gidx_next - gidx, NULL, pgd); } }
/* * Write the Private dictionary. This is a separate procedure only for * readability. write_CharString is a parameter so that we can encrypt * Subrs and CharStrings when the font's lenIV == -1 but we are writing * the font with lenIV = 0. */ static int write_Private(stream *s, gs_font_type1 *pfont, gs_glyph *subset_glyphs, uint subset_size, gs_glyph notdef, int lenIV, int (*write_CharString)(stream *, const void *, uint), const param_printer_params_t *ppp) { const gs_type1_data *const pdata = &pfont->data; printer_param_list_t rlist; gs_param_list *const plist = (gs_param_list *)&rlist; int code = s_init_param_printer(&rlist, ppp, s); if (code < 0) return 0; stream_puts(s, "dup /Private 17 dict dup begin\n"); stream_puts(s, "/-|{string currentfile exch readstring pop}executeonly def\n"); stream_puts(s, "/|-{noaccess def}executeonly def\n"); stream_puts(s, "/|{noaccess put}executeonly def\n"); { static const gs_param_item_t private_items[] = { {"BlueFuzz", gs_param_type_int, offset_of(gs_type1_data, BlueFuzz)}, {"BlueScale", gs_param_type_float, offset_of(gs_type1_data, BlueScale)}, {"BlueShift", gs_param_type_float, offset_of(gs_type1_data, BlueShift)}, {"ExpansionFactor", gs_param_type_float, offset_of(gs_type1_data, ExpansionFactor)}, {"ForceBold", gs_param_type_bool, offset_of(gs_type1_data, ForceBold)}, {"LanguageGroup", gs_param_type_int, offset_of(gs_type1_data, LanguageGroup)}, {"RndStemUp", gs_param_type_bool, offset_of(gs_type1_data, RndStemUp)}, gs_param_item_end }; gs_type1_data defaults; defaults.BlueFuzz = 1; defaults.BlueScale = (float)0.039625; defaults.BlueShift = 7.0; defaults.ExpansionFactor = (float)0.06; defaults.ForceBold = false; defaults.LanguageGroup = 0; defaults.RndStemUp = true; code = gs_param_write_items(plist, pdata, &defaults, private_items); if (code < 0) return code; if (lenIV != 4) { code = param_write_int(plist, "lenIV", &lenIV); if (code < 0) return code; } write_float_array(plist, "BlueValues", pdata->BlueValues.values, pdata->BlueValues.count); write_float_array(plist, "OtherBlues", pdata->OtherBlues.values, pdata->OtherBlues.count); write_float_array(plist, "FamilyBlues", pdata->FamilyBlues.values, pdata->FamilyBlues.count); write_float_array(plist, "FamilyOtherBlues", pdata->FamilyOtherBlues.values, pdata->FamilyOtherBlues.count); write_float_array(plist, "StdHW", pdata->StdHW.values, pdata->StdHW.count); write_float_array(plist, "StdVW", pdata->StdVW.values, pdata->StdVW.count); write_float_array(plist, "StemSnapH", pdata->StemSnapH.values, pdata->StemSnapH.count); write_float_array(plist, "StemSnapV", pdata->StemSnapV.values, pdata->StemSnapV.count); } write_uid(s, &pfont->UID); stream_puts(s, "/MinFeature{16 16} def\n"); stream_puts(s, "/password 5839 def\n"); /* * Write the Subrs. We always write them all, even for subsets. * (We will fix this someday.) */ { int n, i; gs_glyph_data_t gdata; int code; gdata.memory = pfont->memory; for (n = 0; (code = pdata->procs.subr_data(pfont, n, false, &gdata)) != gs_error_rangecheck; ) { ++n; if (code >= 0) gs_glyph_data_free(&gdata, "write_Private(Subrs)"); } pprintd1(s, "/Subrs %d array\n", n); for (i = 0; i < n; ++i) if ((code = pdata->procs.subr_data(pfont, i, false, &gdata)) >= 0) { char buf[50]; if (gdata.bits.size) { sprintf(buf, "dup %d %u -| ", i, gdata.bits.size); stream_puts(s, buf); write_CharString(s, gdata.bits.data, gdata.bits.size); stream_puts(s, " |\n"); } gs_glyph_data_free(&gdata, "write_Private(Subrs)"); } stream_puts(s, "|-\n"); } /* We don't write OtherSubrs -- there had better not be any! */ /* Write the CharStrings. */ { int num_chars = 0; gs_glyph glyph; psf_glyph_enum_t genum; gs_glyph_data_t gdata; int code; gdata.memory = pfont->memory; psf_enumerate_glyphs_begin(&genum, (gs_font *)pfont, subset_glyphs, (subset_glyphs ? subset_size : 0), GLYPH_SPACE_NAME); for (glyph = gs_no_glyph; (code = psf_enumerate_glyphs_next(&genum, &glyph)) != 1; ) if (code == 0 && (code = pdata->procs.glyph_data(pfont, glyph, &gdata)) >= 0 ) { ++num_chars; gs_glyph_data_free(&gdata, "write_Private(CharStrings)"); } pprintd1(s, "2 index /CharStrings %d dict dup begin\n", num_chars); psf_enumerate_glyphs_reset(&genum); for (glyph = gs_no_glyph; (code = psf_enumerate_glyphs_next(&genum, &glyph)) != 1; ) if (code == 0 && (code = pdata->procs.glyph_data(pfont, glyph, &gdata)) >= 0 ) { gs_const_string gstr; int code; code = pfont->procs.glyph_name((gs_font *)pfont, glyph, &gstr); if (code < 0) return code; stream_puts(s, "/"); stream_write(s, gstr.data, gstr.size); pprintd1(s, " %d -| ", gdata.bits.size); write_CharString(s, gdata.bits.data, gdata.bits.size); stream_puts(s, " |-\n"); gs_glyph_data_free(&gdata, "write_Private(CharStrings)"); } } /* Wrap up. */ stream_puts(s, "end\nend\nreadonly put\nnoaccess put\n"); s_release_param_printer(&rlist); return 0; }
int gs_type1_glyph_info(gs_font *font, gs_glyph glyph, const gs_matrix *pmat, int members, gs_glyph_info_t *info) { gs_font_type1 *const pfont = (gs_font_type1 *)font; gs_type1_data *const pdata = &pfont->data; int wmode = ((members & GLYPH_INFO_WIDTH1) != 0); int piece_members = members & (GLYPH_INFO_NUM_PIECES | GLYPH_INFO_PIECES); int width_members = (members & ((GLYPH_INFO_WIDTH0 << wmode) | (GLYPH_INFO_VVECTOR0 << wmode))); int default_members = members & ~(piece_members | GLYPH_INFO_WIDTHS | GLYPH_INFO_VVECTOR0 | GLYPH_INFO_VVECTOR1 | GLYPH_INFO_OUTLINE_WIDTHS); int code = 0; gs_glyph_data_t gdata; if (default_members) { code = gs_default_glyph_info(font, glyph, pmat, default_members, info); if (code < 0) return code; } else info->members = 0; if (default_members == members) return code; /* all done */ gdata.memory = pfont->memory; if ((code = pdata->procs.glyph_data(pfont, glyph, &gdata)) < 0) return code; /* non-existent glyph */ if (piece_members) { code = gs_type1_glyph_pieces(pfont, &gdata, members, info); if (code < 0) return code; info->members |= piece_members; } if (width_members) { gx_path path; /* * Interpret the CharString until we get to the [h]sbw. */ gs_imager_state gis; gs_type1_state cis; int value; /* Initialize just enough of the imager state. */ if (pmat) gs_matrix_fixed_from_matrix(&gis.ctm, pmat); else { gs_matrix imat; gs_make_identity(&imat); gs_matrix_fixed_from_matrix(&gis.ctm, &imat); } gis.flatness = 0; code = gs_type1_interp_init(&cis, &gis, NULL /* no path needed */, NULL, NULL, true, 0, pfont); if (code < 0) return code; cis.no_grid_fitting = true; gx_path_init_bbox_accumulator(&path); cis.path = &path; code = pdata->interpret(&cis, &gdata, &value); switch (code) { case 0: /* done with no [h]sbw, error */ /* Adobe interpreters ignore the error! */ info->width[wmode].x = 0; info->width[wmode].y = 0; info->v.x = 0; info->v.y = 0; break; default: /* code < 0, error */ return code; case type1_result_callothersubr: /* unknown OtherSubr */ return_error(gs_error_rangecheck); /* can't handle it */ case type1_result_sbw: info->width[wmode].x = fixed2float(cis.width.x); info->width[wmode].y = fixed2float(cis.width.y); info->v.x = fixed2float(cis.lsb.x); info->v.y = fixed2float(cis.lsb.y); break; } info->members |= width_members | (GLYPH_INFO_VVECTOR0 << wmode); } gs_glyph_data_free(&gdata, "gs_type1_glyph_info"); return code; }
/* * If a Type 1 character is defined with 'seac', store the character codes * in chars[0] and chars[1] and return 1; otherwise, return 0 or <0. * This is exported only for the benefit of font copying. */ int gs_type1_piece_codes(/*const*/ gs_font_type1 *pfont, const gs_glyph_data_t *pgd, gs_char *chars) { gs_type1_data *const pdata = &pfont->data; /* * Decode the CharString looking for seac. We have to process * callsubr, callothersubr, and return operators, but if we see * any other operators other than [h]sbw, pop, hint operators, * or endchar, we can return immediately. We have to include * endchar because it is an (undocumented) equivalent for seac * in Type 2 CharStrings: see the cx_endchar case in * gs_type2_interpret in gstype2.c. * * It's really unfortunate that we have to duplicate so much parsing * code, but factoring out the parser from the interpreter would * involve more restructuring than we're prepared to do right now. */ bool encrypted = pdata->lenIV >= 0; fixed cstack[ostack_size]; fixed *csp; ip_state_t ipstack[ipstack_size + 1]; ip_state_t *ipsp = &ipstack[0]; const byte *cip; crypt_state state; int c; int code; CLEAR_CSTACK(cstack, csp); cip = pgd->bits.data; call: state = crypt_charstring_seed; if (encrypted) { int skip = pdata->lenIV; /* Skip initial random bytes */ for (; skip > 0; ++cip, --skip) decrypt_skip_next(*cip, state); } top: for (;;) { uint c0 = *cip++; charstring_next(c0, state, c, encrypted); if (c >= c_num1) { /* This is a number, decode it and push it on the stack. */ if (c < c_pos2_0) { /* 1-byte number */ decode_push_num1(csp, cstack, c); } else if (c < cx_num4) { /* 2-byte number */ decode_push_num2(csp, cstack, c, cip, state, encrypted); } else if (c == cx_num4) { /* 4-byte number */ long lw; decode_num4(lw, cip, state, encrypted); CS_CHECK_PUSH(csp, cstack); *++csp = int2fixed(lw); } else /* not possible */ return_error(gs_error_invalidfont); continue; } #define cnext CLEAR_CSTACK(cstack, csp); goto top switch ((char_command) c) { default: goto out; case c_callsubr: c = fixed2int_var(*csp) + pdata->subroutineNumberBias; code = pdata->procs.subr_data (pfont, c, false, &ipsp[1].cs_data); if (code < 0) return_error(code); --csp; ipsp->ip = cip, ipsp->dstate = state; ++ipsp; cip = ipsp->cs_data.bits.data; goto call; case c_return: gs_glyph_data_free(&ipsp->cs_data, "gs_type1_piece_codes"); --ipsp; cip = ipsp->ip, state = ipsp->dstate; goto top; case cx_hstem: case cx_vstem: case c1_hsbw: cnext; case cx_endchar: if (csp < cstack + 3) goto out; /* not seac */ do_seac: /* This is the payoff for all this code! */ chars[0] = fixed2int(csp[-1]); chars[1] = fixed2int(csp[0]); return 1; case cx_escape: charstring_next(*cip, state, c, encrypted); ++cip; switch ((char1_extended_command) c) { default: goto out; case ce1_vstem3: case ce1_hstem3: case ce1_sbw: cnext; case ce1_pop: /* * pop must do nothing, since it is used after * subr# 1 3 callothersubr. */ goto top; case ce1_seac: goto do_seac; case ce1_callothersubr: switch (fixed2int_var(*csp)) { default: goto out; case 3: csp -= 2; goto top; case 12: case 13: case 14: case 15: case 16: case 17: case 18: cnext; } } } #undef cnext } out: return 0; }
/* * Continue interpreting a Type 1 charstring. If str != 0, it is taken as * the byte string to interpret. Return 0 on successful completion, <0 on * error, or >0 when client intervention is required (or allowed). The int* * argument is where the othersubr # is stored for callothersubr. */ int gs_type1_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd, int *pindex) { gs_font_type1 *pfont = pcis->pfont; gs_type1_data *pdata = &pfont->data; t1_hinter *h = &pcis->h; bool encrypted = pdata->lenIV >= 0; fixed cstack[ostack_size]; #define cs0 cstack[0] #define ics0 fixed2int_var(cs0) #define cs1 cstack[1] #define ics1 fixed2int_var(cs1) #define cs2 cstack[2] #define ics2 fixed2int_var(cs2) #define cs3 cstack[3] #define ics3 fixed2int_var(cs3) #define cs4 cstack[4] #define ics4 fixed2int_var(cs4) #define cs5 cstack[5] #define ics5 fixed2int_var(cs5) cs_ptr csp; #define clear CLEAR_CSTACK(cstack, csp) ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1]; register const byte *cip; register crypt_state state; register int c; int code = 0; fixed ftx = pcis->origin.x, fty = pcis->origin.y; switch (pcis->init_done) { case -1: t1_hinter__init(h, pcis->path); break; case 0: gs_type1_finish_init(pcis); /* sets origin */ ftx = pcis->origin.x, fty = pcis->origin.y; code = t1_hinter__set_mapping(h, &pcis->pis->ctm, &pfont->FontMatrix, &pfont->base->FontMatrix, pcis->scale.x.log2_unit, pcis->scale.x.log2_unit, pcis->scale.x.log2_unit - pcis->log2_subpixels.x, pcis->scale.y.log2_unit - pcis->log2_subpixels.y, pcis->origin.x, pcis->origin.y, gs_currentaligntopixels(pfont->dir)); if (code < 0) return code; code = t1_hinter__set_font_data(h, 1, pdata, pcis->no_grid_fitting); if (code < 0) return code; break; default /*case 1 */ : break; } INIT_CSTACK(cstack, csp, pcis); if (pgd == 0) goto cont; ipsp->cs_data = *pgd; cip = pgd->bits.data; call:state = crypt_charstring_seed; if (encrypted) { int skip = pdata->lenIV; /* Skip initial random bytes */ for (; skip > 0; ++cip, --skip) decrypt_skip_next(*cip, state); } goto top; cont:cip = ipsp->ip; state = ipsp->dstate; top:for (;;) { uint c0 = *cip++; charstring_next(c0, state, c, encrypted); if (c >= c_num1) { /* This is a number, decode it and push it on the stack. */ if (c < c_pos2_0) { /* 1-byte number */ decode_push_num1(csp, cstack, c); } else if (c < cx_num4) { /* 2-byte number */ decode_push_num2(csp, cstack, c, cip, state, encrypted); } else if (c == cx_num4) { /* 4-byte number */ long lw; decode_num4(lw, cip, state, encrypted); CS_CHECK_PUSH(csp, cstack); *++csp = int2fixed(lw); if (lw != fixed2long(*csp)) { /* * We handle the only case we've ever seen that * actually uses such large numbers specially. */ long denom; c0 = *cip++; charstring_next(c0, state, c, encrypted); if (c < c_num1) return_error(gs_error_rangecheck); if (c < c_pos2_0) decode_num1(denom, c); else if (c < cx_num4) decode_num2(denom, c, cip, state, encrypted); else if (c == cx_num4) decode_num4(denom, cip, state, encrypted); else return_error(gs_error_invalidfont); c0 = *cip++; charstring_next(c0, state, c, encrypted); if (c != cx_escape) return_error(gs_error_rangecheck); c0 = *cip++; charstring_next(c0, state, c, encrypted); if (c != ce1_div) return_error(gs_error_rangecheck); *csp = float2fixed((double)lw / denom); } } else /* not possible */ return_error(gs_error_invalidfont); pushed:if_debug3('1', "[1]%d: (%d) %f\n", (int)(csp - cstack), c, fixed2float(*csp)); continue; } #ifdef DEBUG if (gs_debug['1']) { static const char *const c1names[] = {char1_command_names}; if (c1names[c] == 0) dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c); else dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c, c1names[c]); } #endif switch ((char_command) c) { #define cnext clear; goto top #define inext goto top /* Commands with identical functions in Type 1 and Type 2, */ /* except for 'escape'. */ case c_undef0: case c_undef2: case c_undef17: return_error(gs_error_invalidfont); case c_callsubr: c = fixed2int_var(*csp) + pdata->subroutineNumberBias; code = pdata->procs.subr_data (pfont, c, false, &ipsp[1].cs_data); if (code < 0) return_error(code); --csp; ipsp->ip = cip, ipsp->dstate = state; ++ipsp; cip = ipsp->cs_data.bits.data; goto call; case c_return: gs_glyph_data_free(&ipsp->cs_data, "gs_type1_interpret"); --ipsp; goto cont; case c_undoc15: /* See gstype1.h for information on this opcode. */ cnext; /* Commands with similar but not identical functions */ /* in Type 1 and Type 2 charstrings. */ case cx_hstem: code = t1_hinter__hstem(h, cs0, cs1); if (code < 0) return code; cnext; case cx_vstem: code = t1_hinter__vstem(h, cs0, cs1); if (code < 0) return code; cnext; case cx_vmoveto: cs1 = cs0; cs0 = 0; move: /* cs0 = dx, cs1 = dy for hint checking. */ code = t1_hinter__rmoveto(h, cs0, cs1); goto cc; case cx_rlineto: line: /* cs0 = dx, cs1 = dy for hint checking. */ code = t1_hinter__rlineto(h, cs0, cs1); cc:if (code < 0) return code; cnext; case cx_hlineto: cs1 = 0; goto line; case cx_vlineto: cs1 = cs0; cs0 = 0; goto line; case cx_rrcurveto: code = t1_hinter__rcurveto(h, cs0, cs1, cs2, cs3, cs4, cs5); goto cc; case cx_endchar: code = t1_hinter__endchar(h, (pcis->seac_accent >= 0)); if (code < 0) return code; if (pcis->seac_accent < 0) { code = t1_hinter__endglyph(h); if (code < 0) return code; code = gx_setcurrentpoint_from_path(pcis->pis, pcis->path); if (code < 0) return code; } code = gs_type1_endchar(pcis); if (code == 1) { /* do accent of seac */ ipsp = &pcis->ipstack[pcis->ips_count - 1]; cip = ipsp->cs_data.bits.data; goto call; } return code; case cx_rmoveto: goto move; case cx_hmoveto: cs1 = 0; goto move; case cx_vhcurveto: code = t1_hinter__rcurveto(h, 0, cs0, cs1, cs2, cs3, 0); goto cc; case cx_hvcurveto: code = t1_hinter__rcurveto(h, cs0, 0, cs1, cs2, 0, cs3); goto cc; /* Commands only recognized in Type 1 charstrings, */ /* plus 'escape'. */ case c1_closepath: code = t1_hinter__closepath(h); goto cc; case c1_hsbw: if (!h->seac_flag) { fixed sbx = cs0, sby = fixed_0, wx = cs1, wy = fixed_0; if (pcis->sb_set) { sbx = pcis->lsb.x; sby = pcis->lsb.y; } if (pcis->width_set) { wx = pcis->width.x; wy = pcis->width.y; } code = t1_hinter__sbw(h, sbx, sby, wx, wy); } else code = t1_hinter__sbw_seac(h, pcis->adxy.x, pcis->adxy.y); if (code < 0) return code; gs_type1_sbw(pcis, cs0, fixed_0, cs1, fixed_0); cs1 = fixed_0; rsbw: /* Give the caller the opportunity to intervene. */ pcis->os_count = 0; /* clear */ ipsp->ip = cip, ipsp->dstate = state; pcis->ips_count = ipsp - &pcis->ipstack[0] + 1; /* If we aren't in a seac, do nothing else now; */ /* finish_init will take care of the rest. */ if (pcis->init_done < 0) { /* Finish init when we return. */ pcis->init_done = 0; } else { /* * Accumulate the side bearing now, but don't do it * a second time for the base character of a seac. */ if (pcis->seac_accent >= 0) { /* * As a special hack to work around a bug in * Fontographer, we deal with the (illegal) * situation in which the side bearing of the * accented character (save_lsbx) is different from * the side bearing of the base character (cs0/cs1). */ fixed dsbx = cs0 - pcis->save_lsb.x; fixed dsby = cs1 - pcis->save_lsb.y; if (dsbx | dsby) { pcis->lsb.x += dsbx; pcis->lsb.y += dsby; pcis->save_adxy.x -= dsbx; pcis->save_adxy.y -= dsby; } } } return type1_result_sbw; case cx_escape: charstring_next(*cip, state, c, encrypted); ++cip; #ifdef DEBUG if (gs_debug['1'] && c < char1_extended_command_count) { static const char *const ce1names[] = {char1_extended_command_names}; if (ce1names[c] == 0) dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c); else dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c, ce1names[c]); } #endif switch ((char1_extended_command) c) { case ce1_dotsection: code = t1_hinter__dotsection(h); if (code < 0) return code; cnext; case ce1_vstem3: code = t1_hinter__vstem3(h, cs0, cs1, cs2, cs3, cs4, cs5); if (code < 0) return code; cnext; case ce1_hstem3: code = t1_hinter__hstem3(h, cs0, cs1, cs2, cs3, cs4, cs5); if (code < 0) return code; cnext; case ce1_seac: code = gs_type1_seac(pcis, cstack + 1, cstack[0], ipsp); if (code != 0) { *pindex = ics3; return code; } clear; cip = ipsp->cs_data.bits.data; goto call; case ce1_sbw: if (!h->seac_flag) code = t1_hinter__sbw(h, cs0, cs1, cs2, cs3); else code = t1_hinter__sbw_seac(h, cs0 + pcis->adxy.x , cs1 + pcis->adxy.y); if (code < 0) return code; gs_type1_sbw(pcis, cs0, cs1, cs2, cs3); goto rsbw; case ce1_div: csp[-1] = float2fixed((double)csp[-1] / (double)*csp); --csp; goto pushed; case ce1_undoc15: /* See gstype1.h for information on this opcode. */ cnext; case ce1_callothersubr: { int num_results; /* We must remember to pop both the othersubr # */ /* and the argument count off the stack. */ switch (*pindex = fixed2int_var(*csp)) { case 0: { fixed fheight = csp[-4]; /* Assume the next two opcodes */ /* are `pop' `pop'. Unfortunately, some */ /* Monotype fonts put these in a Subr, */ /* so we can't just look ahead in the */ /* opcode stream. */ pcis->ignore_pops = 2; csp[-4] = csp[-3] - pcis->asb_diff; csp[-3] = csp[-2]; csp -= 3; code = t1_hinter__flex_end(h, fheight); } if (code < 0) return code; pcis->flex_count = flex_max; /* not inside flex */ inext; case 1: code = t1_hinter__flex_beg(h); if (code < 0) return code; pcis->flex_count = 1; csp -= 2; inext; case 2: if (pcis->flex_count >= flex_max) return_error(gs_error_invalidfont); code = t1_hinter__flex_point(h); if (code < 0) return code; csp -= 2; inext; case 3: /* Assume the next opcode is a `pop'. */ /* See above as to why we don't just */ /* look ahead in the opcode stream. */ pcis->ignore_pops = 1; code = t1_hinter__drop_hints(h); if (code < 0) return code; csp -= 2; inext; case 12: case 13: /* Counter control isn't implemented. */ cnext; case 14: num_results = 1; blend: code = gs_type1_blend(pcis, csp, num_results); if (code < 0) return code; csp -= code; inext; case 15: num_results = 2; goto blend; case 16: num_results = 3; goto blend; case 17: num_results = 4; goto blend; case 18: num_results = 6; goto blend; } } /* Not a recognized othersubr, */ /* let the client handle it. */ { int scount = csp - cstack; int n; /* Copy the arguments to the caller's stack. */ if (scount < 1 || csp[-1] < 0 || csp[-1] > int2fixed(scount - 1) ) return_error(gs_error_invalidfont); n = fixed2int_var(csp[-1]); code = (*pdata->procs.push_values) (pcis->callback_data, csp - (n + 1), n); if (code < 0) return_error(code); scount -= n + 1; /* Exit to caller */ ipsp->ip = cip, ipsp->dstate = state; pcis->os_count = scount; pcis->ips_count = ipsp - &pcis->ipstack[0] + 1; if (scount) memcpy(pcis->ostack, cstack, scount * sizeof(fixed)); return type1_result_callothersubr; } case ce1_pop: /* Check whether we're ignoring the pops after */ /* a known othersubr. */ if (pcis->ignore_pops != 0) { pcis->ignore_pops--; inext; } CS_CHECK_PUSH(csp, cstack); ++csp; code = (*pdata->procs.pop_value) (pcis->callback_data, csp); if (code < 0) return_error(code); goto pushed; case ce1_setcurrentpoint: t1_hinter__setcurrentpoint(h, cs0, cs1); cs0 += pcis->adxy.x; cs1 += pcis->adxy.y; cnext; default: return_error(gs_error_invalidfont); } /*NOTREACHED */ /* Fill up the dispatch up to 32. */ case_c1_undefs: default: /* pacify compiler */ return_error(gs_error_invalidfont); } } }
/* * Continue interpreting a Type 2 charstring. If str != 0, it is taken as * the byte string to interpret. Return 0 on successful completion, <0 on * error, or >0 when client intervention is required (or allowed). The int* * argument is only for compatibility with the Type 1 charstring interpreter. */ int gs_type2_interpret(gs_type1_state * pcis, const gs_glyph_data_t *pgd, int *ignore_pindex) { gs_font_type1 *pfont = pcis->pfont; gs_type1_data *pdata = &pfont->data; t1_hinter *h = &pcis->h; bool encrypted = pdata->lenIV >= 0; fixed cstack[ostack_size]; cs_ptr csp; #define clear CLEAR_CSTACK(cstack, csp) ip_state_t *ipsp = &pcis->ipstack[pcis->ips_count - 1]; register const byte *cip; register crypt_state state; register int c; cs_ptr ap; bool vertical; int code = 0; /****** FAKE THE REGISTRY ******/ struct { float *values; uint size; } Registry[1]; Registry[0].values = pcis->pfont->data.WeightVector.values; switch (pcis->init_done) { case -1: t1_hinter__init(h, pcis->path); break; case 0: gs_type1_finish_init(pcis); /* sets origin */ code = t1_hinter__set_mapping(h, &pcis->pis->ctm, &pfont->FontMatrix, &pfont->base->FontMatrix, pcis->scale.x.log2_unit, pcis->scale.x.log2_unit, pcis->scale.x.log2_unit - pcis->log2_subpixels.x, pcis->scale.y.log2_unit - pcis->log2_subpixels.y, pcis->origin.x, pcis->origin.y, gs_currentaligntopixels(pfont->dir)); if (code < 0) return code; code = t1_hinter__set_font_data(h, 2, pdata, pcis->no_grid_fitting, pcis->pfont->is_resource); if (code < 0) return code; break; default /*case 1 */ : break; } INIT_CSTACK(cstack, csp, pcis); if (pgd == 0) goto cont; ipsp->cs_data = *pgd; cip = pgd->bits.data; if (cip == 0) return (gs_note_error(gs_error_invalidfont)); call:state = crypt_charstring_seed; if (encrypted) { int skip = pdata->lenIV; /* Skip initial random bytes */ for (; skip > 0; ++cip, --skip) decrypt_skip_next(*cip, state); } goto top; cont:if (ipsp < pcis->ipstack || ipsp->ip == 0) return (gs_note_error(gs_error_invalidfont)); cip = ipsp->ip; state = ipsp->dstate; top:for (;;) { uint c0 = *cip++; charstring_next(c0, state, c, encrypted); if (c >= c_num1) { /* This is a number, decode it and push it on the stack. */ if (c < c_pos2_0) { /* 1-byte number */ decode_push_num1(csp, cstack, c); } else if (c < cx_num4) { /* 2-byte number */ decode_push_num2(csp, cstack, c, cip, state, encrypted); } else if (c == cx_num4) { /* 4-byte number */ long lw; decode_num4(lw, cip, state, encrypted); /* 32-bit numbers are 16:16. */ CS_CHECK_PUSH(csp, cstack); *++csp = arith_rshift(lw, 16 - _fixed_shift); } else /* not possible */ return_error(gs_error_invalidfont); pushed:if_debug3('1', "[1]%d: (%d) %f\n", (int)(csp - cstack), c, fixed2float(*csp)); continue; } #ifdef DEBUG if (gs_debug['1']) { static const char *const c2names[] = {char2_command_names}; if (c2names[c] == 0) dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c); else dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c, c2names[c]); } #endif switch ((char_command) c) { #define cnext clear; goto top /* Commands with identical functions in Type 1 and Type 2, */ /* except for 'escape'. */ case c_undef0: case c_undef2: case c_undef17: return_error(gs_error_invalidfont); case c_callsubr: c = fixed2int_var(*csp) + pdata->subroutineNumberBias; code = pdata->procs.subr_data (pfont, c, false, &ipsp[1].cs_data); subr:if (code < 0) { /* Calling a Subr with an out-of-range index is clearly a error: * the Adobe documentation says the results of doing this are * undefined. However, we have seen a PDF file produced by Adobe * PDF Library 4.16 that included a Type 2 font that called an * out-of-range Subr, and Acrobat Reader did not signal an error. * Therefore, we ignore such calls. */ cip++; goto top; } --csp; ipsp->ip = cip, ipsp->dstate = state; ++ipsp; cip = ipsp->cs_data.bits.data; goto call; case c_return: gs_glyph_data_free(&ipsp->cs_data, "gs_type2_interpret"); --ipsp; goto cont; case c_undoc15: /* See gstype1.h for information on this opcode. */ cnext; /* Commands with similar but not identical functions */ /* in Type 1 and Type 2 charstrings. */ case cx_hstem: goto hstem; case cx_vstem: goto vstem; case cx_vmoveto: check_first_operator(csp > cstack); code = t1_hinter__rmoveto(h, 0, *csp); move: cc: if (code < 0) return code; goto pp; case cx_rlineto: for (ap = cstack; ap + 1 <= csp; ap += 2) { code = t1_hinter__rlineto(h, ap[0], ap[1]); if (code < 0) return code; } pp: cnext; case cx_hlineto: vertical = false; goto hvl; case cx_vlineto: vertical = true; hvl:for (ap = cstack; ap <= csp; vertical = !vertical, ++ap) { if (vertical) { code = t1_hinter__rlineto(h, 0, ap[0]); } else { code = t1_hinter__rlineto(h, ap[0], 0); } if (code < 0) return code; } goto pp; case cx_rrcurveto: for (ap = cstack; ap + 5 <= csp; ap += 6) { code = t1_hinter__rcurveto(h, ap[0], ap[1], ap[2], ap[3], ap[4], ap[5]); if (code < 0) return code; } goto pp; case cx_endchar: /* * It is a feature of Type 2 CharStrings that if endchar is * invoked with 4 or 5 operands, it is equivalent to the * Type 1 seac operator. In this case, the asb operand of * seac is missing: we assume it is the same as the * l.s.b. of the accented character. This feature was * undocumented until the 16 March 2000 version of the Type * 2 Charstring Format specification, but, thankfully, is * described in that revision. */ if (csp >= cstack + 3) { check_first_operator(csp > cstack + 3); code = gs_type1_seac(pcis, cstack, 0, ipsp); if (code < 0) return code; clear; cip = ipsp->cs_data.bits.data; goto call; } /* * This might be the only operator in the charstring. * In this case, there might be a width on the stack. */ check_first_operator(csp >= cstack); if (pcis->seac_accent < 0) { code = t1_hinter__endglyph(h); if (code < 0) return code; code = gx_setcurrentpoint_from_path(pcis->pis, pcis->path); if (code < 0) return code; } else { t1_hinter__setcurrentpoint(h, pcis->save_adxy.x + pcis->origin_offset.x, pcis->save_adxy.y + pcis->origin_offset.y); code = t1_hinter__end_subglyph(h); if (code < 0) return code; } code = gs_type1_endchar(pcis); if (code == 1) { /* * Reset the total hint count so that hintmask will * parse its following data correctly. * (gs_type1_endchar already reset the actual hint * tables.) */ pcis->num_hints = 0; /* do accent of seac */ ipsp = &pcis->ipstack[pcis->ips_count - 1]; cip = ipsp->cs_data.bits.data; goto call; } return code; case cx_rmoveto: /* See vmoveto above re closing the subpath. */ check_first_operator(!((csp - cstack) & 1)); if (csp > cstack + 1) { /* Some Type 2 charstrings omit the vstemhm operator before rmoveto, even though this is only allowed before hintmask and cntrmask. Thanks to Felix Pahl. */ type2_vstem(pcis, csp - 2, cstack); cstack [0] = csp [-1]; cstack [1] = csp [ 0]; csp = cstack + 1; } code = t1_hinter__rmoveto(h, csp[-1], *csp); goto move; case cx_hmoveto: /* See vmoveto above re closing the subpath. */ check_first_operator(csp > cstack); code = t1_hinter__rmoveto(h, *csp, 0); goto move; case cx_vhcurveto: vertical = true; goto hvc; case cx_hvcurveto: vertical = false; hvc:for (ap = cstack; ap + 3 <= csp; vertical = !vertical, ap += 4) { gs_fixed_point pt[2] = {{0, 0}, {0, 0}}; if (vertical) { pt[0].y = ap[0]; pt[1].x = ap[3]; if (ap + 4 == csp) pt[1].y = ap[4]; } else { pt[0].x = ap[0]; if (ap + 4 == csp) pt[1].x = ap[4]; pt[1].y = ap[3]; } code = t1_hinter__rcurveto(h, pt[0].x, pt[0].y, ap[1], ap[2], pt[1].x, pt[1].y); if (code < 0) return code; } goto pp; /*********************** * New Type 2 commands * ***********************/ case c2_blend: { int n = fixed2int_var(*csp); int num_values = csp - cstack; gs_font_type1 *pfont = pcis->pfont; int k = pfont->data.WeightVector.count; int i, j; cs_ptr base, deltas; base = csp - 1 - num_values; deltas = base + n - 1; for (j = 0; j < n; j++, base++, deltas += k - 1) for (i = 1; i < k; i++) *base += (fixed)(deltas[i] * pfont->data.WeightVector.values[i]); } cnext; case c2_hstemhm: hstem:check_first_operator(!((csp - cstack) & 1)); { fixed x = 0; for (ap = cstack; ap + 1 <= csp; x += ap[1], ap += 2) { code = t1_hinter__hstem(h, x += ap[0], ap[1]); if (code < 0) return code; } } pcis->num_hints += (csp + 1 - cstack) >> 1; cnext; case c2_hintmask: /* * A hintmask at the beginning of the CharString is * equivalent to vstemhm + hintmask. For simplicity, we use * this interpretation everywhere. */ case c2_cntrmask: check_first_operator(!((csp - cstack) & 1)); type2_vstem(pcis, csp, cstack); /* * We should clear the stack here only if this is the * initial mask operator that includes the implicit * vstemhm, but currently this is too much trouble to * detect. */ clear; { byte mask[max_total_stem_hints / 8]; int i; for (i = 0; i < pcis->num_hints; ++cip, i += 8) { charstring_next(*cip, state, mask[i >> 3], encrypted); if_debug1('1', " 0x%02x", mask[i >> 3]); } if_debug0('1', "\n"); ipsp->ip = cip; ipsp->dstate = state; if (c == c2_cntrmask) { /****** NYI ******/ } else { /* hintmask or equivalent */ if_debug0('1', "[1]hstem hints:\n"); if_debug0('1', "[1]vstem hints:\n"); code = t1_hinter__hint_mask(h, mask); if (code < 0) return code; } } break; case c2_vstemhm: vstem:check_first_operator(!((csp - cstack) & 1)); type2_vstem(pcis, csp, cstack); cnext; case c2_rcurveline: for (ap = cstack; ap + 5 <= csp; ap += 6) { code = t1_hinter__rcurveto(h, ap[0], ap[1], ap[2], ap[3], ap[4], ap[5]); if (code < 0) return code; } code = t1_hinter__rlineto(h, ap[0], ap[1]); goto cc; case c2_rlinecurve: for (ap = cstack; ap + 7 <= csp; ap += 2) { code = t1_hinter__rlineto(h, ap[0], ap[1]); if (code < 0) return code; } code = t1_hinter__rcurveto(h, ap[0], ap[1], ap[2], ap[3], ap[4], ap[5]); goto cc; case c2_vvcurveto: ap = cstack; { int n = csp + 1 - cstack; fixed dxa = (n & 1 ? *ap++ : 0); for (; ap + 3 <= csp; ap += 4) { code = t1_hinter__rcurveto(h, dxa, ap[0], ap[1], ap[2], fixed_0, ap[3]); if (code < 0) return code; dxa = 0; } } goto pp; case c2_hhcurveto: ap = cstack; { int n = csp + 1 - cstack; fixed dya = (n & 1 ? *ap++ : 0); for (; ap + 3 <= csp; ap += 4) { code = t1_hinter__rcurveto(h, ap[0], dya, ap[1], ap[2], ap[3], fixed_0); if (code < 0) return code; dya = 0; } } goto pp; case c2_shortint: { int c1, c2; charstring_next(*cip, state, c1, encrypted); ++cip; charstring_next(*cip, state, c2, encrypted); ++cip; CS_CHECK_PUSH(csp, cstack); *++csp = int2fixed((((c1 ^ 0x80) - 0x80) << 8) + c2); } goto pushed; case c2_callgsubr: c = fixed2int_var(*csp) + pdata->gsubrNumberBias; code = pdata->procs.subr_data (pfont, c, true, &ipsp[1].cs_data); goto subr; case cx_escape: charstring_next(*cip, state, c, encrypted); ++cip; #ifdef DEBUG if (gs_debug['1'] && c < char2_extended_command_count) { static const char *const ce2names[] = {char2_extended_command_names}; if (ce2names[c] == 0) dlprintf2("[1]0x%lx: %02x??\n", (ulong) (cip - 1), c); else dlprintf3("[1]0x%lx: %02x %s\n", (ulong) (cip - 1), c, ce2names[c]); } #endif switch ((char2_extended_command) c) { case ce2_and: csp[-1] = ((csp[-1] != 0) & (*csp != 0) ? fixed_1 : 0); --csp; break; case ce2_or: csp[-1] = (csp[-1] | *csp ? fixed_1 : 0); --csp; break; case ce2_not: *csp = (*csp ? 0 : fixed_1); break; case ce2_store: { int i, n = fixed2int_var(*csp); float *to = Registry[fixed2int_var(csp[-3])].values + fixed2int_var(csp[-2]); const fixed *from = pcis->transient_array + fixed2int_var(csp[-1]); for (i = 0; i < n; ++i) to[i] = fixed2float(from[i]); } csp -= 4; break; case ce2_abs: if (*csp < 0) *csp = -*csp; break; case ce2_add: csp[-1] += *csp; --csp; break; case ce2_sub: csp[-1] -= *csp; --csp; break; case ce2_div: csp[-1] = float2fixed((double)csp[-1] / *csp); --csp; break; case ce2_load: /* The specification says there is no j (starting index */ /* in registry array) argument.... */ { int i, n = fixed2int_var(*csp); const float *from = Registry[fixed2int_var(csp[-2])].values; fixed *to = pcis->transient_array + fixed2int_var(csp[-1]); for (i = 0; i < n; ++i) to[i] = float2fixed(from[i]); } csp -= 3; break; case ce2_neg: *csp = -*csp; break; case ce2_eq: csp[-1] = (csp[-1] == *csp ? fixed_1 : 0); --csp; break; case ce2_drop: --csp; break; case ce2_put: pcis->transient_array[fixed2int_var(*csp)] = csp[-1]; csp -= 2; break; case ce2_get: *csp = pcis->transient_array[fixed2int_var(*csp)]; break; case ce2_ifelse: if (csp[-1] > *csp) csp[-3] = csp[-2]; csp -= 3; break; case ce2_random: CS_CHECK_PUSH(csp, cstack); ++csp; /****** NYI ******/ break; case ce2_mul: { double prod = fixed2float(csp[-1]) * *csp; csp[-1] = (prod > max_fixed ? max_fixed : prod < min_fixed ? min_fixed : (fixed)prod); } --csp; break; case ce2_sqrt: if (*csp >= 0) *csp = float2fixed(sqrt(fixed2float(*csp))); break; case ce2_dup: CS_CHECK_PUSH(csp, cstack); csp[1] = *csp; ++csp; break; case ce2_exch: { fixed top = *csp; *csp = csp[-1], csp[-1] = top; } break; case ce2_index: *csp = (*csp < 0 ? csp[-1] : csp[-1 - fixed2int_var(csp[-1])]); break; case ce2_roll: { int distance = fixed2int_var(*csp); int count = fixed2int_var(csp[-1]); cs_ptr bot; csp -= 2; if (count < 0 || count > csp + 1 - cstack) return_error(gs_error_invalidfont); if (count == 0) break; if (distance < 0) distance = count - (-distance % count); bot = csp + 1 - count; while (--distance >= 0) { fixed top = *csp; memmove(bot + 1, bot, (count - 1) * sizeof(fixed)); *bot = top; } } break; case ce2_hflex: csp[6] = fixed_half; /* fd/100 */ csp[4] = *csp, csp[5] = 0; /* dx6, dy6 */ csp[2] = csp[-1], csp[3] = -csp[-4]; /* dx5, dy5 */ *csp = csp[-2], csp[1] = 0; /* dx4, dy4 */ csp[-2] = csp[-3], csp[-1] = 0; /* dx3, dy3 */ csp[-3] = csp[-4], csp[-4] = csp[-5]; /* dx2, dy2 */ csp[-5] = 0; /* dy1 */ csp += 6; goto flex; case ce2_flex: *csp /= 100; /* fd/100 */ flex: { fixed x_join = csp[-12] + csp[-10] + csp[-8]; fixed y_join = csp[-11] + csp[-9] + csp[-7]; fixed x_end = x_join + csp[-6] + csp[-4] + csp[-2]; fixed y_end = y_join + csp[-5] + csp[-3] + csp[-1]; gs_point join, end; double flex_depth; if ((code = gs_distance_transform(fixed2float(x_join), fixed2float(y_join), &ctm_only(pcis->pis), &join)) < 0 || (code = gs_distance_transform(fixed2float(x_end), fixed2float(y_end), &ctm_only(pcis->pis), &end)) < 0 ) return code; /* * Use the X or Y distance depending on whether * the curve is more horizontal or more * vertical. */ if (any_abs(end.y) > any_abs(end.x)) flex_depth = join.x; else flex_depth = join.y; if (fabs(flex_depth) < fixed2float(*csp)) { /* Do flex as line. */ code = t1_hinter__rlineto(h, x_end, y_end); } else { /* * Do flex as curve. We can't jump to rrc, * because the flex operators don't clear * the stack (!). */ code = t1_hinter__rcurveto(h, csp[-12], csp[-11], csp[-10], csp[-9], csp[-8], csp[-7]); if (code < 0) return code; code = t1_hinter__rcurveto(h, csp[-6], csp[-5], csp[-4], csp[-3], csp[-2], csp[-1]); } if (code < 0) return code; csp -= 13; } cnext; case ce2_hflex1: csp[4] = fixed_half; /* fd/100 */ csp[2] = *csp; /* dx6 */ csp[3] = -(csp[-7] + csp[-5] + csp[-1]); /* dy6 */ *csp = csp[-2], csp[1] = csp[-1]; /* dx5, dy5 */ csp[-2] = csp[-3], csp[-1] = 0; /* dx4, dy4 */ csp[-3] = 0; /* dy3 */ csp += 4; goto flex; case ce2_flex1: { fixed dx = csp[-10] + csp[-8] + csp[-6] + csp[-4] + csp[-2]; fixed dy = csp[-9] + csp[-7] + csp[-5] + csp[-3] + csp[-1]; if (any_abs(dx) > any_abs(dy)) csp[1] = -dy; /* d6 is dx6 */ else csp[1] = *csp, *csp = -dx; /* d6 is dy6 */ } csp[2] = fixed_half; /* fd/100 */ csp += 2; goto flex; } break; /* Fill up the dispatch up to 32. */ case_c2_undefs: default: /* pacify compiler */ return_error(gs_error_invalidfont); } } }