int charstring_execchar(i_ctx_t *i_ctx_p, int font_type_mask) { gs_text_enum_t *penum = op_show_find(i_ctx_p); gs_font *pfont; os_ptr op = osp; int code = font_param(op - 3, &pfont); if (code < 0) return code; if (penum == 0 || pfont->FontType >= sizeof(font_type_mask) * 8 || !(font_type_mask & (1 << (int)pfont->FontType))) return_error(e_undefined); code = charstring_execchar_aux(i_ctx_p, penum, pfont); if (code < 0 && igs->in_cachedevice == CACHE_DEVICE_CACHING) { /* Perform the cache cleanup, when the cached character data has been allocated (gx_alloc_char_bits) but the character has not been added to the cache (gx_add_cached_char) due to a falure in the character renderer. */ gs_show_enum *const penum_s = (gs_show_enum *)penum; if (penum_s->cc != NULL) { gx_free_cached_char(pfont->dir, penum_s->cc); penum_s->cc = NULL; } } return code; }
/* Get the calling operator for error reporting in %Type32BuildGlyph */ static int zgetshowoperator(i_ctx_t *i_ctx_p) { os_ptr op = osp; gs_text_enum_t *osenum = op_show_find(i_ctx_p); push(1); if (osenum == NULL) make_null(op); else { op_proc_t proc; *(void **)&proc = osenum->enum_client_data; make_oper(op, 0, proc); } return 0; }
/* <wx> <wy> setcharwidth - */ static int zsetcharwidth(i_ctx_t *i_ctx_p) { os_ptr op = osp; double width[2]; gs_text_enum_t *penum = op_show_find(i_ctx_p); int code = num_params(op, 2, width); if (penum == 0) return_error(e_undefined); if (code < 0) return code; if (zchar_show_width_only(penum)) return op_show_return_width(i_ctx_p, 2, &width[0]); code = gs_text_setcharwidth(penum, width); if (code < 0) return code; pop(2); return 0; }
/* <wx> <wy> <llx> <lly> <urx> <ury> setcachedevice - */ int zsetcachedevice(i_ctx_t *i_ctx_p) { os_ptr op = osp; double wbox[6]; gs_text_enum_t *penum = op_show_find(i_ctx_p); int code = num_params(op, 6, wbox); if (penum == 0) return_error(e_undefined); if (code < 0) return code; if (zchar_show_width_only(penum)) return op_show_return_width(i_ctx_p, 6, &wbox[0]); code = gs_text_setcachedevice(penum, wbox); if (code < 0) return code; pop(6); if (code == 1) clear_pagedevice(istate); return 0; }
/* <w0x> <w0y> <llx> <lly> <urx> <ury> <w1x> <w1y> <vx> <vy> setcachedevice2 - */ int zsetcachedevice2(i_ctx_t *i_ctx_p) { os_ptr op = osp; double wbox[10]; gs_text_enum_t *penum = op_show_find(i_ctx_p); int code = num_params(op, 10, wbox); if (penum == 0) return_error(e_undefined); if (code < 0) return code; if (zchar_show_width_only(penum)) return op_show_return_width(i_ctx_p, 10, (gs_rootfont(igs)->WMode ? &wbox[6] : &wbox[0])); code = gs_text_setcachedevice2(penum, wbox); if (code < 0) return code; pop(10); if (code == 1) clear_pagedevice(istate); return 0; }
/* Finish setting up a text operator. */ int op_show_finish_setup(i_ctx_t *i_ctx_p, gs_text_enum_t * penum, int npop, op_proc_t endproc /* end procedure */ ) { gs_text_enum_t *osenum = op_show_find(i_ctx_p); es_ptr ep = esp + snumpush; gs_glyph glyph; if (gs_currentcpsimode(igs->memory)) { /* CET 14-03.PS page 2 emits rangecheck before rendering a character. Early check the text to font compatibility with decomposing the text into characters.*/ int code = gs_text_count_chars(igs, gs_get_text_params(penum), imemory); if (code < 0) return code; } /* * If we are in the procedure of a cshow for a CID font and this is * a show operator, do something special, per the Red Book. */ if (osenum && SHOW_IS_ALL_OF(osenum, TEXT_FROM_STRING | TEXT_DO_NONE | TEXT_INTERVENE) && SHOW_IS_ALL_OF(penum, TEXT_FROM_STRING | TEXT_RETURN_WIDTH) && (glyph = gs_text_current_glyph(osenum)) != gs_no_glyph && glyph >= gs_min_cid_glyph && /* According to PLRM, we don't need to raise a rangecheck error, if currentfont is changed in the proc of the operator 'cshow'. */ gs_default_same_font (gs_text_current_font(osenum), gs_text_current_font(penum), true) ) { gs_text_params_t text; if (!(penum->text.size == 1 && penum->text.data.bytes[0] == (gs_text_current_char(osenum) & 0xff)) ) return_error(e_rangecheck); text = penum->text; text.operation = (text.operation & ~(TEXT_FROM_STRING | TEXT_FROM_BYTES | TEXT_FROM_CHARS | TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_CHAR)) | TEXT_FROM_SINGLE_GLYPH; text.data.d_glyph = glyph; text.size = 1; gs_text_restart(penum, &text); } if (osenum && osenum->current_font->FontType == ft_user_defined && osenum->orig_font->FontType == ft_composite && ((const gs_font_type0 *)osenum->orig_font)->data.FMapType == fmap_CMap) { /* A special behavior defined in PLRM3 section 5.11 page 389. */ penum->outer_CID = osenum->returned.current_glyph; } if (osenum == NULL && !(penum->text.operation & (TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_GLYPH))) { int ft = igs->root_font->FontType; if ((ft >= ft_CID_encrypted && ft <= ft_CID_TrueType) || ft == ft_CID_bitmap) return_error(e_typecheck); } make_mark_estack(ep - (snumpush - 1), es_show, op_show_cleanup); if (endproc == NULL) endproc = finish_show; make_null(&esslot(ep)); make_int(&esodepth(ep), ref_stack_count_inline(&o_stack) - npop); /* Save stack depth for */ make_int(&esddepth(ep), ref_stack_count_inline(&d_stack)); /* correct interrupt processing */ make_int(&esgslevel(ep), igs->level); make_null(&essfont(ep)); make_null(&esrfont(ep)); make_op_estack(&eseproc(ep), endproc); make_istruct(ep, 0, penum); esp = ep; return 0; }
/* * Consult Metrics2 and CDevProc, and call setcachedevice[2]. Return * o_push_estack if we had to call a CDevProc, or if we are skipping the * rendering process (only getting the metrics). * Returns exec_cont - a function, which must be called by caller after this function. */ int zchar_set_cache(i_ctx_t *i_ctx_p, const gs_font_base * pbfont, const ref * pcnref, const double psb[2], const double pwidth[2], const gs_rect * pbbox, op_proc_t cont, op_proc_t *exec_cont, const double Metrics2_sbw_default[4]) { os_ptr op = osp; ref *pcdevproc, *valueref; int have_cdevproc; ref rpop; ref cid, *cidptr; bool metrics2; bool metrics2_use_default = false; double w2[10]; gs_text_enum_t *penum = op_show_find(i_ctx_p); w2[0] = pwidth[0], w2[1] = pwidth[1]; /* Adjust the bounding box for stroking if needed. */ w2[2] = pbbox->p.x, w2[3] = pbbox->p.y; w2[4] = pbbox->q.x, w2[5] = pbbox->q.y; if (pbfont->PaintType != 0) { double expand = max(1.415, gs_currentmiterlimit(igs)) * gs_currentlinewidth(igs) / 2; w2[2] -= expand, w2[3] -= expand; w2[4] += expand, w2[5] += expand; } /* Check for Metrics2. */ { int code = zchar_get_metrics2(pbfont, pcnref, w2 + 6); if (code < 0) return code; metrics2 = code > 0; } /* * For FontType 9 and 11, if Metrics2 is missing, the caller provides * default Metrics2 values derived from the FontBBox. */ if (!metrics2 && Metrics2_sbw_default != NULL) { w2[6] = Metrics2_sbw_default[2]; w2[7] = Metrics2_sbw_default[3]; w2[8] = Metrics2_sbw_default[0]; w2[9] = Metrics2_sbw_default[1]; metrics2 = true; metrics2_use_default = true; } /* Check for CDevProc or "short-circuiting". */ have_cdevproc = zchar_get_CDevProc(pbfont, &pcdevproc); /* Obscure test. The CDevProc is supposed to be called with the original CID but what we get passed * here is the TT GID. So the CDevProc won't do the right thing. We need to extract the CID from the * enumerator, and use that instead. */ cidptr = (ref *)pcnref; if (pbfont->FontType == ft_CID_TrueType && dict_find_string(&pfont_data(gs_font_parent(pbfont))->dict, "File", &valueref) > 0) { if (pbfont->key_name.size != pbfont->font_name.size || strncmp((const char *)pbfont->key_name.chars, (const char *)pbfont->font_name.chars, pbfont->key_name.size)) { if (penum->returned.current_glyph >= GS_MIN_CID_GLYPH) { make_int(&cid, penum->returned.current_glyph - GS_MIN_CID_GLYPH); } else { make_int(&cid, penum->returned.current_glyph); } cidptr = &cid; } } if (have_cdevproc || zchar_show_width_only(penum)) { int i; op_proc_t zsetc; int nparams; if (have_cdevproc) { check_proc_only(*pcdevproc); zsetc = zsetcachedevice2; /* If we have cdevproc and the font type is CID type 0, we'll throw away Metrics2_sbw_default that is calculated from FontBBox. */ if (!metrics2 || (penum->current_font->FontType == ft_CID_encrypted && metrics2_use_default)) { w2[6] = w2[0], w2[7] = w2[1]; w2[8] = w2[9] = 0; } nparams = 10; } else { make_oper(&rpop, 0, zpop); pcdevproc = &rpop; if (metrics2) zsetc = zsetcachedevice2, nparams = 10; else zsetc = zsetcachedevice, nparams = 6; } check_estack(3); /* Push the l.s.b. for .type1addpath if necessary. */ if (psb != 0) { push(nparams + 3); make_real(op - (nparams + 2), psb[0]); make_real(op - (nparams + 1), psb[1]); } else { push(nparams + 1); } for (i = 0; i < nparams; ++i) make_real(op - nparams + i, w2[i]); ref_assign(op, cidptr); push_op_estack(cont); push_op_estack(zsetc); ++esp; ref_assign(esp, pcdevproc); return o_push_estack; } { int code = (metrics2 ? gs_text_setcachedevice2(penum, w2) : gs_text_setcachedevice(penum, w2)); if (code < 0) return code; } /* No metrics modification, do the stroke or fill now. */ /* Push the l.s.b. for .type1addpath if necessary. */ if (psb != 0) { push(2); make_real(op - 1, psb[0]); make_real(op, psb[1]); } *exec_cont = cont; return 0; }
/* * Consult Metrics2 and CDevProc, and call setcachedevice[2]. Return * o_push_estack if we had to call a CDevProc, or if we are skipping the * rendering process (only getting the metrics). */ int zchar_set_cache(os_ptr op, const gs_font_base *pbfont, const ref *pcnref, const float psb[2], const float pwidth[2], const gs_rect *pbbox, int (*cont_fill)(P1(os_ptr)), int (*cont_stroke)(P1(os_ptr))) { const ref *pfdict = &pfont_data(pbfont)->dict; ref *pmdict; ref *pcdevproc; int have_cdevproc; ref rpop; bool metrics2 = false; int (*cont)(P1(os_ptr)); float w2[10]; gs_show_enum *penum = op_show_find(); w2[0] = pwidth[0], w2[1] = pwidth[1]; /* Adjust the bounding box for stroking if needed. */ w2[2] = pbbox->p.x, w2[3] = pbbox->p.y; w2[4] = pbbox->q.x, w2[5] = pbbox->q.y; if ( pbfont->PaintType == 0 ) cont = cont_fill; else { double expand = max(1.415, gs_currentmiterlimit(igs)) * gs_currentlinewidth(igs) / 2; w2[2] -= expand, w2[3] -= expand; w2[4] += expand, w2[5] += expand; cont = cont_stroke; } /* Check for Metrics2. */ if ( dict_find_string(pfdict, "Metrics2", &pmdict) > 0 ) { ref *pmvalue; check_type_only(*pmdict, t_dictionary); check_dict_read(*pmdict); if ( dict_find(pmdict, pcnref, &pmvalue) > 0 ) { check_read_type_only(*pmvalue, t_array); if ( r_size(pmvalue) == 4 ) { int code = num_params(pmvalue->value.refs + 3, 4, w2 + 6); if ( code < 0 ) return code; metrics2 = true; } } } /* Check for CDevProc or "short-circuiting". */ have_cdevproc = dict_find_string(pfdict, "CDevProc", &pcdevproc) > 0; if ( have_cdevproc || gs_show_width_only(penum) ) { int i; int (*zsetc)(P1(os_ptr)); int nparams; if ( have_cdevproc ) { check_proc_only(*pcdevproc); zsetc = zsetcachedevice2; if ( !metrics2 ) { w2[6] = w2[0], w2[7] = w2[1]; w2[8] = w2[9] = 0; } nparams = 10; } else { make_oper(&rpop, 0, zpop); pcdevproc = &rpop; if ( metrics2 ) zsetc = zsetcachedevice2, nparams = 10; else zsetc = zsetcachedevice, nparams = 6; } check_estack(3); /* Push the l.s.b. for .type1addpath if necessary. */ if ( psb != 0 ) { push(nparams + 3); make_real(op - (nparams + 2), psb[0]); make_real(op - (nparams + 1), psb[1]); } else { push(nparams + 1); } for ( i = 0; i < nparams; ++i ) make_real(op - nparams + i, w2[i]); ref_assign(op, pcnref); push_op_estack(cont); push_op_estack(zsetc); ++esp; ref_assign(esp, pcdevproc); return o_push_estack; } { int code = (metrics2 ? gs_setcachedevice2(penum, igs, w2) : gs_setcachedevice(penum, igs, w2)); if ( code < 0 ) return code; } /* No metrics modification, do the stroke or fill now. */ /* Push the l.s.b. for .type1addpath if necessary. */ if ( psb != 0 ) { push(2); make_real(op - 1, psb[0]); make_real(op, psb[1]); } return cont(op); }
/* * Check the path against FontBBox before drawing. The original operands * of type1execchar are still on the o-stack. * Returns exec_cont - a function, which must be called by caller after this function. */ static int bbox_draw(i_ctx_t *i_ctx_p, int (*draw)(gs_state *), op_proc_t *exec_cont) { os_ptr op = osp; gs_rect bbox; gs_font *pfont; gs_text_enum_t *penum; gs_font_base * pbfont; gs_font_type1 * pfont1; gs_type1exec_state cxs; int code; if (igs->in_cachedevice < 2) /* not caching */ return nobbox_draw(i_ctx_p, draw); if ((code = font_param(op - 3, &pfont)) < 0) return code; penum = op_show_find(i_ctx_p); if (penum == 0 || !font_uses_charstrings(pfont)) return_error(e_undefined); if ((code = gs_pathbbox(igs, &bbox)) < 0) { /* * If the matrix is singular, all user coordinates map onto a * straight line. Don't bother rendering the character at all. */ if (code == e_undefinedresult) { pop(4); gs_newpath(igs); return 0; } return code; } if (draw == gs_stroke) { /* Expand the bounding box by the line width. */ float width = gs_currentlinewidth(igs) * 1.41422; bbox.p.x -= width, bbox.p.y -= width; bbox.q.x += width, bbox.q.y += width; } pbfont = (gs_font_base *)pfont; if (rect_within(bbox, pbfont->FontBBox)) /* within bounds */ return nobbox_draw(i_ctx_p, draw); /* Enlarge the FontBBox to save work in the future. */ rect_merge(pbfont->FontBBox, bbox); /* Dismantle everything we've done, and start over. */ gs_text_retry(penum); pfont1 = (gs_font_type1 *) pfont; if ((penum->FontBBox_as_Metrics2.x == 0 && penum->FontBBox_as_Metrics2.y == 0) || gs_rootfont(igs)->WMode == 0 ) { code = zchar_get_metrics(pbfont, op - 1, cxs.sbw); if (code < 0) return code; cxs.present = code; cxs.use_FontBBox_as_Metrics2 = false; } else { cxs.sbw[0] = penum->FontBBox_as_Metrics2.x / 2; cxs.sbw[1] = penum->FontBBox_as_Metrics2.y; cxs.sbw[2] = 0; cxs.sbw[3] = -penum->FontBBox_as_Metrics2.x; /* Sic! */ cxs.use_FontBBox_as_Metrics2 = true; cxs.present = metricsSideBearingAndWidth; } code = type1_exec_init(&cxs.cis, penum, igs, pfont1); if (code < 0) return code; cxs.char_bbox = pfont1->FontBBox; code = type1exec_bbox(i_ctx_p, penum, &cxs, pfont, exec_cont); return code; }
static int bbox_finish(i_ctx_t *i_ctx_p, op_proc_t cont, op_proc_t *exec_cont) { /* Returns exec_cont - a function, which must be called by caller after this function. */ os_ptr op = osp; gs_font *pfont; int code; gs_text_enum_t *penum = op_show_find(i_ctx_p); gs_type1exec_state cxs; /* stack allocate to avoid sandbars */ gs_type1_state *const pcis = &cxs.cis; double sbxy[2]; gs_point sbpt; gs_point *psbpt = 0; os_ptr opc = op; const ref *opstr; ref other_subr; if (!r_has_type(opc, t_string)) { check_op(3); code = num_params(op, 2, sbxy); if (code < 0) return code; sbpt.x = sbxy[0]; sbpt.y = sbxy[1]; psbpt = &sbpt; opc -= 2; check_type(*opc, t_string); } code = font_param(opc - 3, &pfont); if (code < 0) return code; if (penum == 0 || !font_uses_charstrings(pfont)) return_error(e_undefined); { gs_font_type1 *const pfont1 = (gs_font_type1 *) pfont; int lenIV = pfont1->data.lenIV; if (lenIV > 0 && r_size(opc) <= lenIV) return_error(e_invalidfont); check_estack(5); /* in case we need to do a callout */ code = type1_exec_init(pcis, penum, igs, pfont1); if (code < 0) return code; if (psbpt) gs_type1_set_lsb(pcis, psbpt); } opstr = opc; icont: code = type1_continue_dispatch(i_ctx_p, &cxs, opstr, &other_subr, (psbpt ? 6 : 4)); op = osp; /* OtherSubrs might have altered it */ switch (code) { case 0: /* all done */ /* Call the continuation now. */ if (psbpt) pop(2); *exec_cont = cont; return 0; case type1_result_callothersubr: /* unknown OtherSubr */ push_op_estack(cont); /* call later */ return type1_call_OtherSubr(i_ctx_p, &cxs, bbox_continue, &other_subr); case type1_result_sbw: /* [h]sbw, just continue */ opstr = 0; goto icont; default: /* code < 0, error */ return code; } }
/* * Consult Metrics2 and CDevProc, and call setcachedevice[2]. Return * o_push_estack if we had to call a CDevProc, or if we are skipping the * rendering process (only getting the metrics). * Returns exec_cont - a function, which must be called by caller after this function. */ int zchar_set_cache(i_ctx_t *i_ctx_p, const gs_font_base * pbfont, const ref * pcnref, const double psb[2], const double pwidth[2], const gs_rect * pbbox, op_proc_t cont, op_proc_t *exec_cont, const double Metrics2_sbw_default[4]) { os_ptr op = osp; ref *pcdevproc; int have_cdevproc; ref rpop; bool metrics2; bool metrics2_use_default = false; double w2[10]; gs_text_enum_t *penum = op_show_find(i_ctx_p); w2[0] = pwidth[0], w2[1] = pwidth[1]; /* Adjust the bounding box for stroking if needed. */ w2[2] = pbbox->p.x, w2[3] = pbbox->p.y; w2[4] = pbbox->q.x, w2[5] = pbbox->q.y; if (pbfont->PaintType != 0) { double expand = max(1.415, gs_currentmiterlimit(igs)) * gs_currentlinewidth(igs) / 2; w2[2] -= expand, w2[3] -= expand; w2[4] += expand, w2[5] += expand; } /* Check for Metrics2. */ { int code = zchar_get_metrics2(pbfont, pcnref, w2 + 6); if (code < 0) return code; metrics2 = code > 0; } /* * For FontType 9 and 11, if Metrics2 is missing, the caller provides * default Metrics2 values derived from the FontBBox. */ if (!metrics2 && Metrics2_sbw_default != NULL) { w2[6] = Metrics2_sbw_default[2]; w2[7] = Metrics2_sbw_default[3]; w2[8] = Metrics2_sbw_default[0]; w2[9] = Metrics2_sbw_default[1]; metrics2 = true; metrics2_use_default = true; } /* Check for CDevProc or "short-circuiting". */ have_cdevproc = zchar_get_CDevProc(pbfont, &pcdevproc); if (have_cdevproc || zchar_show_width_only(penum)) { int i; op_proc_t zsetc; int nparams; if (have_cdevproc) { check_proc_only(*pcdevproc); zsetc = zsetcachedevice2; /* If we have cdevproc and the font type is CID type 0, we'll throw away Metrics2_sbw_default that is calculated from FontBBox. */ if (!metrics2 || (penum->current_font->FontType == ft_CID_encrypted && metrics2_use_default)) { w2[6] = w2[0], w2[7] = w2[1]; w2[8] = w2[9] = 0; } nparams = 10; } else { make_oper(&rpop, 0, zpop); pcdevproc = &rpop; if (metrics2) zsetc = zsetcachedevice2, nparams = 10; else zsetc = zsetcachedevice, nparams = 6; } check_estack(3); /* Push the l.s.b. for .type1addpath if necessary. */ if (psb != 0) { push(nparams + 3); make_real(op - (nparams + 2), psb[0]); make_real(op - (nparams + 1), psb[1]); } else { push(nparams + 1); } for (i = 0; i < nparams; ++i) make_real(op - nparams + i, w2[i]); ref_assign(op, pcnref); push_op_estack(cont); push_op_estack(zsetc); ++esp; ref_assign(esp, pcdevproc); return o_push_estack; } { int code = (metrics2 ? gs_text_setcachedevice2(penum, w2) : gs_text_setcachedevice(penum, w2)); if (code < 0) return code; } /* No metrics modification, do the stroke or fill now. */ /* Push the l.s.b. for .type1addpath if necessary. */ if (psb != 0) { push(2); make_real(op - 1, psb[0]); make_real(op, psb[1]); } *exec_cont = cont; return 0; }