/* The caller guarantees that *op is a dictionary. */ int build_gs_sub_font(i_ctx_t *i_ctx_p, const ref *op, gs_font **ppfont, font_type ftype, gs_memory_type_ptr_t pstype, const build_proc_refs * pbuild, const ref *pencoding, ref *fid_op) { gs_matrix mat, omat; ref fname; /* t_string */ gs_font *pfont; font_data *pdata; /* * Make sure that we allocate the font data * in the same VM as the font dictionary. */ uint space = ialloc_space(idmemory); int code = sub_font_params(imemory, op, &mat, &omat, &fname); if (code < 0) return code; ialloc_set_space(idmemory, r_space(op)); pfont = gs_font_alloc(imemory, pstype, &gs_font_procs_default, NULL, "buildfont(font)"); pdata = ialloc_struct(font_data, &st_font_data, "buildfont(data)"); if (pfont == 0 || pdata == 0) code = gs_note_error(e_VMerror); else if (fid_op) code = add_FID(i_ctx_p, fid_op, pfont, iimemory); if (code < 0) { ifree_object(pdata, "buildfont(data)"); ifree_object(pfont, "buildfont(font)"); ialloc_set_space(idmemory, space); return code; } refset_null((ref *) pdata, sizeof(font_data) / sizeof(ref)); ref_assign_new(&pdata->dict, op); ref_assign_new(&pdata->BuildChar, &pbuild->BuildChar); ref_assign_new(&pdata->BuildGlyph, &pbuild->BuildGlyph); if (pencoding) ref_assign_new(&pdata->Encoding, pencoding); pfont->client_data = pdata; pfont->FontType = ftype; pfont->FontMatrix = mat; pfont->orig_FontMatrix = omat; pfont->BitmapWidths = false; pfont->ExactSize = fbit_use_bitmaps; pfont->InBetweenSize = fbit_use_outlines; pfont->TransformedChar = fbit_use_outlines; pfont->WMode = 0; pfont->procs.encode_char = zfont_encode_char; pfont->procs.glyph_name = zfont_glyph_name; ialloc_set_space(idmemory, space); copy_font_name(&pfont->font_name, &fname); *ppfont = pfont; return 0; }
/* <string|name> <font_dict> .buildfont9 <string|name> <font> */ static int zbuildfont9(i_ctx_t *i_ctx_p) { os_ptr op = osp; build_proc_refs build; int code = build_proc_name_refs(imemory, &build, NULL, "%Type9BuildGlyph"); gs_font_cid_data common; ref GlyphDirectory, GlyphData, DataSource; ref *prfda, cfnstr; ref *pCIDFontName, CIDFontName; gs_font_type1 **FDArray; uint FDArray_size; int FDBytes; uint CIDMapOffset; gs_font_base *pfont; gs_font_cid0 *pfcid; uint i; /* * If the CIDFont's data have been loaded into VM, GlyphData will be * a string or an array of strings; if they are loaded incrementally * from a file, GlyphData will be an integer, and DataSource will be * a (reusable) stream. */ if (code < 0 || (code = cid_font_data_param(op, &common, &GlyphDirectory)) < 0 || (code = dict_find_string(op, "FDArray", &prfda)) < 0 || (code = dict_find_string(op, "CIDFontName", &pCIDFontName)) <= 0 || (code = dict_int_param(op, "FDBytes", 0, MAX_FDBytes, -1, &FDBytes)) < 0 ) return code; /* * Since build_gs_simple_font may resize the dictionary and cause * pointers to become invalid, save CIDFontName */ CIDFontName = *pCIDFontName; if (r_has_type(&GlyphDirectory, t_null)) { /* Standard CIDFont, require GlyphData and CIDMapOffset. */ ref *pGlyphData; if ((code = dict_find_string(op, "GlyphData", &pGlyphData)) < 0 || (code = dict_uint_param(op, "CIDMapOffset", 0, max_uint - 1, max_uint, &CIDMapOffset)) < 0) return code; GlyphData = *pGlyphData; if (r_has_type(&GlyphData, t_integer)) { ref *pds; stream *ignore_s; if ((code = dict_find_string(op, "DataSource", &pds)) < 0) return code; check_read_file(i_ctx_p, ignore_s, pds); DataSource = *pds; } else { if (!r_has_type(&GlyphData, t_string) && !r_is_array(&GlyphData)) return_error(e_typecheck); make_null(&DataSource); } } else { make_null(&GlyphData); make_null(&DataSource); CIDMapOffset = 0; } if (!r_is_array(prfda)) return_error(e_invalidfont); FDArray_size = r_size(prfda); if (FDArray_size == 0) return_error(e_invalidfont); FDArray = ialloc_struct_array(FDArray_size, gs_font_type1 *, &st_gs_font_type1_ptr_element, "buildfont9(FDarray)"); if (FDArray == 0) return_error(e_VMerror); memset(FDArray, 0, sizeof(gs_font_type1 *) * FDArray_size); for (i = 0; i < FDArray_size; ++i) { ref rfd; array_get(imemory, prfda, (long)i, &rfd); code = fd_array_element(i_ctx_p, &FDArray[i], &rfd); if (code < 0) goto fail; } code = build_gs_outline_font(i_ctx_p, op, &pfont, ft_CID_encrypted, &st_gs_font_cid0, &build, bf_Encoding_optional | bf_UniqueID_ignored, build_gs_simple_font); if (code < 0) goto fail; if (code == 1) { /* The font already has a FID, don't need to build it again. Release FDArray and return normally. fixme: FDArray fonts are thrown for garbager. We're not safe to build them after build_gs_simple_font(..., &pfont, ...), because a failure in building them would throw an underbuilt font with unclear consequences. */ ifree_object(FDArray, "buildfont9(FDarray)"); return 0; } pfont->procs.enumerate_glyph = gs_font_cid0_enumerate_glyph; pfont->procs.glyph_outline = z9_glyph_outline; pfont->procs.glyph_info = z9_glyph_info; pfcid = (gs_font_cid0 *)pfont; pfcid->cidata.common = common; pfcid->cidata.CIDMapOffset = CIDMapOffset; pfcid->cidata.FDArray = FDArray; pfcid->cidata.FDArray_size = FDArray_size; pfcid->cidata.FDBytes = FDBytes; pfcid->cidata.glyph_data = z9_glyph_data; pfcid->cidata.proc_data = 0; /* for GC */ if (pfcid->font_name.size == 0) { get_font_name(imemory, &cfnstr, &CIDFontName); copy_font_name(&pfcid->font_name, &cfnstr); } ref_assign(&pfont_data(pfont)->u.cid0.GlyphDirectory, &GlyphDirectory); ref_assign(&pfont_data(pfont)->u.cid0.GlyphData, &GlyphData); ref_assign(&pfont_data(pfont)->u.cid0.DataSource, &DataSource); code = define_gs_font(i_ctx_p, (gs_font *)pfont); if (code >= 0) code = gs_notify_register(&pfont->notify_list, notify_remove_font_type9, pfont); if (code >= 0) { for (i = 0; i < FDArray_size; ++i) { FDArray[i]->dir = pfont->dir; FDArray[i]->data.parent = pfont; } return code; } fail: ifree_object(FDArray, "buildfont9(FDarray)"); return code; }
/* or a negative error code. */ int build_gs_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font ** ppfont, font_type ftype, gs_memory_type_ptr_t pstype, const build_proc_refs * pbuild, build_font_options_t options) { ref kname; /* t_string */ ref *pftype; ref *pencoding = 0; bool bitmapwidths; int exactsize, inbetweensize, transformedchar; int wmode; int code; gs_font *pfont; ref *pfid; ref *aop = dict_access_ref(op); bool cpsi_mode = gs_currentcpsimode(imemory); get_font_name(imemory, &kname, op - 1); if (dict_find_string(op, "FontType", &pftype) <= 0 || !r_has_type(pftype, t_integer) || pftype->value.intval != (int)ftype ) return_error(e_invalidfont); if (dict_find_string(op, "Encoding", &pencoding) <= 0) { if (!(options & bf_Encoding_optional)) return_error(e_invalidfont); pencoding = 0; } else { if (!r_is_array(pencoding)) return_error(e_invalidfont); } if (pencoding) { /* observed Adobe behavior */ int count = r_size(pencoding); int type = ftype ? t_name : t_integer; bool fixit = false; while (count--) { ref r; if ((code = array_get(imemory, pencoding, count, &r)) < 0 || !(r_has_type(&r, type) || r_has_type(&r, t_null))) { if (!cpsi_mode && ftype == ft_user_defined) { if (code < 0 || r_has_type(&r, t_null)) { return_error(e_typecheck); } fixit = true; break; } else { return_error(e_typecheck); } } } /* For at least Type 3 fonts, Adobe Distiller will "fix" an Encoding array, as in, for example * Bug 692681 where the arrays contain integers rather than names. Once the font is instantiated * the integers have been converted to names. * It is preferable to to this manipulation here, rather than in Postscript, because we are less * restricted by read-only attributes and VM save levels. */ if (fixit) { ref penc; uint size = 0; char buf[32], *bptr; avm_space curglob = ialloc_space(idmemory); avm_space useglob = r_is_local(pencoding) ? avm_local : avm_global; ialloc_set_space(idmemory, useglob); count = r_size(pencoding); if ((code = ialloc_ref_array(&penc, (r_type_attrs(pencoding) & a_readonly), count, "build_gs_font")) < 0) return code; while (count--) { ref r; if (array_get(imemory, pencoding, count, &r) < 0){ return_error(e_typecheck); } /* For type 3, we know the Encoding entries must be names */ if (r_has_type(&r, t_name)){ ref_assign(&(penc.value.refs[count]), &r); } else { if ((code = obj_cvs(imemory, &r, (byte *)buf, 32, &size, (const byte **)(&bptr))) < 0) { return(code); } if ((code = name_ref(imemory, (const byte *)bptr, size, &r, true)) < 0) return code; ref_assign(&(penc.value.refs[count]), &r); } } if ((code = dict_put_string(osp, "Encoding", &penc, NULL)) < 0) return code; ialloc_set_space(idmemory, curglob); } } if ((code = dict_int_param(op, "WMode", 0, 1, 0, &wmode)) < 0 || (code = dict_bool_param(op, "BitmapWidths", false, &bitmapwidths)) < 0 || (code = dict_int_param(op, "ExactSize", 0, 2, fbit_use_bitmaps, &exactsize)) < 0 || (code = dict_int_param(op, "InBetweenSize", 0, 2, fbit_use_outlines, &inbetweensize)) < 0 || (code = dict_int_param(op, "TransformedChar", 0, 2, fbit_use_outlines, &transformedchar)) < 0 ) return code; code = dict_find_string(op, "FID", &pfid); if (code > 0 && r_has_type(pfid, t_fontID)) { /* silently ignore invalid FID per CET 13-05.ps */ /* * If this font has a FID entry already, it might be a scaled font * made by makefont or scalefont; in a Level 2 environment, it might * be an existing font being registered under a second name, or a * re-encoded font (which was invalid in Level 1, but dvips did it * anyway). */ pfont = r_ptr(pfid, gs_font); /* * If the following condition is false this is a re-encoded font, * or some other questionable situation in which the FID * was preserved. Pretend the FID wasn't there. */ if (obj_eq(pfont->memory, pfont_dict(pfont), op)) { if (pfont->base == pfont) { /* original font */ if (!level2_enabled) return_error(e_invalidfont); *ppfont = pfont; return 1; } else { /* This was made by makefont or scalefont. */ /* Just insert the new name. */ gs_matrix mat; ref fname; /* t_string */ code = sub_font_params(imemory, op, &mat, NULL, &fname); if (code < 0) return code; code = 1; copy_font_name(&pfont->font_name, &fname); goto set_name; } } } /* This is a new font. */ if (!r_has_attr(aop, a_write)) return_error(e_invalidaccess); { ref encoding; /* * Since add_FID may resize the dictionary and cause * pencoding to become invalid, save the Encoding. */ if (pencoding) { encoding = *pencoding; pencoding = &encoding; } code = build_gs_sub_font(i_ctx_p, op, &pfont, ftype, pstype, pbuild, pencoding, op); if (code < 0) return code; } pfont->BitmapWidths = bitmapwidths; pfont->ExactSize = (fbit_type)exactsize; pfont->InBetweenSize = (fbit_type)inbetweensize; pfont->TransformedChar = (fbit_type)transformedchar; pfont->WMode = wmode; pfont->procs.font_info = zfont_info; code = 0; set_name: copy_font_name(&pfont->key_name, &kname); *ppfont = pfont; return code; }