/* Copyright (C) 1998, 1999, 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: gdevpsf1.c,v 1.9.2.1.2.1 2003/01/17 00:49:01 giles Exp $ */ /* Write an embedded Type 1 font */ #include "memory_.h" #include "gx.h" #include "gserrors.h" #include "gsccode.h" #include "gsmatrix.h" #include "gxfixed.h" #include "gxfont.h" #include "gxfont1.h" #include "gxmatrix.h" /* for gxtype1.h */ #include "gxtype1.h" #include "strimpl.h" /* required by Watcom compiler (why?) */ #include "stream.h" #include "sfilter.h" #include "spsdf.h" #include "sstring.h" #include "spprint.h" #include "gdevpsf.h" /* ------ Utilities shared with CFF writer ------ */ /* Gather glyph information for a Type 1 or Type 2 font. */ int psf_type1_glyph_data(gs_font_base *pbfont, gs_glyph glyph, gs_const_string *pstr, gs_font_type1 **ppfont) { gs_font_type1 *const pfont = (gs_font_type1 *)pbfont; *ppfont = pfont; return pfont->data.procs.glyph_data(pfont, glyph, pstr); } int psf_get_type1_glyphs(psf_outline_glyphs_t *pglyphs, gs_font_type1 *pfont, gs_glyph *subset_glyphs, uint subset_size) { return psf_get_outline_glyphs(pglyphs, (gs_font_base *)pfont, subset_glyphs, subset_size, psf_type1_glyph_data); } /* ------ Main program ------ */ /* Write a (named) array of floats. */ private int write_float_array(gs_param_list *plist, const char *key, const float *values, int count) { if (count != 0) { gs_param_float_array fa; fa.size = count; fa.data = values; return param_write_float_array(plist, key, &fa); } return 0; } /* Write a UniqueID and/or XUID. */ private void write_uid(stream *s, const gs_uid *puid) { if (uid_is_UniqueID(puid)) pprintld1(s, "/UniqueID %ld def\n", puid->id); else if (uid_is_XUID(puid)) { uint i, n = uid_XUID_size(puid); stream_puts(s, "/XUID ["); for (i = 0; i < n; ++i) pprintld1(s, "%ld ", uid_XUID_values(puid)[i]); stream_puts(s, "] readonly def\n"); } } /* Write the font name. */ private void write_font_name(stream *s, const gs_font_type1 *pfont, const gs_const_string *alt_font_name) { if (alt_font_name) stream_write(s, alt_font_name->data, alt_font_name->size); else stream_write(s, pfont->font_name.chars, pfont->font_name.size); } /* * Write the Encoding array. This is a separate procedure only for * readability. */ private int write_Encoding(stream *s, gs_font_type1 *pfont, int options, gs_glyph *subset_glyphs, uint subset_size, gs_glyph notdef) { stream_puts(s, "/Encoding "); switch (pfont->encoding_index) { case ENCODING_INDEX_STANDARD: stream_puts(s, "StandardEncoding"); break; case ENCODING_INDEX_ISOLATIN1: /* ATM only recognizes StandardEncoding. */ if (options & WRITE_TYPE1_POSTSCRIPT) { stream_puts(s, "ISOLatin1Encoding"); break; } default:{ gs_char i; stream_puts(s, "256 array\n"); stream_puts(s, "0 1 255 {1 index exch /.notdef put} for\n"); for (i = 0; i < 256; ++i) { gs_glyph glyph = (*pfont->procs.encode_char) ((gs_font *)pfont, (gs_char)i, GLYPH_SPACE_NAME); const char *namestr; uint namelen; if (subset_glyphs && subset_size) { /* * Only write Encoding entries for glyphs in the * subset. Use binary search to check each glyph, * since subset_glyphs are sorted. */ if (!psf_sorted_glyphs_include(subset_glyphs, subset_size, glyph)) continue; } if (glyph != gs_no_glyph && glyph != notdef && (namestr = (*pfont->procs.callbacks.glyph_name) (glyph, &namelen)) != 0 ) { pprintd1(s, "dup %d /", (int)i); stream_write(s, namestr, namelen); stream_puts(s, " put\n"); } } stream_puts(s, "readonly"); } } stream_puts(s, " def\n"); return 0; } /* * 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. */ private int write_Private(stream *s, gs_font_type1 *pfont, gs_glyph *subset_glyphs, uint subset_size, gs_glyph notdef, int lenIV, int (*write_CharString)(P3(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"); { private 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 = 0.039625; defaults.BlueShift = 7.0; defaults.ExpansionFactor = 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_const_string str; int code; for (n = 0; (code = pdata->procs.subr_data(pfont, n, false, &str)) != gs_error_rangecheck; ) { ++n; if (code > 0) gs_free_const_string(pfont->memory, str.data, str.size, "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, &str)) >= 0) { char buf[50]; sprintf(buf, "dup %d %u -| ", i, str.size); stream_puts(s, buf); write_CharString(s, str.data, str.size); stream_puts(s, " |\n"); if (code > 0) gs_free_const_string(pfont->memory, str.data, str.size, "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_const_string gdata; int code; 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; if (code > 0) gs_free_const_string(pfont->memory, gdata.data, gdata.size, "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 ) { uint gssize; const char *gstr = (*pfont->procs.callbacks.glyph_name)(glyph, &gssize); stream_puts(s, "/"); stream_write(s, gstr, gssize); pprintd1(s, " %d -| ", gdata.size); write_CharString(s, gdata.data, gdata.size); stream_puts(s, " |-\n"); if (code > 0) gs_free_const_string(pfont->memory, gdata.data, gdata.size, "write_Private(CharStrings)"); } } /* Wrap up. */ stream_puts(s, "end\nend\nreadonly put\nnoaccess put\n"); s_release_param_printer(&rlist); return 0; } /* Encrypt and write a CharString. */ private int stream_write_encrypted(stream *s, const void *ptr, uint count) { const byte *const data = ptr; crypt_state state = crypt_charstring_seed; byte buf[50]; /* arbitrary */ uint left, n; int code = 0; for (left = count; left > 0; left -= n) { n = min(left, sizeof(buf)); gs_type1_encrypt(buf, data + count - left, n, &state); code = stream_write(s, buf, n); } return code; } /* Write one FontInfo entry. */ private void write_font_info(stream *s, const char *key, const gs_const_string *pvalue, int do_write) { if (do_write) { pprints1(s, "\n/%s ", key); s_write_ps_string(s, pvalue->data, pvalue->size, PRINT_HEX_NOT_OK); stream_puts(s, " def"); } } /* Write the definition of a Type 1 font. */ int psf_write_type1_font(stream *s, gs_font_type1 *pfont, int options, gs_glyph *orig_subset_glyphs, uint orig_subset_size, const gs_const_string *alt_font_name, int lengths[3]) { stream *es = s; long start = stell(s); param_printer_params_t ppp; printer_param_list_t rlist; gs_param_list *const plist = (gs_param_list *)&rlist; stream AXE_stream; stream_AXE_state AXE_state; byte AXE_buf[200]; /* arbitrary */ stream exE_stream; stream_exE_state exE_state; byte exE_buf[200]; /* arbitrary */ psf_outline_glyphs_t glyphs; int lenIV = pfont->data.lenIV; int (*write_CharString)(P3(stream *, const void *, uint)) = stream_write; int code = psf_get_type1_glyphs(&glyphs, pfont, orig_subset_glyphs, orig_subset_size); if (code < 0) return code; /* Initialize the parameter printer. */ ppp = param_printer_params_default; ppp.item_suffix = " def\n"; ppp.print_ok = (options & WRITE_TYPE1_ASCIIHEX ? 0 : PRINT_BINARY_OK) | PRINT_HEX_NOT_OK; code = s_init_param_printer(&rlist, &ppp, s); if (code < 0) return code; /* Write the font header. */ stream_puts(s, "%!FontType1-1.0: "); write_font_name(s, pfont, alt_font_name); stream_puts(s, "\n11 dict begin\n"); /* Write FontInfo. */ stream_puts(s, "/FontInfo 5 dict dup begin"); { gs_font_info_t info; int code = pfont->procs.font_info((gs_font *)pfont, NULL, (FONT_INFO_COPYRIGHT | FONT_INFO_NOTICE | FONT_INFO_FAMILY_NAME | FONT_INFO_FULL_NAME), &info); if (code >= 0) { write_font_info(s, "Copyright", &info.Copyright, info.members & FONT_INFO_COPYRIGHT); write_font_info(s, "Notice", &info.Notice, info.members & FONT_INFO_NOTICE); write_font_info(s, "FamilyName", &info.FamilyName, info.members & FONT_INFO_FAMILY_NAME); write_font_info(s, "FullName", &info.FullName, info.members & FONT_INFO_FULL_NAME); } } stream_puts(s, "\nend readonly def\n"); /* Write the main font dictionary. */ stream_puts(s, "/FontName /"); write_font_name(s, pfont, alt_font_name); stream_puts(s, " def\n"); code = write_Encoding(s, pfont, options, glyphs.subset_glyphs, glyphs.subset_size, glyphs.notdef); if (code < 0) return code; pprintg6(s, "/FontMatrix [%g %g %g %g %g %g] readonly def\n", pfont->FontMatrix.xx, pfont->FontMatrix.xy, pfont->FontMatrix.yx, pfont->FontMatrix.yy, pfont->FontMatrix.tx, pfont->FontMatrix.ty); write_uid(s, &pfont->UID); pprintg4(s, "/FontBBox {%g %g %g %g} readonly def\n", pfont->FontBBox.p.x, pfont->FontBBox.p.y, pfont->FontBBox.q.x, pfont->FontBBox.q.y); { private const gs_param_item_t font_items[] = { {"FontType", gs_param_type_int, offset_of(gs_font_type1, FontType)}, {"PaintType", gs_param_type_int, offset_of(gs_font_type1, PaintType)}, {"StrokeWidth", gs_param_type_float, offset_of(gs_font_type1, StrokeWidth)}, gs_param_item_end }; code = gs_param_write_items(plist, pfont, NULL, font_items); if (code < 0) return code; } { const gs_type1_data *const pdata = &pfont->data; write_float_array(plist, "WeightVector", pdata->WeightVector.values, pdata->WeightVector.count); } stream_puts(s, "currentdict end\n"); /* Write the Private dictionary. */ if (lenIV < 0 && (options & WRITE_TYPE1_WITH_LENIV)) { /* We'll have to encrypt the CharStrings. */ lenIV = 0; write_CharString = stream_write_encrypted; } if (options & WRITE_TYPE1_EEXEC) { stream_puts(s, "currentfile eexec\n"); lengths[0] = stell(s) - start; start = stell(s); if (options & WRITE_TYPE1_ASCIIHEX) { s_init(&AXE_stream, NULL); s_init_state((stream_state *)&AXE_state, &s_AXE_template, NULL); AXE_state.EndOfData = false; s_init_filter(&AXE_stream, (stream_state *)&AXE_state, AXE_buf, sizeof(AXE_buf), es); es = &AXE_stream; } s_init(&exE_stream, NULL); s_init_state((stream_state *)&exE_state, &s_exE_template, NULL); exE_state.cstate = 55665; s_init_filter(&exE_stream, (stream_state *)&exE_state, exE_buf, sizeof(exE_buf), es); es = &exE_stream; /* * Note: eexec encryption always writes/skips 4 initial bytes, not * the number of initial bytes given by pdata->lenIV. */ stream_puts(es, "****"); } code = write_Private(es, pfont, glyphs.subset_glyphs, glyphs.subset_size, glyphs.notdef, lenIV, write_CharString, &ppp); if (code < 0) return code; stream_puts(es, "dup/FontName get exch definefont pop\n"); if (options & WRITE_TYPE1_EEXEC) { if (options & (WRITE_TYPE1_EEXEC_PAD | WRITE_TYPE1_EEXEC_MARK)) stream_puts(es, "mark "); stream_puts(es, "currentfile closefile\n"); s_close_filters(&es, s); lengths[1] = stell(s) - start; start = stell(s); if (options & WRITE_TYPE1_EEXEC_PAD) { int i; for (i = 0; i < 8; ++i) stream_puts(s, "\n0000000000000000000000000000000000000000000000000000000000000000"); stream_puts(s, "\ncleartomark\n"); } lengths[2] = stell(s) - start; } else { lengths[0] = stell(s) - start; lengths[1] = lengths[2] = 0; } /* Wrap up. */ s_release_param_printer(&rlist); return 0; }