/* Get a Type 42 character metrics and set the cache device. */ int zchar42_set_cache(i_ctx_t *i_ctx_p, gs_font_base *pbfont, ref *cnref, uint glyph_index, op_proc_t cont, op_proc_t *exec_cont, bool put_lsb) { double sbw[4]; double w[2]; int present; int code = zchar_get_metrics(pbfont, cnref, sbw); if (code < 0) return code; present = code; if (present == metricsNone) { float sbw42[4]; int i; code = gs_type42_wmode_metrics((gs_font_type42 *)pbfont, glyph_index, false, sbw42); if (code < 0) return code; present = metricsSideBearingAndWidth; for (i = 0; i < 4; ++i) sbw[i] = sbw42[i]; w[0] = sbw[2]; w[1] = sbw[3]; if (gs_rootfont(igs)->WMode) { /* for vertically-oriented metrics */ code = gs_type42_wmode_metrics((gs_font_type42 *)pbfont, glyph_index, true, sbw42); if (code < 0) { /* no vertical metrics */ if (pbfont->FontType == ft_CID_TrueType) { sbw[0] = sbw[2] / 2; sbw[1] = pbfont->FontBBox.q.y; sbw[2] = 0; sbw[3] = pbfont->FontBBox.p.y - pbfont->FontBBox.q.y; } } else { sbw[0] = sbw[2] / 2; sbw[1] = (pbfont->FontBBox.q.y + pbfont->FontBBox.p.y - sbw42[3]) / 2; sbw[2] = sbw42[2]; sbw[3] = sbw42[3]; } } } else { w[0] = sbw[2]; w[1] = sbw[3]; } return zchar_set_cache(i_ctx_p, pbfont, cnref, (put_lsb && present == metricsSideBearingAndWidth ? sbw : NULL), w, &pbfont->FontBBox, cont, exec_cont, gs_rootfont(igs)->WMode ? sbw : NULL); }
/* * 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 charstring_execchar_aux(i_ctx_t *i_ctx_p, gs_text_enum_t *penum, gs_font *pfont) { os_ptr op = osp; gs_font_base *const pbfont = (gs_font_base *) pfont; gs_font_type1 *const pfont1 = (gs_font_type1 *) pfont; const gs_type1_data *pdata; gs_type1exec_state cxs; gs_type1_state *const pcis = &cxs.cis; gs_rect FontBBox = pfont1->FontBBox; int code; if (penum->current_font->FontType == ft_CID_encrypted) { if (FontBBox.q.x <= FontBBox.p.x && FontBBox.q.y <= FontBBox.p.y) { gs_font_cid0 *pfcid0 = (gs_font_cid0 *)penum->current_font; FontBBox = pfcid0->FontBBox; } } pdata = &pfont1->data; /* * Any reasonable implementation would execute something like * 1 setmiterlimit 0 setlinejoin 0 setlinecap * here, but the Adobe implementations don't. * * If this is a stroked font, set the stroke width. */ if (pfont->PaintType) gs_setlinewidth(igs, pfont->StrokeWidth); check_estack(3); /* for continuations */ /* * Execute the definition of the character. */ if (r_is_proc(op)) return zchar_exec_char_proc(i_ctx_p); /* * The definition must be a Type 1 CharString. * Note that we do not require read access: this is deliberate. */ check_type(*op, t_string); if (r_size(op) <= max(pdata->lenIV, 0)) return_error(e_invalidfont); /* * In order to make character oversampling work, we must * set up the cache before calling .type1addpath. * To do this, we must get the bounding box from the FontBBox, * and the width from the CharString or the Metrics. * If the FontBBox isn't valid, we can't do any of this. */ 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 { /* pass here if FontType==9,11 && WMode==1*/ 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 = metricsNone; } /* Establish a current point. */ code = gs_moveto(igs, 0.0, 0.0); if (code < 0) return code; code = type1_exec_init(pcis, penum, igs, pfont1); if (code < 0) return code; gs_type1_set_callback_data(pcis, &cxs); if (FontBBox.q.x > FontBBox.p.x && FontBBox.q.y > FontBBox.p.y ) { /* The FontBBox appears to be valid. */ op_proc_t exec_cont = 0; cxs.char_bbox = pfont1->FontBBox; code = type1exec_bbox(i_ctx_p, penum, &cxs, pfont, &exec_cont); if (code >= 0 && exec_cont != 0) code = (*exec_cont)(i_ctx_p); return code; } else { /* The FontBBox is not valid */ const ref *opstr = op; ref other_subr; const gs_matrix * pctm = &ctm_only(igs); /* First, check for singular CTM */ if (pctm->xx * pctm->yy == pctm->xy * pctm->yx) { /* The code below won't be able to find the FontBBox but we * don't need it anyway. Set an empty box and consider it valid. */ op_proc_t exec_cont = 0; cxs.char_bbox.p.x = 0; cxs.char_bbox.p.y = 0; cxs.char_bbox.q.x = 0; cxs.char_bbox.q.y = 0; code = type1exec_bbox(i_ctx_p, penum, &cxs, pfont, &exec_cont); if (code >= 0 && exec_cont != 0) code = (*exec_cont)(i_ctx_p); return code; } /* Now we create the path first, then do the setcachedevice. * If we are oversampling (in this case, only for anti- * aliasing, not just to improve quality), we have to * create the path twice, since we can't know the * oversampling factor until after setcachedevice. */ switch (cxs.present) { case metricsSideBearingAndWidth: { gs_point pt; pt.x = cxs.sbw[0], pt.y = cxs.sbw[1]; gs_type1_set_lsb(pcis, &pt); } /* fall through */ case metricsWidthOnly: { gs_point pt; pt.x = cxs.sbw[2], pt.y = cxs.sbw[3]; gs_type1_set_width(pcis, &pt); } } /* Continue interpreting. */ icont: code = type1_continue_dispatch(i_ctx_p, &cxs, opstr, &other_subr, 4); op = osp; /* OtherSubrs might change it */ switch (code) { case 0: /* all done */ return nobbox_finish(i_ctx_p, &cxs); default: /* code < 0, error */ return code; case type1_result_callothersubr: /* unknown OtherSubr */ return type1_call_OtherSubr(i_ctx_p, &cxs, nobbox_continue, &other_subr); case type1_result_sbw: /* [h]sbw, just continue */ switch (cxs.present) { case metricsNone: cxs.sbw[0] = fixed2float(pcis->lsb.x); cxs.sbw[1] = fixed2float(pcis->lsb.y); /* fall through */ case metricsWidthOnly: cxs.sbw[2] = fixed2float(pcis->width.x); cxs.sbw[3] = fixed2float(pcis->width.y); } opstr = 0; goto icont; } } }