/* Copyright (C) 1991, 2000 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: zfont0.c,v 1.3.6.1.2.1 2003/01/17 00:49:06 giles Exp $ */ /* Composite font creation operator */ #include "ghost.h" #include "oper.h" #include "gsstruct.h" /* * The following lines used to say: * #include "gsmatrix.h" * #include "gxdevice.h" /. for gxfont.h ./ * Tony Li says the longer list is necessary to keep the GNU compiler * happy, but this is pretty hard to understand.... */ #include "gxfixed.h" #include "gxmatrix.h" #include "gzstate.h" /* must precede gxdevice */ #include "gxdevice.h" /* must precede gxfont */ #include "gxfcmap.h" #include "gxfont.h" #include "gxfont0.h" #include "bfont.h" #include "ialloc.h" #include "iddict.h" #include "idparam.h" #include "igstate.h" #include "iname.h" #include "store.h" /* Imported from zfcmap.c */ int ztype0_get_cmap(P4(const gs_cmap_t ** ppcmap, const ref * pfdepvector, const ref * op, gs_memory_t *imem)); /* Forward references */ private font_proc_define_font(ztype0_define_font); private font_proc_make_font(ztype0_make_font); private int ensure_char_entry(P5(i_ctx_t *, os_ptr, const char *, byte *, int)); /* .buildfont0 */ /* Build a type 0 (composite) font. */ private int zbuildfont0(i_ctx_t *i_ctx_p) { os_ptr op = osp; gs_type0_data data; ref fdepvector; ref *pprefenc; gs_font_type0 *pfont; font_data *pdata; ref save_FID; int i; int code = 0; check_type(*op, t_dictionary); { ref *pfmaptype; ref *pfdepvector; if (dict_find_string(op, "FMapType", &pfmaptype) <= 0 || !r_has_type(pfmaptype, t_integer) || pfmaptype->value.intval < (int)fmap_type_min || pfmaptype->value.intval > (int)fmap_type_max || dict_find_string(op, "FDepVector", &pfdepvector) <= 0 || !r_is_array(pfdepvector) ) return_error(e_invalidfont); data.FMapType = (fmap_type) pfmaptype->value.intval; /* * Adding elements below could cause the font dictionary to be * resized, which would invalidate pfdepvector. */ fdepvector = *pfdepvector; } /* Check that every element of the FDepVector is a font. */ data.fdep_size = r_size(&fdepvector); for (i = 0; i < data.fdep_size; i++) { ref fdep; gs_font *psub; array_get(&fdepvector, i, &fdep); if ((code = font_param(&fdep, &psub)) < 0) return code; /* * Check the inheritance rules. Allowed configurations * (paths from root font) are defined by the regular * expression: * (shift | double_escape escape* | escape*) * non_modal* non_composite */ if (psub->FontType == ft_composite) { const gs_font_type0 *const psub0 = (const gs_font_type0 *)psub; fmap_type fmt = psub0->data.FMapType; if (fmt == fmap_double_escape || fmt == fmap_shift || (fmt == fmap_escape && !(data.FMapType == fmap_escape || data.FMapType == fmap_double_escape)) ) return_error(e_invalidfont); } } switch (data.FMapType) { case fmap_escape: case fmap_double_escape: /* need EscChar */ code = ensure_char_entry(i_ctx_p, op, "EscChar", &data.EscChar, 255); break; case fmap_shift: /* need ShiftIn & ShiftOut */ code = ensure_char_entry(i_ctx_p, op, "ShiftIn", &data.ShiftIn, 15); if (code >= 0) code = ensure_char_entry(i_ctx_p, op, "ShiftOut", &data.ShiftOut, 14); break; case fmap_SubsVector: /* need SubsVector */ { ref *psubsvector; uint svsize; if (dict_find_string(op, "SubsVector", &psubsvector) <= 0 || !r_has_type(psubsvector, t_string) || (svsize = r_size(psubsvector)) == 0 || (data.subs_width = (int)*psubsvector->value.bytes + 1) > 4 || (svsize - 1) % data.subs_width != 0 ) return_error(e_invalidfont); data.subs_size = (svsize - 1) / data.subs_width; data.SubsVector.data = psubsvector->value.bytes + 1; data.SubsVector.size = svsize - 1; } break; case fmap_CMap: /* need CMap */ code = ztype0_get_cmap(&data.CMap, (const ref *)&fdepvector, (const ref *)op, imemory); break; default: ; } if (code < 0) return code; /* * Save the old FID in case we have to back out. * build_gs_font will return an error if there is a FID entry * but it doesn't reference a valid font. */ { ref *pfid; if (dict_find_string(op, "FID", &pfid) <= 0) make_null(&save_FID); else save_FID = *pfid; } { build_proc_refs build; code = build_proc_name_refs(&build, "%Type0BuildChar", "%Type0BuildGlyph"); if (code < 0) return code; code = build_gs_font(i_ctx_p, op, (gs_font **) & pfont, ft_composite, &st_gs_font_type0, &build, bf_options_none); } if (code != 0) return code; /* Fill in the rest of the basic font data. */ pfont->procs.init_fstack = gs_type0_init_fstack; pfont->procs.define_font = ztype0_define_font; pfont->procs.make_font = ztype0_make_font; pfont->procs.next_char_glyph = gs_type0_next_char_glyph; if (dict_find_string(op, "PrefEnc", &pprefenc) <= 0) { ref nul; make_null_new(&nul); if ((code = idict_put_string(op, "PrefEnc", &nul)) < 0) goto fail; } /* Fill in the font data */ pdata = pfont_data(pfont); data.encoding_size = r_size(&pdata->Encoding); data.Encoding = (uint *) ialloc_byte_array(data.encoding_size, sizeof(uint), "buildfont0(Encoding)"); if (data.Encoding == 0) { code = gs_note_error(e_VMerror); goto fail; } /* Fill in the encoding vector, checking to make sure that */ /* each element is an integer between 0 and fdep_size-1. */ for (i = 0; i < data.encoding_size; i++) { ref enc; array_get(&pdata->Encoding, i, &enc); if (!r_has_type(&enc, t_integer)) { code = gs_note_error(e_typecheck); goto fail; } if ((ulong) enc.value.intval >= data.fdep_size) { code = gs_note_error(e_rangecheck); goto fail; } data.Encoding[i] = (uint) enc.value.intval; } data.FDepVector = ialloc_struct_array(data.fdep_size, gs_font *, &st_gs_font_ptr_element, "buildfont0(FDepVector)"); if (data.FDepVector == 0) { code = gs_note_error(e_VMerror); goto fail; } for (i = 0; i < data.fdep_size; i++) { ref fdep; ref *pfid; array_get(&fdepvector, i, &fdep); /* The lookup can't fail, because of the pre-check above. */ dict_find_string(&fdep, "FID", &pfid); data.FDepVector[i] = r_ptr(pfid, gs_font); } pfont->data = data; code = define_gs_font((gs_font *) pfont); if (code >= 0) return code; fail: /* Undo the insertion of the FID entry in the dictionary. */ if (r_has_type(&save_FID, t_null)) { ref rnfid; name_enter_string("FID", &rnfid); idict_undef(op, &rnfid); } else idict_put_string(op, "FID", &save_FID); gs_free_object(pfont->memory, pfont, "buildfont0(font)"); return code; } /* If a newly defined or scaled composite font had to scale */ /* any composite sub-fonts, adjust the parent font's FDepVector. */ /* This is called only if gs_type0_define/make_font */ /* actually changed the FDepVector. */ private int ztype0_adjust_FDepVector(gs_font_type0 * pfont) { gs_memory_t *mem = pfont->memory; /* HACK: We know the font was allocated by the interpreter. */ gs_ref_memory_t *imem = (gs_ref_memory_t *)mem; gs_font **pdep = pfont->data.FDepVector; ref newdep; uint fdep_size = pfont->data.fdep_size; ref *prdep; uint i; int code = gs_alloc_ref_array(imem, &newdep, a_readonly, fdep_size, "ztype0_adjust_matrix"); if (code < 0) return code; for (prdep = newdep.value.refs, i = 0; i < fdep_size; i++, prdep++) { const ref *pdict = pfont_dict(pdep[i]); ref_assign(prdep, pdict); r_set_attrs(prdep, imemory_new_mask(imem)); } /* * The FDepVector is an existing key in the parent's dictionary, * so it's safe to pass NULL as the dstack pointer to dict_put_string. */ return dict_put_string(pfont_dict(pfont), "FDepVector", &newdep, NULL); } private int ztype0_define_font(gs_font_dir * pdir, gs_font * pfont) { gs_font_type0 *const pfont0 = (gs_font_type0 *)pfont; gs_font **pdep = pfont0->data.FDepVector; int code = gs_type0_define_font(pdir, pfont); if (code < 0 || pfont0->data.FDepVector == pdep) return code; return ztype0_adjust_FDepVector(pfont0); } private int ztype0_make_font(gs_font_dir * pdir, const gs_font * pfont, const gs_matrix * pmat, gs_font ** ppfont) { gs_font_type0 **const ppfont0 = (gs_font_type0 **)ppfont; gs_font **pdep = (*ppfont0)->data.FDepVector; int code; code = zdefault_make_font(pdir, pfont, pmat, ppfont); if (code < 0) return code; code = gs_type0_make_font(pdir, pfont, pmat, ppfont); if (code < 0) return code; if ((*ppfont0)->data.FDepVector == pdep) return 0; return ztype0_adjust_FDepVector(*ppfont0); } /* ------ Internal routines ------ */ /* Find or add a character entry in a font dictionary. */ private int ensure_char_entry(i_ctx_t *i_ctx_p, os_ptr op, const char *kstr, byte * pvalue, int default_value) { ref *pentry; if (dict_find_string(op, kstr, &pentry) <= 0) { ref ent; make_int(&ent, default_value); *pvalue = (byte) default_value; return idict_put_string(op, kstr, &ent); } else { check_int_leu_only(*pentry, 255); *pvalue = (byte) pentry->value.intval; return 0; } } /* ------ Initialization procedure ------ */ const op_def zfont0_op_defs[] = { {"2.buildfont0", zbuildfont0}, op_def_end(0) };