diff options
author | scuri <scuri> | 2008-10-17 06:10:33 +0000 |
---|---|---|
committer | scuri <scuri> | 2008-10-17 06:10:33 +0000 |
commit | 7b52cc13af4e85f1ca2deb6b6c77de9c95ea0dcf (patch) | |
tree | d0857278bde2eff784227c57dcaf930346ceb7ac /src/pdflib/pdflib/p_font.c |
First commit - moving from LuaForge to SourceForge
Diffstat (limited to 'src/pdflib/pdflib/p_font.c')
-rw-r--r-- | src/pdflib/pdflib/p_font.c | 2513 |
1 files changed, 2513 insertions, 0 deletions
diff --git a/src/pdflib/pdflib/p_font.c b/src/pdflib/pdflib/p_font.c new file mode 100644 index 0000000..5dfce77 --- /dev/null +++ b/src/pdflib/pdflib/p_font.c @@ -0,0 +1,2513 @@ +/*---------------------------------------------------------------------------* + | PDFlib - A library for generating PDF on the fly | + +---------------------------------------------------------------------------+ + | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. | + +---------------------------------------------------------------------------+ + | | + | This software is subject to the PDFlib license. It is NOT in the | + | public domain. Extended versions and commercial licenses are | + | available, please check http://www.pdflib.com. | + | | + *---------------------------------------------------------------------------*/ + +/* $Id: p_font.c,v 1.1 2008/10/17 06:11:49 scuri Exp $ + * + * PDFlib font handling routines + * + */ + +#define P_FONT_C + +#include "p_intern.h" +#include "p_color.h" +#include "p_defopt.h" +#include "p_font.h" +#include "p_tagged.h" + +#include "ft_truetype.h" + + +#define PDF_TTC_SEPARATOR ':' + +static const pdc_keyconn pdf_fonttype_pdfkeylist[] = +{ + {"Type1", fnt_Type1}, + {"MMType1", fnt_MMType1}, + {"TrueType", fnt_TrueType}, + {"Type0", fnt_CIDFontType2}, + {"Type1", fnt_Type1C}, + {"Type0", fnt_CIDFontType0}, + {"Type3", fnt_Type3}, + {NULL, 0} +}; + +typedef enum +{ + font_afm = 1, + font_pfm = 2, + font_ttot = 3, + font_pfab = 4 +} +pdf_fontfile_type; + +static const pdc_keyconn pdf_extension_names[] = +{ + {".tte", font_ttot}, + {".ttf", font_ttot}, + {".otf", font_ttot}, + {".afm", font_afm}, + {".pfm", font_pfm}, + {".ttc", font_ttot}, + {".TTE", font_ttot}, + {".TTF", font_ttot}, + {".OTF", font_ttot}, + {".AFM", font_afm}, + {".PFM", font_pfm}, + {".TTC", font_ttot}, + {".pfa", font_pfab}, + {".pfb", font_pfab}, + {".PFA", font_pfab}, + {".PFB", font_pfab}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_fontoption_keylist[] = +{ + {"fontname", fo_fontname}, + {"encoding", fo_encoding}, + {"fontstyle", fo_fontstyle}, + {"monospace", fo_monospace}, + {NULL, 0} +}; + + +void +pdf_init_font(PDF *p, pdf_font *font, pdf_font_options *fo) +{ + (void) p; + + /* font metric */ + fnt_init_font(&font->ft); + + /* font options */ + font->opt = *fo; + font->verbose = fo->fontwarning; + + font->apiname = NULL; + font->filename = NULL; + font->metricfilename = NULL; + + font->used_in_formfield = pdc_false; + font->used_in_current_doc = pdc_false; + font->used_on_current_page = pdc_false; + font->obj_id = PDC_BAD_ID; + + font->cff_offset = 0; + font->cff_length = 0; + + font->t3font = NULL; + font->hasoriginal = pdc_false; + + font->encapiname = NULL; + font->outcmapname = NULL; + font->codepage = 0; + font->towinansi = pdc_invalidenc; + font->hasnomac = pdc_false; + font->passthrough = pdc_false; + font->unibyte = pdc_false; + font->asciispace = pdc_false; + font->issemantic = pdc_false; + font->widthsmissing = pdc_false; + font->missingglyphs = 0; + font->metricflags = 0; + font->supplement = 0; + font->symenc = pdc_invalidenc; + font->replacementchar = -1; + font->replacementcode = -1; + + font->codesize = 1; + font->lastcode = -1; + font->gid0code = -1; + font->usedgids = NULL; + font->expectglyphs = pdc_false; + font->iscidfont = pdc_false; + +} + +void +pdf_cleanup_font(PDF *p, pdf_font *font) +{ + if (font->ft.imgname) + pdc_unlock_pvf(p->pdc, font->ft.imgname); + + /* font metric */ + fnt_cleanup_font(p->pdc, &font->ft); + + if (font->apiname != NULL) + { + pdc_free(p->pdc, font->apiname); + font->apiname = NULL; + } + + if (font->metricfilename != NULL) + { + pdc_free(p->pdc, font->metricfilename); + font->metricfilename = NULL; + } + + if (font->encapiname != NULL) + { + pdc_free(p->pdc, font->encapiname); + font->encapiname = NULL; + } + + if (font->outcmapname != NULL) + { + pdc_free(p->pdc, font->outcmapname); + font->outcmapname = NULL; + } + + + if (font->usedgids != NULL) + { + pdc_free(p->pdc, font->usedgids); + font->usedgids = NULL; + } + + /* Type3 font */ + if (font->t3font != NULL && font->hasoriginal) + { + pdf_cleanup_t3font(p, font->t3font); + pdc_free(p->pdc, font->t3font); + font->t3font = NULL; + } + +} + +void +pdf_init_fonts(PDF *p) +{ + p->fonts = NULL; + p->fonts_number = 0; + p->fonts_capacity = 0; + p->t3slot = -1; + + + pdc_init_encoding_info_ids(p->pdc); +} + +void +pdf_cleanup_fonts(PDF *p) +{ + int slot; + + if (p->fonts != NULL) + { + for (slot = 0; slot < p->fonts_number; slot++) + pdf_cleanup_font(p, &p->fonts[slot]); + + pdc_free(p->pdc, p->fonts); + p->fonts = NULL; + } + +} + +int +pdf_insert_font(PDF *p, pdf_font *font) +{ + static const char fn[] = "pdf_insert_font"; + int slot = p->fonts_number; + + /* insert font */ + if (p->fonts_number == p->fonts_capacity) + { + if (p->fonts_capacity == 0) + { + p->fonts_capacity = FONTS_CHUNKSIZE; + p->fonts = (pdf_font *) pdc_calloc(p->pdc, + sizeof(pdf_font) * p->fonts_capacity, fn); + } + else + { + p->fonts_capacity *= 2; + p->fonts = (pdf_font *) pdc_realloc(p->pdc, p->fonts, + sizeof(pdf_font) * p->fonts_capacity, fn); + } + } + p->fonts[slot] = *font; + + p->fonts_number++; + + return slot; +} + + +const char * +pdf_get_pdf_fontname(pdf_font *font) +{ + const char *fontname; + + fontname = fnt_get_abb_std_fontname(font->ft.name); + if (fontname == NULL) + fontname = fnt_get_abb_cjk_fontname(font->ft.name); + if (fontname == NULL) + fontname = font->ft.name; + + return (const char *) fontname; +} + +const char * +pdf_get_encoding_name(PDF *p, pdc_encoding enc, pdf_font *font) +{ + const char *apiname = pdc_get_fixed_encoding_name(enc); + if (!apiname[0] && enc >= 0) + { + pdc_encodingvector *ev = pdc_get_encoding_vector(p->pdc, enc); + apiname = (const char *) ev->apiname; + } + else if (enc == pdc_cid && font != NULL && font->outcmapname != NULL) + apiname = (const char *) font->outcmapname; + return apiname; +} + +char * +pdf_get_encoding_adaptname(PDF *p, pdc_encoding enc, pdf_font *font, + const char *fontname) +{ + static const char *fn = "pdf_get_encoding_adaptname"; + char *encname = (char *) pdf_get_encoding_name(p, enc, font); + char *adaptname = NULL; + size_t len; + + len = strlen(encname) + 1 + strlen(fontname) + 1; + adaptname = (char *) pdc_malloc_tmp(p->pdc, len, fn, 0, 0); + strcpy(adaptname, encname); + strcat(adaptname, PDC_ENC_MODSEPAR); + strcat(adaptname, fontname); + + return adaptname; +} + +pdc_encodingvector * +pdf_create_font_encoding(PDF *p, pdc_encoding enc, pdf_font *font, + const char *fontname, pdc_bool kreg) +{ + pdc_encodingvector *ev = NULL; + char *adaptname = NULL; + + adaptname = pdf_get_encoding_adaptname(p, enc, font, fontname); + + /* search for a registered encoding */ + enc = pdc_find_encoding(p->pdc, adaptname); + if (enc != pdc_invalidenc) + { + font->ft.enc = enc; + } + else + { + /* create a font encoding */ + ev = pdc_new_encoding(p->pdc, adaptname); + ev->flags |= PDC_ENC_FONT; + ev->flags |= PDC_ENC_SETNAMES; + + if (kreg) + { + enc = pdc_insert_encoding_vector(p->pdc, ev); + font->ft.enc = enc; + } + } + + pdc_free_tmp(p->pdc, adaptname); + + return ev; +} + +const char * +pdf_get_font_char_option(PDF *p, pdf_font_optflags fflags) +{ + pdf_text_options *to = p->curr_ppt->currto; + pdf_font *currfont; + + if (p->fonts_number == 0 || to->font == -1) + pdc_error(p->pdc, PDF_E_TEXT_NOFONT_PAR, + pdc_get_keyword(fflags, pdf_fontoption_keylist), 0, 0, 0); + currfont = &p->fonts[to->font]; + + switch (fflags) + { + case fo_fontname: + return (const char *) currfont->ft.name; + + case fo_encoding: + return pdf_get_encoding_name(p, currfont->ft.enc, currfont); + + case fo_fontstyle: + return pdc_get_keyword(currfont->opt.fontstyle, + pdf_fontstyle_pdfkeylist); + + default: + return NULL; + } +} + +double +pdf_get_font_float_option(PDF *p, pdf_font_optflags fflags) +{ + pdf_text_options *to = p->curr_ppt->currto; + pdf_font *currfont; + + if (p->fonts_number == 0 || to->font == -1) + pdc_error(p->pdc, PDF_E_TEXT_NOFONT_PAR, + pdc_get_keyword(fflags, pdf_fontoption_keylist), 0, 0, 0); + currfont = &p->fonts[to->font]; + + switch (fflags) + { + case fo_monospace: + return (double) currfont->opt.monospace; + + default: + return 0; + } +} + +static const pdc_keyconn pdf_courier_keylist[] = +{ + {"Courier", fnt_Normal}, + {"Courier-Bold", fnt_Bold}, + {"Courier-Oblique", fnt_Italic}, + {"Courier-BoldOblique", fnt_BoldItalic}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_helvetica_keylist[] = +{ + {"Helvetica", fnt_Normal}, + {"Helvetica-Bold", fnt_Bold}, + {"Helvetica-Oblique", fnt_Italic}, + {"Helvetica-BoldOblique", fnt_BoldItalic}, + {NULL, 0} +}; + +static const pdc_keyconn pdf_times_keylist[] = +{ + {"Times-Roman", fnt_Normal}, + {"Times-Bold", fnt_Bold}, + {"Times-Italic", fnt_Italic}, + {"Times-BoldItalic", fnt_BoldItalic}, + {NULL, 0} +}; + +static const char * +pdf_get_fontname_core(pdf_font *font, const char *fontname, pdc_bool checktimes) +{ + const char *fname = NULL; + + /* font style for core fonts */ + if (font->opt.fontstyle != fnt_Normal) + { + if (!strcmp(fontname, "Courier")) + fname = pdc_get_keyword(font->opt.fontstyle, pdf_courier_keylist); + else if (!strcmp(fontname, "Helvetica")) + fname = pdc_get_keyword(font->opt.fontstyle, pdf_helvetica_keylist); + else if (!strcmp(fontname, "Times-Roman")) + fname = pdc_get_keyword(font->opt.fontstyle, pdf_times_keylist); + } + + if (checktimes) + { + if (!strcmp(fontname, "Times")) + fname = pdc_get_keyword(font->opt.fontstyle, pdf_times_keylist); + } + + return fname; +} + +static pdc_bool +pdf_get_metrics_core(PDF *p, pdf_font *font, const char *fontname, + pdc_encoding enc, pdc_bool checktimes) +{ + const char *fname = NULL; + const fnt_font_metric *ftm; + + fname = pdf_get_fontname_core(font, fontname, checktimes); + if (fname != NULL) + { + fontname = fname; + font->opt.fontstyle = fnt_Normal; + } + + ftm = fnt_get_core_metric(fontname); + if (ftm != NULL) + { + pdc_logg_cond(p->pdc, 1, trc_font, + "\tLoading metrics data for core font \"%s\":\n", fontname); + + /* Fill up the font struct */ + fnt_fill_font_metric(p->pdc, &font->ft, + pdc_false, + ftm); + font->ft.enc = enc; + + /* all new glyph names of AGL 2.0 are missing */ + font->missingglyphs = 0xFFFFFFFF; + + /* Process metrics data */ + if (pdf_process_metrics_data(p, font, fontname)) + { + if (pdf_make_fontflag(p, font)) + { + if (!font->opt.monospace) + return pdc_true; + else + pdc_set_errmsg(p->pdc, PDC_E_OPT_IGNORED, "monospace", + 0, 0, 0); + } + } + + return pdc_false; + } + + return pdc_undef; +} + +void +pdf_font_set_missvalues(PDF *p, pdf_font *font) +{ + pdf_font_options *fo = &font->opt; + fnt_font_metric *ftm = &font->ft.m; + + (void) p; + + if (ftm->descender > 0) + ftm->descender = -(ftm->descender); + + if (fo->mask & (1L << fo_ascender)) + { + font->metricflags |= font_ascender; + ftm->ascender = fo->ascender; + } + else if (ftm->ascender <= 0) + { + font->metricflags |= font_ascender; + ftm->ascender = 720; + } + + if (fo->mask & (1L << fo_descender)) + { + font->metricflags |= font_descender; + ftm->descender = fo->descender; + } + else if (ftm->descender == FNT_MISSING_FONTVAL) + { + font->metricflags |= font_descender; + ftm->descender = (int) PDC_ROUND(-0.25 * ftm->ascender); + } + + if (fo->mask & (1L << fo_capheight)) + { + font->metricflags |= font_capheight; + ftm->capHeight = fo->capheight; + } + else if (ftm->capHeight <= 0) + { + font->metricflags |= font_capheight; + ftm->capHeight = (int) PDC_ROUND(0.93 * ftm->ascender); + } + + if (fo->mask & (1L << fo_xheight)) + { + font->metricflags |= font_xheight; + ftm->xHeight = fo->xheight; + } + else if (ftm->xHeight <= 0) + { + font->metricflags |= font_xheight; + ftm->xHeight = (int) PDC_ROUND(0.66 * ftm->ascender); + } + + if (fo->mask & (1L << fo_linegap)) + { + font->metricflags |= font_linegap; + font->ft.linegap = fo->linegap; + } + else if (font->ft.linegap == FNT_MISSING_FONTVAL) + { + font->metricflags |= font_linegap; + font->ft.linegap = (int) PDC_ROUND(0.23 * ftm->ascender); + } + + if (ftm->llx == FNT_MISSING_FONTVAL) + ftm->llx = -50; + if (ftm->lly == FNT_MISSING_FONTVAL) + ftm->lly = ftm->descender; + if (ftm->urx == FNT_MISSING_FONTVAL) + ftm->urx = 1000; + if (ftm->ury == FNT_MISSING_FONTVAL) + ftm->ury = ftm->ascender; + + /* try to fix broken entries */ + if (ftm->lly > ftm->ury) + ftm->ury = ftm->lly + ftm->ascender; + if (ftm->llx > ftm->urx) + ftm->urx = ftm->llx + 1000; +} + +pdc_bool +pdf_font_get_is_faked(pdf_font *font, pdf_font_values flag) +{ + return (font->metricflags & flag) ? pdc_true : pdc_false; +} + +double +pdf_font_get_metric_value(int value) +{ + return (double) value / 1000.0; +} + + +/* --------------------------- font processing ---------------------------- */ + +pdc_bool +pdf_make_fontflag(PDF *p, pdf_font *font) +{ + int errcode = 0; + + if (font->ft.m.type != fnt_Type3) + { + if (font->ft.m.isFixedPitch) + font->ft.m.flags |= FNT_FIXEDWIDTH; + + if (font->ft.issymbfont == pdc_false || + font->ft.enc == pdc_winansi || + font->ft.enc == pdc_macroman || + font->ft.enc == pdc_ebcdic || + font->ft.enc == pdc_ebcdic_37 || + font->ft.enc == pdc_ebcdic_winansi) + font->ft.m.flags |= FNT_ADOBESTANDARD; + else + font->ft.m.flags |= FNT_SYMBOL; + + if (font->ft.m.italicAngle < 0 || + font->opt.fontstyle == fnt_Italic || + font->opt.fontstyle == fnt_BoldItalic) + font->ft.m.flags |= FNT_ITALIC; + if (font->ft.m.italicAngle == 0 && + font->ft.m.flags & FNT_ITALIC) + font->ft.m.italicAngle = FNT_DEF_ITALICANGLE; + + /* heuristic to identify (small) caps fonts */ + if (font->ft.name && + (strstr(font->ft.name, "Caps") || + !strcmp(font->ft.name + strlen(font->ft.name) - 2, "SC"))) + font->ft.m.flags |= FNT_SMALLCAPS; + + if (font->opt.fontstyle == fnt_Bold || + font->opt.fontstyle == fnt_BoldItalic) + font->ft.weight = FNT_FW_BOLD; + + if (strstr(font->ft.name, "Bold") || + font->ft.weight >= FNT_FW_BOLD) + font->ft.m.flags |= FNT_FORCEBOLD; + + /* determine values for FontWeight to StemV */ + if (font->ft.m.StdVW == 0) + font->ft.m.StdVW = fnt_weight2stemv(font->ft.weight); + else if (font->ft.weight == 0) + font->ft.weight = fnt_stemv2weight(font->ft.m.StdVW); + } + + fnt_font_logg_protocol(p->pdc, &font->ft); + + switch(font->ft.m.type) + { + case fnt_Type1: + case fnt_MMType1: + case fnt_Type3: + if (font->opt.fontstyle == fnt_Bold || + font->opt.fontstyle == fnt_BoldItalic) + { + font->metricflags |= font_bold; + } + + if (font->opt.fontstyle == fnt_Italic || + font->opt.fontstyle == fnt_BoldItalic) + { + font->metricflags |= font_italic; + } + + break; + + default: + if (font->opt.embedding) + { + if (font->opt.fontstyle == fnt_Bold || + font->opt.fontstyle == fnt_BoldItalic) + { + font->metricflags |= font_bold; + } + + if (font->opt.fontstyle == fnt_Italic || + font->opt.fontstyle == fnt_BoldItalic) + { + font->metricflags |= font_italic; + } + } + break; + } + + + return errcode ? pdc_false : pdc_true; +} + +int +pdf_get_code_or_glyphid(PDF *p, pdf_font *font, pdc_encodingvector *ev, + pdc_ushort uv) +{ + if (ev != NULL) + { + int code = pdc_get_encoding_bytecode(p->pdc, ev, uv); + + if (code >= 0) + { + if (fnt_get_glyphid(code, &font->ft) <= 0) + code = 0; + } + return code; + } + + return fnt_get_glyphid((int) uv, &font->ft); +} + +void +pdf_set_replchar(PDF *p, pdf_font *font) +{ + pdc_encoding enc = font->ft.enc; + + switch (enc) + { + case pdc_glyphid: + case pdc_cid: + return; + + case pdc_builtin: + font->replacementcode = 0; + return; + + case pdc_unicode: + default: + { + pdc_encodingvector *ev = pdc_get_encoding_vector(p->pdc, enc); + pdc_ushort uv = 0; + int cg = 0; + uv = PDC_UNICODE_NBSP; + cg = pdf_get_code_or_glyphid(p, font, ev, uv); + if (cg <= 0) + { + uv = PDC_UNICODE_SPACE; + cg = pdf_get_code_or_glyphid(p, font, ev, uv); + if (cg <= 0) + { + uv = 0; + cg = 0; + } + } + + font->replacementchar = (int) uv; + font->replacementcode = cg; + } + return; + } +} + +void +pdf_font_issemantic(PDF *p, pdf_font *font) +{ + pdc_encoding enc = font->ft.enc; + pdc_ushort spacechar = 0; + + /* Flag: encoding with ASCII space for wordspacing */ + if (enc >= 0) + { + pdc_encodingvector *ev = pdc_get_encoding_vector(p->pdc, enc); + int i; + + ev->flags |= PDC_ENC_USED; + i = pdc_get_encoding_bytecode(p->pdc, ev, PDC_UNICODE_SPACE); + if (i > -1) + { + spacechar = (pdc_ushort) i; + if (spacechar == PDC_UNICODE_SPACE) + font->asciispace = pdc_true; + } + } + + /* Flag: encoding is Unicode interpretable */ + if ((enc >= 0) || + (enc == pdc_cid && font->codesize == 2) || + (enc == pdc_unicode)) + font->issemantic = pdc_true; + + /* determine code of space character */ + switch(enc) + { + case pdc_cid: + if (font->codesize == 2) + font->ft.spacechar = PDC_UNICODE_SPACE; + break; + + case pdc_unicode: + font->ft.spacechar = PDC_UNICODE_SPACE; + break; + + case pdc_glyphid: + font->ft.spacechar = + (pdc_ushort) MAX(fnt_get_glyphid(PDC_UNICODE_SPACE, &font->ft), 0); + break; + + default: + font->ft.spacechar = spacechar; + break; + } +} + +/* definitions of font options */ +static const pdc_defopt pdf_load_font_options[] = +{ + PDF_FONT_OPTIONS2 + PDF_FONT_OPTIONS3 + PDF_ERRORPOLICY_OPTION + PDC_OPT_TERMINATE +}; + +void +pdf_init_font_options(PDF *p, pdf_font_options *fo) +{ + static const char fn[] = "pdf_init_font_options"; + + if (fo == NULL) + { + p->currfo = (pdf_font_options *) pdc_malloc(p->pdc, + sizeof(pdf_font_options), fn); + + + fo = p->currfo; + } + else + { + } + + + fo->embedding = pdc_false; /* default true if CID custom font */ + fo->encoding = NULL; + fo->flags = 0; + fo->fontname = NULL; + fo->fontstyle = fnt_Normal; + fo->fontwarning = p->debug[(int) 'F']; + fo->fontwarning = pdf_get_errorpolicy(p, NULL, fo->fontwarning); + fo->mask = 0; + fo->monospace = 0; + fo->ascender = 0; + fo->descender = 0; + fo->capheight = 0; + fo->xheight = 0; + fo->linegap = 0; + fo->auxiliary = pdc_false; + +} + +void +pdf_cleanup_font_curroptions(PDF *p) +{ + if (p->currfo) + { + pdc_free(p->pdc, p->currfo); + p->currfo = NULL; + } +} + +void +pdf_cleanup_font_options(PDF *p, pdf_font_options *fo) +{ + if (fo->fontname != NULL) + { + pdc_free(p->pdc, fo->fontname); + fo->fontname = NULL; + } + + if (fo->encoding != NULL) + { + pdc_free(p->pdc, fo->encoding); + fo->encoding = NULL; + } +} + +void +pdf_parse_font_options(PDF *p, const char *optlist) +{ + pdc_resopt *resopts = pdc_parse_optionlist(p->pdc, optlist, + pdf_load_font_options, NULL, pdc_true); + + pdf_get_font_options(p, p->currfo, resopts); + pdc_cleanup_optionlist(p->pdc, resopts); +} + +void +pdf_get_font_options(PDF *p, pdf_font_options *fo, pdc_resopt *resopts) +{ + int inum; + + (void) p; + + if (fo->flags & is_block || + fo->flags & is_textline || + fo->flags & is_textflow) + { + if (pdc_get_optvalues("fontname", resopts, NULL, NULL)) + { + fo->fontname = (char *)pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + fo->mask |= (1L << fo_fontname); + } + + if (pdc_get_optvalues("encoding", resopts, NULL, NULL)) + { + fo->encoding = (char *)pdc_save_lastopt(resopts, PDC_OPT_SAVE1ELEM); + fo->mask |= (1L << fo_encoding); + } + } + + if (pdc_get_optvalues("fontwarning", resopts, &fo->fontwarning, NULL)) + fo->mask |= (1L << fo_fontwarning); + fo->fontwarning = pdf_get_errorpolicy(p, resopts, fo->fontwarning); + + if (pdc_get_optvalues("embedding", resopts, &fo->embedding, NULL)) + fo->mask |= (1L << fo_embedding); + + + if (pdc_get_optvalues("fontstyle", resopts, &inum, NULL)) + { + fo->fontstyle = (fnt_fontstyle) inum; + fo->mask |= (1L << fo_fontstyle); + } + + if (pdc_get_optvalues("monospace", resopts, &fo->monospace, NULL)) + fo->mask |= (1L << fo_monospace); + + if (pdc_get_optvalues("ascender", resopts, &fo->ascender, NULL)) + fo->mask |= (1L << fo_ascender); + + if (pdc_get_optvalues("descender", resopts, &fo->descender, NULL)) + fo->mask |= (1L << fo_descender); + + if (pdc_get_optvalues("capheight", resopts, &fo->capheight, NULL)) + fo->mask |= (1L << fo_capheight); + + if (pdc_get_optvalues("xheight", resopts, &fo->xheight, NULL)) + fo->mask |= (1L << fo_xheight); + + if (pdc_get_optvalues("linegap", resopts, &fo->linegap, NULL)) + fo->mask |= (1L << fo_linegap); + +} + +int +pdf__load_font(PDF *p, const char *fontname, int inlen, + const char *encoding, const char *optlist) +{ + int slot; + pdf_font_options fo; + + if (encoding == NULL || *encoding == '\0') + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "encoding", 0, 0, 0); + + if (fontname == NULL) + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "fontname", 0, 0, 0); + + /* initialize */ + pdf_init_font_options(p, &fo); + + /* Converting fontname */ + fo.fontname = (char *) pdf_convert_name(p, fontname, inlen, + PDC_CONV_WITHBOM); + if (fo.fontname == NULL || *fo.fontname == '\0') + pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "fontname", 0, 0, 0); + + /* encoding */ + fo.encoding = (char *) pdc_strdup(p->pdc, encoding); + + /* parsing option list */ + if (optlist && strlen(optlist)) + { + pdc_resopt *resopts; + pdc_clientdata data; + + pdf_set_clientdata(p, &data); + resopts = pdc_parse_optionlist(p->pdc, optlist, + pdf_load_font_options, &data, pdc_true); + if (!resopts) + { + pdf_cleanup_font_options(p, &fo); + return -1; + } + + pdf_get_font_options(p, &fo, resopts); + pdc_cleanup_optionlist(p->pdc, resopts); + } + + slot = pdf_load_font_internal(p, &fo); + return slot; +} + +static void +pdf_check_font_identical(PDF *p, pdf_font *font, int *slot) +{ + pdf_font *oldfont = &p->fonts[*slot]; + const char *optname = NULL; + + if (!oldfont->opt.embedding && font->opt.embedding) + { + optname = "embedding"; + if (p->errorpolicy == errpol_legacy) + { + pdc_warning(p->pdc, PDF_E_FONT_NOTFULFILL, optname, optname, + 0, 0); + } + else + { + pdc_set_errmsg(p->pdc, PDF_E_FONT_NOTFULFILL, optname, optname, + 0, 0); + *slot = -1; + } + } + +} + +pdc_bool +pdf_check_font_embedding(PDF *p, pdf_font *font, const char *fontname) +{ + (void) p; + (void) font; + (void) fontname; + + + + return pdc_true; +} + +int +pdf_load_font_internal(PDF *p, pdf_font_options *fo) +{ + pdc_bool logg2 = pdc_logg_is_enabled(p->pdc, 2, trc_font); + const char *fontname; + const char *encoding; + const char *encoding_aux; + pdc_encoding enc = pdc_invalidenc; + pdf_font tmpfont, *font; + const char *filename = NULL; + const char *extension = NULL; + const char *outfilename = NULL; + char *fontname_p = NULL; + char testfilename[PDF_MAX_FONTNAME + 5]; + char *sf, *mmparam, mastername[PDF_MAX_FONTNAME + 1]; + char ittc; + size_t len; + pdc_bool retval = pdc_false; + int slot = -1, i; + + /* host or UTF-8 encoded font name without BOM */ + fontname_p = pdc_utf8_to_hostbytes(p->pdc, pdc_false, fo->fontname); + if (fontname_p == NULL) + { + fontname = pdc_utf8strprint(p->pdc, fo->fontname); + } + else + { + fontname = pdc_utf8strprint(p->pdc, fontname_p); + pdc_free(p->pdc, fontname_p); + } + fontname_p = NULL; + + /* font encoding */ + encoding = fo->encoding; + encoding_aux = encoding; + + /* initialize font struct */ + font = &tmpfont; + pdf_init_font(p, font, fo); + + /* error message prefix */ + pdc_push_errmsg(p->pdc, PDF_E_FONT_PREFIX, fontname, encoding, 0, 0); + + + + + /* API font name */ + font->apiname = pdc_strdup(p->pdc, fontname); + + /* UTF-8 font name with BOM */ + font->ft.utf8name = pdc_strdup(p->pdc, fo->fontname); + + pdc_logg_cond(p->pdc, 1, trc_font, "\tFont UTF-8 name: \"%s\"\n", + font->ft.utf8name); + + /* specified encoding name */ + font->encapiname = pdc_strdup(p->pdc, encoding); + + /* search for a registered encoding */ + enc = pdc_find_encoding(p->pdc, encoding); + if (enc == pdc_invalidenc || enc == pdc_unicode) + { + /* search for a predefined CMap and registered fonts */ + if (!pdf_handle_cidfont(p, fontname, encoding, enc, font, &slot, &enc)) + goto PDF_PREMATURE_EXIT; + + if (enc == pdc_invalidenc) + { + /* search for a new encoding */ + enc = pdc_insert_encoding(p->pdc, encoding, &font->codepage, + font->verbose); + if (enc == pdc_invalidenc) + goto PDF_PREMATURE_EXIT; + } + else if (enc == pdc_cid) + { + if (slot == -1) + goto PDF_NEWFONT_EXIT; + else + goto PDF_PREMATURE_EXIT; + } + else if (enc == pdc_glyphid) + { + encoding_aux = "glyphid"; + } + else if (enc == pdc_unicode) + { + encoding_aux = "unicode"; + } + } + + if (pdc_strcmp(font->encapiname, encoding)) + { + pdc_push_errmsg(p->pdc, PDF_E_FONT_PREFIX2, + fontname, font->encapiname, encoding, 0); + } + encoding = encoding_aux; + + encoding = pdc_get_user_encoding(p->pdc, enc); + pdc_logg_cond(p->pdc, 1, trc_encoding, "\tFont encoding: \"%s\"\n", + encoding); + + if (enc == pdc_unicode || enc == pdc_glyphid) + { + pdc_set_errmsg(p->pdc, PDF_E_UNSUPP_UNICODE, 0, 0, 0, 0); + goto PDF_PREMATURE_EXIT; + } + + /* + * Look whether font is already in the cache. + * Look first for the auxiliary font (obj_id == -1). + * If a font with same encoding and same relevant options is found, + * return its handle. + * If a Type 3 font with the same name but different encoding + * is found, make a copy in a new slot and attach the requested encoding. + */ + + pdc_logg_cond(p->pdc, 1, trc_font, + "\tFont will be searched in the PDFlib font cache\n"); + for (slot = 0; slot < p->fonts_number; slot++) + { + if (p->fonts[slot].obj_id == PDC_BAD_ID && + p->fonts[slot].ft.m.type != fnt_Type3) + { + if (font->opt.auxiliary) + goto PDF_PREMATURE_EXIT; + } + else if (!font->opt.auxiliary && + !pdc_strcmp(p->fonts[slot].apiname, fontname) && + p->fonts[slot].opt.fontstyle == font->opt.fontstyle) + { + if (p->fonts[slot].ft.m.type == fnt_Type3) + { + if (logg2) + pdc_logg(p->pdc, "\t\tType3 font [%d] found\n", slot); + + if (enc < pdc_winansi && enc != pdc_unicode) + { + pdc_set_errmsg(p->pdc, PDF_E_FONT_BADENC, 0, 0, 0, 0); + + slot = -1; + goto PDF_PREMATURE_EXIT; + } + + if (p->fonts[slot].ft.enc != enc) + { + if (!pdf_handle_t3font(p, fontname, enc, font, &slot)) + { + slot = -1; + goto PDF_PREMATURE_EXIT; + } + if (slot > -1) + font = &p->fonts[slot]; + goto PDF_NEWFONT_EXIT; + } + + goto PDF_PREMATURE_EXIT; + } + else if (p->fonts[slot].opt.monospace == font->opt.monospace + ) + { + if (p->fonts[slot].ft.enc == enc && + p->fonts[slot].codepage == font->codepage) + { + if (logg2) + pdc_logg(p->pdc, + "\t\tfont [%d] with same encoding found\n", + slot); + + pdf_check_font_identical(p, font, &slot); + goto PDF_PREMATURE_EXIT; + } + else + { + char *adaptname; + int kc; + + /* Comparing apiname of encoding */ + if (!pdc_stricmp(font->encapiname, + p->fonts[slot].encapiname) && + !pdc_stricmp(font->ft.cmapname, + p->fonts[slot].ft.cmapname)) + { + if (logg2) + pdc_logg(p->pdc, + "\t\tfont [%d] with same encoding " + "apiname '%s' found\n", slot, encoding); + + pdf_check_font_identical(p, font, &slot); + goto PDF_PREMATURE_EXIT; + } + + /* Name of adapted to font encoding */ + adaptname = + pdf_get_encoding_adaptname(p, enc, font, fontname); + kc = strcmp(adaptname, pdf_get_encoding_name(p, + p->fonts[slot].ft.enc, &p->fonts[slot])); + if (!kc) + { + if (logg2) + pdc_logg(p->pdc, + "\t\tfont [%d] with same internal " + "encoding name '%s' found\n", + slot, adaptname); + pdc_free_tmp(p->pdc, adaptname); + + pdf_check_font_identical(p, font, &slot); + goto PDF_PREMATURE_EXIT; + } + pdc_free_tmp(p->pdc, adaptname); + } + } + } + else if (!font->opt.auxiliary && + p->fonts[slot].ft.m.type == fnt_Type1 && + p->fonts[slot].ft.isstdfont && p->fonts[slot].ft.enc == enc) + { + /* different core font specifications */ + const char *fname = pdf_get_fontname_core(font, fontname, pdc_true); + + if ((fname != NULL && !strcmp(fname, p->fonts[slot].ft.name) && + p->fonts[slot].opt.fontstyle == fnt_Normal) || + (!strcmp(fontname, p->fonts[slot].ft.name) && + p->fonts[slot].opt.fontstyle == font->opt.fontstyle)) + { + if (logg2) + pdc_logg(p->pdc, + "\t\tfont [%d] with same font style '%s' found\n", + slot, pdc_get_keyword(font->opt.fontstyle, + pdf_fontstyle_pdfkeylist)); + + pdf_check_font_identical(p, font, &slot); + goto PDF_PREMATURE_EXIT; + } + } + } + + slot = -1; + pdc_logg_cond(p->pdc, 1, trc_font, + "\tFont not found in the PDFlib font cache\n"); + + /* embedding check */ + if (!pdf_check_font_embedding(p, font, fontname)) + { + goto PDF_PREMATURE_EXIT; + } + + /* Multiple Master handling: + * - strip MM parameters to build the master name + * - the master name is used to find the metrics + * - the instance name (client-supplied font name) is used in all places + * - although the master name is used for finding the metrics, the + * instance name is stored in the font struct. + */ + + len = strlen(fontname); + if (len > PDF_MAX_FONTNAME) + { + pdc_set_errmsg(p->pdc, FNT_E_FONT_NAMETOOLONG, + pdc_errprintf(p->pdc, "%d", PDF_MAX_FONTNAME), 0, 0, 0); + goto PDF_PREMATURE_EXIT; + } + strcpy(mastername, fontname); + + /* A Multiple Master font was requested */ + if ((mmparam = strstr(mastername, "MM_")) != NULL) + { + if (font->opt.embedding) + { + pdc_set_errmsg(p->pdc, PDF_E_FONT_EMBEDMM, 0, 0, 0, 0); + goto PDF_PREMATURE_EXIT; + } + mmparam[2] = '\0'; /* strip the parameter from the master name */ + } + + /* Font for vertical writing mode */ + fontname_p = mastername; + if (mastername[0] == '@') + { + font->ft.vertical = pdc_true; + fontname_p = &mastername[1]; + } + + /* protocol */ + pdc_logg_cond(p->pdc, 1, trc_font, + "\tPDFlib font name: \"%s\"\n", fontname_p); + + /* Font file search hierarchy + * - Check "FontOutline" resource entry and check TrueType font + * - Check "FontAFM" resource entry + * - Check "FontPFM" resource entry + * - Check "HostFont" resource entry + * - Check available in-core metrics + * - Check host font + */ + retval = pdc_false; + while (1) + { +#ifdef PDF_TRUETYPE_SUPPORTED + /* Check specified TrueType file */ + filename = pdc_find_resource(p->pdc, "FontOutline", fontname_p); + if (!filename) + { + /* check for TTC font names with index */ + ittc = PDF_TTC_SEPARATOR; + sf = strrchr(fontname_p, ittc); + + if (sf != NULL) + { + *sf = 0; + filename = pdc_find_resource(p->pdc, "FontOutline", fontname_p); + *sf = ittc; + } + } + if (filename) + { + outfilename = filename; + retval = fnt_check_tt_font(p->pdc, filename, fontname_p, &font->ft, + pdc_false); + if (retval == pdc_true) + { + retval = pdf_get_metrics_tt(p, font, fontname_p, enc, filename); + break; + } + else if (retval == pdc_undef && + pdc_get_errnum(p->pdc) == PDC_E_IO_RDOPEN_NF) + { + /* file must be exist */ + retval = pdc_false; + } + if (retval == pdc_false) + break; + } +#endif /* PDF_TRUETYPE_SUPPORTED */ + + /* Check specified AFM file */ + filename = pdc_find_resource(p->pdc, "FontAFM", fontname_p); + if (filename) + { + retval = pdf_get_metrics_afm(p, font, fontname_p, enc, filename, + pdc_true); + break; + } + + /* Check specified PFM file */ + filename = pdc_find_resource(p->pdc, "FontPFM", fontname_p); + if (filename) + { + retval = pdf_get_metrics_pfm(p, font, fontname_p, enc, filename, + pdc_true); + break; + } + + + + /* Check available in-core metrics */ + retval = pdf_get_metrics_core(p, font, fontname_p, enc, pdc_false); + if (retval != pdc_undef) + break; + retval = pdc_false; + + + /* Check available in-core metrics */ + retval = pdf_get_metrics_core(p, font, fontname_p, enc, pdc_true); + if (retval != pdc_undef) + break; + retval = pdc_false; + + /* Searching for a metric file */ + pdc_logg_cond(p->pdc, 1, trc_font, + "\tSearching for font metrics data file:\n"); + + filename = testfilename; + for (i = 0; i < 100; i++) + { + extension = pdf_extension_names[i].word; + if (!extension) + break; + + strcpy(testfilename, fontname_p); + sf = strrchr(testfilename, PDF_TTC_SEPARATOR); + if (sf != NULL) + *sf = 0; + strcat(testfilename, extension); + + switch (pdf_extension_names[i].code) + { +#ifdef PDF_TRUETYPE_SUPPORTED + case font_ttot: + retval = fnt_check_tt_font(p->pdc, filename, fontname_p, + &font->ft, pdc_false); + if (retval == pdc_true) + retval = pdf_get_metrics_tt(p, font, fontname_p, enc, + filename); + break; +#endif /* PDF_TRUETYPE_SUPPORTED */ + + case font_afm: + retval = pdf_get_metrics_afm(p, font, fontname_p, enc, + filename, pdc_false); + break; + + case font_pfm: + retval = pdf_get_metrics_pfm(p, font, fontname_p, enc, + filename, pdc_false); + break; + + default: + break; + } + + /* file found or error */ + if (retval != pdc_undef) + { + if (retval == pdc_true) + if (pdf_extension_names[i].code == font_ttot) + outfilename = filename; + break; + } + } + + if (retval == pdc_undef) + { + retval = pdc_false; + + pdc_logg_cond(p->pdc, 1, trc_font, + "\tMetric data file for font \"%s\" not available\n", + fontname_p); + pdc_set_errmsg(p->pdc, PDF_E_FONT_NOMETRICS, 0, 0, 0, 0); + } + + break; + } + + /* metrics data search finished */ + + if (retval == pdc_false) + { + goto PDF_PREMATURE_EXIT; + } + + /* store instance name instead of master name in the font structure */ + if (mmparam) + { + pdc_free(p->pdc, font->ft.name); + font->ft.name = pdc_strdup(p->pdc, fontname); + pdc_free(p->pdc, font->ft.m.name); + font->ft.m.name = pdc_strdup(p->pdc, fontname); + } + + /* If embedding was requested, check font file (or raise an exception) */ + if (font->opt.embedding) + { + if (font->ft.img == NULL) + { + retval = pdc_undef; + + if (outfilename) + { + /* Font outline file specified */ + if (font->ft.m.type == fnt_Type1 || + font->ft.m.type == fnt_MMType1) + { + retval = pdf_t1open_fontfile(p, font, outfilename, NULL, + pdc_true); + } + else + { + retval = fnt_check_tt_font(p->pdc, outfilename, NULL, + &font->ft, pdc_true); + } + } + else + { + /* Searching font outline file */ + pdc_logg_cond(p->pdc, 1, trc_font, + "\tSearching for font outline data file:\n"); + + outfilename = testfilename; + for (i = 0; i < 100; i++) + { + extension = pdf_extension_names[i].word; + if (!extension) + break; + + strcpy(testfilename, fontname_p); + strcat(testfilename, extension); + + if (font->ft.m.type == fnt_Type1 || + font->ft.m.type == fnt_MMType1) + { + if (pdf_extension_names[i].code == font_pfab) + { + retval = pdf_t1open_fontfile(p, font, outfilename, + NULL, pdc_false); + } + } + else if (pdf_extension_names[i].code == font_ttot) + { + retval = fnt_check_tt_font(p->pdc, outfilename, + NULL, &font->ft, pdc_false); + } + + /* file found or error */ + if (retval != pdc_undef) + break; + } + + if (retval == pdc_undef) + { + retval = pdc_false; + pdc_set_errmsg(p->pdc, PDF_E_FONT_NOOUTLINE, 0, 0, 0, 0); + } + } + + if (retval == pdc_false) + { + pdc_logg_cond(p->pdc, 1, trc_font, + "\tOutline data file for font \"%s\" not found\n", + fontname_p); + } + else + { + if (!font->ft.img) + font->filename = font->ft.filename; + + pdc_logg_cond(p->pdc, 1, trc_font, + "\tFont outline data file \"%s\" available\n", + font->filename ? + font->filename : font->ft.imgname); + } + } + } + else if (font->ft.img) + { + if (!font->ft.imgname) + pdc_free(p->pdc, font->ft.img); + else + { + pdc_unlock_pvf(p->pdc, font->ft.imgname); + pdc_free(p->pdc, font->ft.imgname); + font->ft.imgname = NULL; + } + font->ft.img = NULL; + font->ft.filelen = 0; + } + + if (retval && font->opt.monospace && font->opt.embedding) + { + pdc_set_errmsg(p->pdc, PDC_E_OPT_IGNORED, "monospace", 0, 0, 0); + retval = pdc_false; + } + + if (retval == pdc_false) + { + goto PDF_PREMATURE_EXIT; + } + + PDF_NEWFONT_EXIT: + + pdf_cleanup_font_options(p, fo); + + encoding = pdc_get_user_encoding(p->pdc, font->ft.enc); + if (pdc_strcmp(font->encapiname, encoding)) + pdc_logg_cond(p->pdc, 1, trc_encoding, + "\tDetermined font encoding: \"%s\"\n", encoding); + + /* set missing font metrics values */ + pdf_font_set_missvalues(p, font); + + /* font is semantic (Unicode compatible) */ + pdf_font_issemantic(p, font); + + /* set replacement character and code */ + pdf_set_replchar(p, font); + + /* font object ID */ + if (!font->opt.auxiliary) + font->obj_id = pdc_alloc_id(p->out); + + /* Now everything is fine, insert font */ + if (slot == -1) + slot = pdf_insert_font(p, font); + + + pdc_pop_errmsg(p->pdc); + + return slot; + + + PDF_PREMATURE_EXIT: + + pdf_cleanup_font_options(p, fo); + pdf_cleanup_font(p, font); + + if (slot == -1) + { + if (font->verbose) + pdc_error(p->pdc, -1, 0, 0, 0, 0); + } + + pdc_pop_errmsg(p->pdc); + + return slot; +} + + +/* --------------------------- font writing ---------------------------- */ + +static char * +pdf_code2fontglyphname(pdf_font *font, pdc_encodingvector *ev, int code) +{ + char *glyphname; + + glyphname = ev->chars[code]; + pdc_get_alter_glyphname(ev->codes[code], font->missingglyphs, + &glyphname); + + return glyphname ? glyphname : (char *) pdc_get_notdef_glyphname(); +} + +void +pdf_transform_fontwidths(PDF *p, pdf_font *font, pdc_encodingvector *evto, + pdc_encodingvector *evfrom) +{ + int widths[256]; + pdc_ushort code2gid[256]; + int i, j; + + for (i = 0; i < 256; i++) + { + widths[i] = font->ft.m.defwidth; + code2gid[i] = 0; + } + + for (i = 0; i < 256; i++) + { + j = (int) pdc_transform_bytecode(p->pdc, evto, evfrom, (pdc_byte)i); + widths[j] = font->ft.m.widths[i]; + if (font->ft.code2gid != NULL) + code2gid[j] = font->ft.code2gid[i]; + } + + widths[0] = font->ft.m.defwidth; + memcpy(font->ft.m.widths, widths, 256 * sizeof(int)); + if (font->ft.code2gid != NULL) + memcpy(font->ft.code2gid, code2gid, 256 * sizeof(pdc_ushort)); +} + + + +static void +pdf_write_fontdescriptor( + PDF *p, + pdf_font *font, + int missingwidth, + pdc_id fontdescriptor_id, + pdc_id cidset_id, + pdc_id fontfile_id, + int nusedgids) +{ + (void) cidset_id; + (void) nusedgids; + + /* + * Font descriptor object + */ + pdc_begin_obj(p->out, fontdescriptor_id); /* font descriptor obj */ + pdc_begin_dict(p->out); /* font descriptor dict */ + + pdc_puts(p->out, "/Type/FontDescriptor\n"); + pdc_printf(p->out, "/Flags %ld\n", font->ft.m.flags); + + + pdc_printf(p->out, "/Ascent %d\n", font->ft.m.ascender); + pdc_printf(p->out, "/CapHeight %d\n", font->ft.m.capHeight); + pdc_printf(p->out, "/Descent %d\n", font->ft.m.descender); + pdc_printf(p->out, "/FontBBox[%d %d %d %d]\n", + (int) font->ft.m.llx, (int) font->ft.m.lly, + (int) font->ft.m.urx, (int) font->ft.m.ury); + + pdc_printf(p->out, "/FontName"); + pdf_put_pdfname(p, font->ft.m.name); + pdc_puts(p->out, "\n"); + + pdc_printf(p->out, "/ItalicAngle %d\n", (int) (font->ft.m.italicAngle)); + pdc_printf(p->out, "/StemV %d\n", font->ft.m.StdVW); + + if (font->ft.m.StdHW > 0) + pdc_printf(p->out, "/StemH %d\n", font->ft.m.StdHW); + + if (font->ft.m.xHeight > 0) + pdc_printf(p->out, "/XHeight %d\n", font->ft.m.xHeight); + + if (missingwidth > 0) + pdc_printf(p->out, "/MissingWidth %d\n", missingwidth); + + if (fontfile_id != PDC_BAD_ID) + { + switch(font->ft.m.type) + { + case fnt_Type1: + case fnt_MMType1: + pdc_objref(p->out, "/FontFile", fontfile_id); + break; + +#ifdef PDF_TRUETYPE_SUPPORTED + case fnt_TrueType: + case fnt_CIDFontType2: + pdc_objref(p->out, "/FontFile2", fontfile_id); + break; + + case fnt_Type1C: + case fnt_CIDFontType0: + pdc_objref(p->out, "/FontFile3", fontfile_id); + break; +#endif /* PDF_TRUETYPE_SUPPORTED */ + + default: + break; + } + } + + + pdc_end_dict(p->out); /* font descriptor dict */ + pdc_end_obj(p->out); /* font descriptor obj */ +} + +static void +pdf_put_font(PDF *p, pdf_font *font) +{ + const char *fontname = font->ft.name; + fnt_fonttype fonttype = font->ft.m.type; + pdc_id fontdescriptor_id = PDC_BAD_ID; + pdc_id fontfile_id = PDC_BAD_ID; + pdc_id encoding_id = PDC_BAD_ID; + pdc_id cidset_id = PDC_BAD_ID; + pdc_id length_id = PDC_BAD_ID; + pdc_id descendant_id = PDC_BAD_ID; + pdc_encoding enc = font->ft.enc; + const char *encoding; + pdc_encoding_info *encinfo = NULL; + pdc_bool comp_font = pdc_false; + pdc_bool acro_fontstyle = pdc_false; + pdc_scalar a = 1.0; + PDF_data_source src; + int nusedgids = 0; + + /* save font struct members */ + pdc_encodingvector *ev = NULL; + pdc_encoding font_encoding = font->ft.enc; + int font_numcodes = font->ft.numcodes; + int font_codesize = font->codesize; + + int missingwidth = 0; + int i; + + encoding = pdc_get_user_encoding(p->pdc, enc); + if (!pdc_strcmp(font->encapiname, encoding)) + { + pdc_push_errmsg(p->pdc, PDF_E_FONT_PREFIX, + font->apiname, font->encapiname, 0, 0); + } + else + { + pdc_push_errmsg(p->pdc, PDF_E_FONT_PREFIX2, + font->apiname, font->encapiname, encoding, 0); + } + + + /* ID for embedded font */ + if (font->opt.embedding) + { + switch(fonttype) + { + case fnt_Type1: + case fnt_MMType1: + case fnt_TrueType: + case fnt_CIDFontType2: + case fnt_Type1C: + case fnt_CIDFontType0: + fontfile_id = pdc_alloc_id(p->out); + break; + + default: + break; + } + } + + /* + * Font dictionary + */ + pdc_begin_obj(p->out, font->obj_id); /* font obj */ + pdc_begin_dict(p->out); /* font dict */ + pdc_puts(p->out, "/Type/Font\n"); + + /* /Subtype */ + pdc_printf(p->out, "/Subtype/%s\n", + pdc_get_keyword(fonttype, pdf_fonttype_pdfkeylist)); + comp_font = fonttype == fnt_CIDFontType0 || fonttype == fnt_CIDFontType2; + + /* Acrobat font style */ + acro_fontstyle = font->opt.fontstyle != fnt_Normal && + !(font->metricflags & (font_bold | font_italic)); + + /* /Name */ + if (fonttype == fnt_Type3 || font->used_in_formfield) + { + /* + * The name is optional, but if we include it it will show up + * in Acrobat's font info box. However, if the same font name + * is used with different encodings Acrobat 4 will not be + * able to distinguish both. For this reason we add the + * encoding name to make the font name unique. + */ + + const char *name = fontname; + + if (font->used_in_formfield) + name = pdf_get_pdf_fontname(font); + + pdc_puts(p->out, "/Name"); + pdf_put_pdfname(p, name); + pdc_puts(p->out, "\n"); + } + + /* /BaseFont */ + switch (fonttype) + { + case fnt_Type1: + case fnt_MMType1: + case fnt_TrueType: + case fnt_Type1C: + case fnt_CIDFontType2: + case fnt_CIDFontType0: + { + pdc_puts(p->out, "/BaseFont"); + pdf_put_pdfname(p, fontname); + if (font->outcmapname) + pdc_printf(p->out, "-%s", font->outcmapname); + if (acro_fontstyle && !comp_font) + pdc_printf(p->out, ",%s", pdc_get_keyword(font->opt.fontstyle, + pdf_fontstyle_pdfkeylist)); + pdc_puts(p->out, "\n"); + } + break; + + /* /FontBBox, /FontMatrix, /CharProcs /Resources */ + case fnt_Type3: + if (font->t3font->charprocs_id == PDC_BAD_ID) + pdc_error(p->pdc, PDF_E_T3_OUTLINESMISSING, fontname, 0, 0, 0); + + pdc_printf(p->out, "/FontBBox[%f %f %f %f]\n", + font->ft.bbox.llx, font->ft.bbox.lly, + font->ft.bbox.urx, font->ft.bbox.ury); + + pdc_printf(p->out, "/FontMatrix[%f %f %f %f %f %f]\n", + font->ft.matrix.a, font->ft.matrix.b, + font->ft.matrix.c, font->ft.matrix.d, + font->ft.matrix.e, font->ft.matrix.f); + pdc_objref(p->out, "/CharProcs", font->t3font->charprocs_id); + pdc_objref(p->out, "/Resources", font->t3font->res_id); + + /* We must apply a correctional factor since Type 3 fonts not + * necessarily use 1000 units per em. We apply the correction + * here, and store the 1000-based width values in the font in + * order to speed up PDF_stringwidth(). + */ + a = 1000 * font->ft.matrix.a; + break; + + default: + break; + } + + /* changing 8-bit font encoding to builtin */ + if (enc >= 0 && font->symenc != pdc_invalidenc) + { + ev = NULL; + enc = pdc_builtin; + font->ft.enc = enc; + } + + /* changing 8-bit font encoding to winansi */ + if (font->towinansi != pdc_invalidenc) + { + pdc_encodingvector *evfrom; + + ev = pdc_get_encoding_vector(p->pdc, font->towinansi); + evfrom = pdc_get_encoding_vector(p->pdc, enc); + pdf_transform_fontwidths(p, font, ev, evfrom); + + enc = font->towinansi; + font->ft.enc = enc; + } + + /* /FontDescriptor, /FirstChar, /LastChar, /Widths */ + switch (fonttype) + { + case fnt_Type1: + /* disabled, because of PDF 1.7 reference + if (font->ft.isstdfont == pdc_true) break; + */ + case fnt_MMType1: + case fnt_TrueType: + case fnt_Type1C: + case fnt_Type3: + { + int firstchar = 0; + int lastchar = 255; + int defwidth = 0; + + if (fonttype != fnt_Type3 + ) + { + fontdescriptor_id = pdc_alloc_id(p->out); + pdc_objref(p->out, "/FontDescriptor", fontdescriptor_id); + } + + + /* determine missing width. + * Only for embedded fonts because of a bug in Acrobat, + * which arises if the font is not installed at host. + */ + if (font->opt.embedding) + { + if (fonttype != fnt_Type3) + defwidth = font->ft.m.widths[0]; + + { + for (i = 1; i < 255; i++) + { + if (font->ft.m.widths[i] != defwidth) + break; + } + if (i > 1) + firstchar = i; + for (i = 255; i > 0; i--) + { + if (i == firstchar || font->ft.m.widths[i] != defwidth) + break; + } + lastchar = i; + } + + if (firstchar > 0 || lastchar < 255) + missingwidth = (int) (defwidth / a + 0.5); + } + + pdc_printf(p->out, "/FirstChar %d\n", firstchar); + pdc_printf(p->out, "/LastChar %d\n", lastchar); + + pdc_puts(p->out, "/Widths"); + pdc_begin_array(p->out); + for (i = firstchar; i <= lastchar; i++) + { + pdc_printf(p->out, "%d", + (int) (font->ft.m.widths[i] / a + .5)); + if (i < 255) + pdc_printf(p->out, "%s", ((i + 1) % 16) ? " " : "\n"); + } + pdc_end_array(p->out); + } + break; + + default: + break; + } + + /* /Encoding */ + switch (fonttype) + { + case fnt_Type1: + case fnt_MMType1: + case fnt_TrueType: + case fnt_Type1C: + if (!font->used_in_formfield) + { + if (enc == pdc_winansi) + { + pdc_printf(p->out, "/Encoding/WinAnsiEncoding\n"); + break; + } + if (enc == pdc_macroman && font->hasnomac == pdc_false) + { + pdc_printf(p->out, "/Encoding/MacRomanEncoding\n"); + break; + } + } + case fnt_Type3: + if (enc >= 0) + { + encinfo = pdc_get_encoding_info(p->pdc, enc); + if (encinfo->id == PDC_BAD_ID) + encinfo->id = pdc_alloc_id(p->out); + encoding_id = encinfo->id; + } + + if (encoding_id != PDC_BAD_ID) + pdc_objref(p->out, "/Encoding", encoding_id); + + if (encinfo != NULL) + { + if (!encinfo->stored) + encinfo->stored = pdc_true; + else + encoding_id = PDC_BAD_ID; + } + + break; + + case fnt_CIDFontType2: + case fnt_CIDFontType0: + if (font->outcmapname) + { + pdc_printf(p->out, "/Encoding/%s\n", font->outcmapname); + } + break; + + default: + break; + } + + /* /ToUnicode . Only reasonable if nusedgids != 1 + * (== 1: only notdef character in a font subset) + */ + + + /* /DescendantFonts */ + if (comp_font == pdc_true) + { + descendant_id = pdc_alloc_id(p->out); + pdc_puts(p->out, "/DescendantFonts"); + pdc_begin_array(p->out); + pdc_objref(p->out, "", descendant_id); + pdc_end_array(p->out); + } + + pdc_end_dict(p->out); /* font dict */ + pdc_end_obj(p->out); /* font obj */ + + /* + * Encoding dictionary + */ + if (encoding_id != PDC_BAD_ID) + { + char *glyphname; + + pdc_begin_obj(p->out, encoding_id); /* encoding obj */ + pdc_begin_dict(p->out); /* encoding dict */ + + pdc_puts(p->out, "/Type/Encoding\n"); + + { + pdc_encodingvector *evb = NULL; + + pdc_set_encoding_glyphnames(p->pdc, enc); + ev = pdc_get_encoding_vector(p->pdc, enc); + + /* See Implementation Note 46. The restrictions described there + * are also valid for Acrobat versions up to now. + */ + if (fonttype != fnt_Type3 && !font->used_in_formfield) + { + if (!strncmp(ev->apiname, PDC_ENC_MODWINANSI, + strlen(PDC_ENC_MODWINANSI)) || + !strncmp(ev->apiname, PDC_ENC_ISO8859, + strlen(PDC_ENC_ISO8859)) || + !strncmp(ev->apiname, PDC_ENC_CP125, + strlen(PDC_ENC_CP125))) + { + pdc_puts(p->out, "/BaseEncoding/WinAnsiEncoding\n"); + evb = pdc_get_encoding_vector(p->pdc, pdc_winansi); + } + else if (!strncmp(ev->apiname, PDC_ENC_MODMACROMAN, + strlen(PDC_ENC_MODMACROMAN))) + { + pdc_puts(p->out, "/BaseEncoding/MacRomanEncoding\n"); + evb = pdc_get_encoding_vector(p->pdc, pdc_macroman); + } + else + { + /* /BaseEncoding/StandardEncoding */ + evb = pdc_get_encoding_vector(p->pdc, pdc_stdenc); + } + } + + if (evb != NULL) + { + int iv = -1; + for (i = 0; i < font->ft.numcodes; i++) + { + glyphname = pdf_code2fontglyphname(font, ev, i); + + /* enforce first three names because of bug in Acrobat 6 */ + if (i < 3 || + (glyphname && !evb->chars[i]) || + (!glyphname && evb->chars[i]) || + (glyphname && evb->chars[i] && + strcmp(glyphname, evb->chars[i]))) + { + if (iv == -1) + pdc_puts(p->out, "/Differences[0"); + if (i > iv + 1) + pdc_printf(p->out, "%d", i); + pdf_put_pdfname(p, glyphname); + pdc_puts(p->out, "\n"); + iv = i; + } + } + if (iv > -1) + pdc_end_array(p->out); + } + else + { + pdc_puts(p->out, "/Differences[0"); + for (i = 0; i < font->ft.numcodes; i++) + { + glyphname = pdf_code2fontglyphname(font, ev, i); + pdf_put_pdfname(p, glyphname); + pdc_puts(p->out, "\n"); + } + pdc_end_array(p->out); + } + } + + pdc_end_dict(p->out); /* encoding dict */ + pdc_end_obj(p->out); /* encoding obj */ + + if (p->flush & pdc_flush_content) + pdc_flush_stream(p->out); + } + + + /* + * CID fonts dictionary + */ + if (descendant_id != PDC_BAD_ID) + { + pdc_begin_obj(p->out, descendant_id); /* CID font obj */ + pdc_begin_dict(p->out); /* CID font dict */ + pdc_puts(p->out, "/Type/Font\n"); + + /* /Subtype */ + if (fonttype == fnt_CIDFontType0) + pdc_puts(p->out, "/Subtype/CIDFontType0\n"); + if (fonttype == fnt_CIDFontType2) + pdc_puts(p->out, "/Subtype/CIDFontType2\n"); + + /* /BaseFont */ + pdc_puts(p->out, "/BaseFont"); + pdf_put_pdfname(p, fontname); + if (acro_fontstyle) + pdc_printf(p->out, ",%s", + pdc_get_keyword(font->opt.fontstyle, pdf_fontstyle_pdfkeylist)); + pdc_puts(p->out, "\n"); + + /* /CIDSystemInfo */ + pdc_puts(p->out, "/CIDSystemInfo<</Registry"); + pdf_put_hypertext(p, "Adobe"); + pdc_puts(p->out, "/Ordering"); + pdf_put_hypertext(p, fnt_get_ordering_cid(font->ft.m.charcoll)); + pdc_printf(p->out, "/Supplement %d>>\n", MAX(font->supplement, 0)); + + /* /FontDescriptor */ + fontdescriptor_id = pdc_alloc_id(p->out); + pdc_objref(p->out, "/FontDescriptor", fontdescriptor_id); + + + + /* /DW /W */ +#ifdef PDF_CJKFONTWIDTHS_SUPPORTED + if (font->ft.isstdfont) + pdf_put_cidglyph_widths(p, font); +#endif /* PDF_CJKFONTWIDTHS_SUPPORTED */ + + + pdc_end_dict(p->out); /* CID font dict */ + pdc_end_obj(p->out); /* CID font obj */ + + } + + + /* + * FontDescriptor dictionary + */ + if (fontdescriptor_id != PDC_BAD_ID) + pdf_write_fontdescriptor(p, font, missingwidth, fontdescriptor_id, + cidset_id, fontfile_id, nusedgids); + + + + /* + * Font embedding + */ + if (fontfile_id != PDC_BAD_ID) + { + pdc_id length1_id = PDC_BAD_ID; + pdc_id length2_id = PDC_BAD_ID; + pdc_id length3_id = PDC_BAD_ID; + pdc_bool compress = pdc_false; + + /* Prepare embedding */ + switch(fonttype) + { + case fnt_Type1: + case fnt_MMType1: + { + pdf_make_t1src(p, font, &src); + length1_id = pdc_alloc_id(p->out); + length2_id = pdc_alloc_id(p->out); + length3_id = pdc_alloc_id(p->out); + } + break; + +#ifdef PDF_TRUETYPE_SUPPORTED + case fnt_TrueType: + case fnt_CIDFontType2: + { + length1_id = pdc_alloc_id(p->out); + } + case fnt_Type1C: + case fnt_CIDFontType0: + case fnt_OpenType: + { + src.private_data = (void *) font->filename; + if (font->filename) + { + /* Read the font from file */ + src.init = pdf_data_source_file_init; + src.fill = pdf_data_source_file_fill; + src.terminate = pdf_data_source_file_terminate; + switch(fonttype) + { + case fnt_TrueType: + case fnt_CIDFontType2: + case fnt_OpenType: + src.offset = (long) 0; + src.length = (long) 0; + break; + + case fnt_Type1C: + case fnt_CIDFontType0: + src.offset = font->cff_offset; + src.length = (long) font->cff_length; + break; + + default: + break; + } + } + else + { + /* Read the font from memory */ + src.init = NULL; + src.fill = pdf_data_source_buf_fill; + src.terminate = NULL; + switch(fonttype) + { + case fnt_TrueType: + case fnt_CIDFontType2: + case fnt_OpenType: + src.buffer_start = font->ft.img; + src.buffer_length = font->ft.filelen; + break; + + case fnt_Type1C: + case fnt_CIDFontType0: + src.buffer_start = font->ft.img + font->cff_offset; + src.buffer_length = font->cff_length; + break; + + default: + break; + } + src.bytes_available = 0; + src.next_byte = NULL; + } + } + break; +#endif /* PDF_TRUETYPE_SUPPORTED */ + + default: + break; + } + + /* Embedded font stream dictionary */ + pdc_begin_obj(p->out, fontfile_id); /* Embedded font stream obj */ + pdc_begin_dict(p->out); /* Embedded font stream dict */ + + /* /Length, /Filter */ + length_id = pdc_alloc_id(p->out); + pdc_objref(p->out, "/Length", length_id); + switch(fonttype) + { + case fnt_Type1: + case fnt_MMType1: + break; + +#ifdef PDF_TRUETYPE_SUPPORTED + case fnt_TrueType: + case fnt_CIDFontType2: + case fnt_Type1C: + case fnt_CIDFontType0: + case fnt_OpenType: + if (font->ft.filelen != 0L) + { + compress = pdc_true; + if (pdc_get_compresslevel(p->out)) + pdc_puts(p->out, "/Filter/FlateDecode\n"); + } + break; +#endif /* PDF_TRUETYPE_SUPPORTED */ + + default: + break; + } + + /* /Length1, /Length2, Length3 */ + if (length1_id != PDC_BAD_ID) + pdc_objref(p->out, "/Length1", length1_id); + if (length2_id != PDC_BAD_ID) + pdc_objref(p->out, "/Length2", length2_id); + if (length3_id != PDC_BAD_ID) + pdc_objref(p->out, "/Length3", length3_id); + +#ifdef PDF_TRUETYPE_SUPPORTED + /* /Subtype */ + if(fonttype == fnt_Type1C) + pdc_puts(p->out, "/Subtype/Type1C\n"); + if (fonttype == fnt_CIDFontType0) + pdc_puts(p->out, "/Subtype/CIDFontType0C\n"); + if (fonttype == fnt_OpenType) + pdc_puts(p->out, "/Subtype/OpenType\n"); +#endif /* PDF_TRUETYPE_SUPPORTED */ + + + pdc_end_dict(p->out); /* Embedded font stream dict */ + + /* Stream */ + pdf_copy_stream(p, &src, compress); + + pdc_end_obj(p->out); /* Embedded font stream obj */ + + pdc_put_pdfstreamlength(p->out, length_id); + + /* Length objects */ + switch(fonttype) + { + case fnt_Type1: + case fnt_MMType1: + pdf_put_length_objs(p, &src, length1_id, length2_id, length3_id); + break; + +#ifdef PDF_TRUETYPE_SUPPORTED + case fnt_TrueType: + case fnt_CIDFontType2: + if (compress) + { + pdc_begin_obj(p->out, length1_id); /* Length1 obj */ + pdc_printf(p->out, "%ld\n", (long) font->ft.filelen); + pdc_end_obj(p->out); /* Length1 obj */ + } + else + { + /* same as /Length */ + pdc_put_pdfstreamlength(p->out, length1_id); + } + break; +#endif /* PDF_TRUETYPE_SUPPORTED */ + + default: + break; + } + } + + if (p->flush & pdc_flush_content) + pdc_flush_stream(p->out); + + /* restore font struct members */ + font->ft.enc = font_encoding; + font->ft.numcodes = font_numcodes; + font->codesize = font_codesize; + + pdc_pop_errmsg(p->pdc); +} + +void +pdf_write_doc_fonts(PDF *p) +{ + int slot; + pdc_bool logg1 = pdc_logg_is_enabled(p->pdc, 1, trc_font); + + /* output pending font objects */ + for (slot = 0; slot < p->fonts_number; slot++) + { + pdf_font *font = &p->fonts[slot]; + + switch(p->fonts[slot].ft.m.type) + { + case fnt_Type1: + case fnt_MMType1: +#ifdef PDF_TRUETYPE_SUPPORTED + case fnt_TrueType: + case fnt_CIDFontType2: + case fnt_Type1C: +#endif /* PDF_TRUETYPE_SUPPORTED */ + case fnt_CIDFontType0: + case fnt_Type3: + if (font->obj_id != PDC_BAD_ID) + { + if (logg1) + { + pdc_logg(p->pdc, + "\tProcessing font %d: \"%s\" " + "with encoding \"%s\" and PDF object id %ld", + slot, font->ft.name, + pdf_get_encoding_name(p, font->ft.enc, font), + font->obj_id); + } + + if (font->ft.enc == pdc_invalidenc || + font->used_in_current_doc == pdc_false) + { + if (logg1) + pdc_logg(p->pdc, " - but not used\n", font->obj_id); + + /* + * This font has been defined, but never used in the + * document. Ignore it. However, the font's object id + * has already been allocated, so we mark the object + * as free in order to avoid a complaint of the object + * machinery. + */ + pdc_mark_free(p->out, font->obj_id); + } + else + { + if (logg1) + pdc_logg(p->pdc, "\n"); + + pdf_put_font(p, font); + } + } + break; + + default: + break; + } + } +} + +void +pdf_write_page_fonts(PDF *p) +{ + int i, total = 0; + int bias = p->curr_ppt->fn_bias; + + /* This doesn't really belong here, but all modules which write + * font resources also need this, so we include it here. + * Note that keeping track of ProcSets is considered obsolete + * starting with PDF 1.4, so we always include the full set which + * is written as a constant object at the beginning of the file. + */ + + pdc_objref(p->out, "/ProcSet", p->procset_id); + + for (i = 0; i < p->fonts_number; i++) + if (p->fonts[i].used_on_current_page == pdc_true) + total++; + + if (total > 0 || bias) + { + pdc_puts(p->out, "/Font"); + pdc_begin_dict(p->out); /* font resource dict */ + } + + if (total > 0) + { + for (i = 0; i < p->fonts_number; i++) + { + if (p->fonts[i].used_on_current_page == pdc_true) { + p->fonts[i].used_on_current_page = pdc_false; /* reset */ + pdc_printf(p->out, "/F%d", bias + i); + pdc_objref(p->out, "", p->fonts[i].obj_id); + } + } + + if (!bias) + pdc_end_dict(p->out); /* font resource dict */ + } +} + +void +pdf_get_page_fonts(PDF *p, pdf_reslist *rl) +{ + int i; + + for (i = 0; i < p->fonts_number; i++) + { + if (p->fonts[i].used_on_current_page) + { + p->fonts[i].used_on_current_page = pdc_false; /* reset */ + pdf_add_reslist(p, rl, i); + } + } +} + +void +pdf_mark_page_font(PDF *p, int ft) +{ + p->fonts[ft].used_on_current_page = pdc_true; +} + + + |