/*---------------------------------------------------------------------------*
 |              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.461.2.80 2011/05/02 10:42:22 kurt 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;

    font->widths = NULL;
    font->numwidths = 0;
    font->konlydef = 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;
    }

    if (font->widths != NULL)
    {
        pdc_free(p->pdc, font->widths);
        font->widths = 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,
             const char *outfilename, pdc_encoding enc, pdc_bool checktimes)
{
    static const char fn[] = "pdf_get_metrics_core";
    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;

        if (font->apiname != NULL)
        {
            pdc_free(p->pdc, font->apiname);
            font->apiname = pdc_strdup_ext(p->pdc, fontname, 0, fn);
        }
    }

    ftm = fnt_get_core_metric(fontname);
    if (ftm != NULL && (!font->opt.embedding || outfilename != 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;
    fo->dropcorewidths = 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);


        pdc_get_optvalues("dropcorewidths", resopts, &fo->dropcorewidths, NULL);
}

int
pdf__load_font(PDF *p, const char *fontname, int len,
               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);

    /* initialize */
    pdf_init_font_options(p, &fo);

    /* Converting fontname */
    fo.fontname = (char *) pdf_convert_name(p, fontname, len,
                                            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 logg1 = pdc_logg_is_enabled(p->pdc, 1, trc_font);
    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;

    /* register and skip at sign '@' in font name */
    if (fo->fontname[0] == PDF_VERTICAL_SIGN ||
        (pdc_is_utf8_bytecode(fo->fontname) &&
         fo->fontname[3] == PDF_VERTICAL_SIGN))
    {

        i = (fo->fontname[0] == PDF_VERTICAL_SIGN) ? 1 : 4;
        len = strlen(fo->fontname) + 1 - i;
        memmove(&fo->fontname[i - 1], &fo->fontname[i], len);
    }

    /* 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_tmp(p->pdc, fontname_p);
    }
    fontname_p = NULL;

    if (logg1)
        pdc_logg(p->pdc, "\tCanonical font name: \"%s\"\n",
                 fontname);

    /* 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);

    if (logg1)
        pdc_logg(p->pdc, "\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_unicode || enc == pdc_glyphid)
    {
        pdc_set_errmsg(p->pdc, PDF_E_UNSUPP_UNICODE, 0, 0, 0, 0);
        goto PDF_PREMATURE_EXIT;
    }

    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.
     */

    if (logg1)
        pdc_logg(p->pdc, "\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;
    if (logg1)
        pdc_logg(p->pdc, "\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 */
    }
    fontname_p = mastername;

    /* protocol */
    if (logg1)
        pdc_logg(p->pdc, "\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)
    {
        if (font->opt.auxiliary)
        {
            /* only in-core fonts are possible */
            retval = pdf_get_metrics_core(p, font, fontname_p, "", enc,
                                          pdc_false);
            break;
        }

#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 - will be skipped
         * in the case of embedding and missing outline file
         * to check the possibility of an host font in the next step.
         */
        retval = pdf_get_metrics_core(p, font, fontname_p, outfilename, 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 */
        if (logg1)
            pdc_logg(p->pdc, "\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;

            if (logg1)
                pdc_logg(p->pdc,
                         "\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 */
                if (logg1)
                    pdc_logg(p->pdc,
                             "\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;
                    if (font->ft.m.type == fnt_Type1 ||
                        font->ft.m.type == fnt_MMType1)
                        pdc_set_errmsg(p->pdc, PDF_E_FONT_NOOUTLINE_PS,
                                       0, 0, 0, 0);
                    else
                        pdc_set_errmsg(p->pdc, PDF_E_FONT_NOOUTLINE_TT,
                                       0, 0, 0, 0);
                }
            }

            if (retval == pdc_false)
            {
                    if (logg1)
                        pdc_logg(p->pdc,
                            "\tOutline data file for font \"%s\" not found\n",
                            fontname_p);
            }
            else
            {
                if (!font->ft.img)
                    font->filename = font->ft.filename;

                    if (logg1)
                        pdc_logg(p->pdc,
                                "\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));
}

void
pdf_prepare_fontwidths(PDF *p, pdf_font *font, int nusedgids)
{

    (void) p;
    (void) nusedgids;

    if (font->towinansi != pdc_invalidenc || font->widths != NULL ||
        (font->iscidfont && (font->ft.isstdfont || font->opt.monospace)))
    {
        return;
    }

    /* exchange widths pointer */
    if (!font->iscidfont && font->ft.enc != pdc_unicode)
    {
        font->widths = font->ft.m.widths;
        font->numwidths = font->ft.m.numwidths;
        font->ft.m.widths = NULL;
        font->ft.m.numwidths = 0;
        return;
    }

    /* already defined or no basic data */
    if (font->ft.m.widths == NULL && font->ft.m.ciw == NULL
       )
    {
        return;
    }

}



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);

    if (font->ft.m.type != fnt_Type3)
        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));

    if (font->ft.m.type != fnt_Type3)
        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;
    pdc_encoding       font_towinansi = font->towinansi;
    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;
        font->towinansi = pdc_invalidenc;
    }

    /* preparation for font widths array */
    pdf_prepare_fontwidths(p, font, nusedgids);

    /* /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);

                /* bug #1036 */
                if (font->ft.isstdfont == pdc_true && font->opt.dropcorewidths)
                    break;
            }

            /* 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 && !font->used_in_formfield)
            {
                if (fonttype != fnt_Type3)
                    defwidth = font->widths[0];

                {
                    for (i = 1; i < 255; i++)
                    {
                        if (font->widths[i] != defwidth)
                            break;
                    }
                    if (i > 1)
                        firstchar = i;
                    for (i = 255; i > 0; i--)
                    {
                        if (i == firstchar || font->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->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->towinansi = font_towinansi;
    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;

    /* 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)
    {
        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", i);
                pdc_objref(p->out, "", p->fonts[i].obj_id);
            }
	}

	    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;
}
