Commit message: txtwrite - guard against using GS_NO_GLYPH to retrieve Unicode values

Bug 701822 "Segmentation fault at psi/iname.c:296 in names_index_ref"

Avoid using a glyph with the value GS_NO_GLYPH to retrieve a glyph
name or Unicode code point from the glyph ID, as this is not a valid
ID.
CVE: CVE-2020-16307
CWE: CWE-476
Vulnerability description: A null pointer dereference vulnerability in devices/vector/gdevtxtw.c and psi/zbfont.c of Artifex Software GhostScript v9.50 allows a remote attacker to cause a denial of service via a crafted postscript file. This is fixed in v9.51.

Project: ghostpdl
File: zbfont.c

CLEAR_MARKS_PROC(font_data_clear_marks)
{
    ref_struct_clear_marks(cmem, vptr, offset_of(font_data, u.type42.mru_sfnts_index)/*size*/, pstype);
}

Project: ghostpdl
File: gdevtxtw.c

static int write_simple_text(unsigned short *text, int count, gx_device_txtwrite_t *tdev)
{
    switch(tdev->TextFormat) {
        case 2:
            gp_fwrite(text, sizeof (unsigned short), count, tdev->file);
            break;
        case 3:
            {
                int i;
                unsigned short *UTF16 = (unsigned short *)text;
                unsigned char UTF8[3];

                for (i=0;i<count;i++) {
                    if (*UTF16 < 0x80) {
                        UTF8[0] = *UTF16 & 0xff;
                        gp_fwrite (UTF8, sizeof(unsigned char), 1, tdev->file);
                    } else {
                        if (*UTF16 < 0x800) {
                            UTF8[0] = (*UTF16 >> 6) + 0xC0;
                            UTF8[1] = (*UTF16 & 0x3F) + 0x80;
                            gp_fwrite (UTF8, sizeof(unsigned char), 2, tdev->file);
                        } else {
                            UTF8[0] = (*UTF16 >> 12) + 0xE0;
                            UTF8[1] = ((*UTF16 >> 6) & 0x3F) + 0x80;
                            UTF8[2] = (*UTF16 & 0x3F) + 0x80;
                            gp_fwrite (UTF8, sizeof(unsigned char), 3, tdev->file);
                        }
                    }
                    UTF16++;
                }
            }
            break;
        default:
            return gs_note_error(gs_error_rangecheck);
            break;
    }
    return 0;
}

Project: ghostpdl
File: zbfont.c

sub_font_params(gs_memory_t *mem, const ref *op, gs_matrix *pmat, gs_matrix *pomat, ref *pfname)
{
    ref *pmatrix, *pfontname, *pfontstyle, *porigfont, *pfontinfo;

    if (dict_find_string(op, "FontMatrix", &pmatrix) <= 0 ||
        read_matrix(mem, pmatrix, pmat) < 0
        )
        return_error(gs_error_invalidfont);
    if (dict_find_string(op, "OrigFont", &porigfont) <= 0)
        porigfont = NULL;
    if (porigfont != NULL && !r_has_type(porigfont, t_dictionary))
        return_error(gs_error_typecheck);

    if (pomat!= NULL) {
        if (porigfont == NULL ||
            dict_find_string(porigfont, "FontMatrix", &pmatrix) <= 0 ||
            read_matrix(mem, pmatrix, pomat) < 0
            )
            memset(pomat, 0, sizeof(*pomat));
    }
    /* Use the FontInfo/OrigFontName key preferrentially (created by MS PSCRIPT driver) */
    if ((dict_find_string((porigfont != NULL ? porigfont : op), "FontInfo", &pfontinfo) > 0) &&
        r_has_type(pfontinfo, t_dictionary) &&
        (dict_find_string(pfontinfo, "OrigFontName", &pfontname) > 0) && (r_has_type(pfontname, t_name) || r_has_type(pfontname, t_string))) {
        if ((dict_find_string(pfontinfo, "OrigFontStyle", &pfontstyle) > 0) && (r_has_type(pfontname, t_name) || r_has_type(pfontname, t_string)) &&
                r_size(pfontstyle) > 0) {
            const byte *tmpStr1 = pfontname->value.const_bytes;
            const byte *tmpStr2 = pfontstyle->value.const_bytes;
            int fssize1 = r_size(pfontname), fssize2 = r_size(pfontstyle), fssize = fssize1 + fssize2 + 1;
            byte *sfname = gs_alloc_string(mem, fssize, "sub_font_params");

            if (sfname == NULL)
                return_error(gs_error_VMerror);
            memcpy(sfname, tmpStr1, fssize1);
            sfname[fssize1]=',' ;
            memcpy(sfname + fssize1 + 1, tmpStr2, fssize2);
            make_string(pfname, a_readonly, fssize, sfname);
        } else
            get_font_name(mem, pfname, pfontname);
    } else if (dict_find_string((porigfont != NULL ? porigfont : op), ".Alias", &pfontname) > 0) {
        /* If we emulate the font, we want the requested name rather than a substitute. */
        get_font_name(mem, pfname, pfontname);
    } else if (dict_find_string((porigfont != NULL ? porigfont : op), "FontName", &pfontname) > 0) {
        get_font_name(mem, pfname, pfontname);
    } else
        make_empty_string(pfname, a_readonly);
    return 0;
}

Project: ghostpdl
File: zbfont.c

build_gs_sub_font(i_ctx_t *i_ctx_p, const ref *op, gs_font **ppfont,
                  font_type ftype, gs_memory_type_ptr_t pstype,
                  const build_proc_refs * pbuild, const ref *pencoding,
                  ref *fid_op)
{
    gs_matrix mat, omat;
    ref fname;			/* t_string */
    gs_font *pfont;
    font_data *pdata;
    /*
     * Make sure that we allocate the font data
     * in the same VM as the font dictionary.
     */
    uint space = ialloc_space(idmemory);
    int code = sub_font_params(imemory, op, &mat, &omat, &fname);

    if (code < 0)
        return code;
    ialloc_set_space(idmemory, r_space(op));
    pfont = gs_font_alloc(imemory, pstype, &gs_font_procs_default, NULL,
                          "buildfont(font)");
    pdata = ialloc_struct(font_data, &st_font_data,
                          "buildfont(data)");
    if (pfont == 0 || pdata == 0)
        code = gs_note_error(gs_error_VMerror);
    else if (fid_op)
        code = add_FID(i_ctx_p, fid_op, pfont, iimemory);
    if (code < 0) {
        ifree_object(pdata, "buildfont(data)");
        ifree_object(pfont, "buildfont(font)");
        ialloc_set_space(idmemory, space);
        return code;
    }
    refset_null((ref *) pdata, sizeof(font_data) / sizeof(ref));
    ref_assign_new(&pdata->dict, op);
    ref_assign_new(&pdata->BuildChar, &pbuild->BuildChar);
    ref_assign_new(&pdata->BuildGlyph, &pbuild->BuildGlyph);
    if (pencoding)
        ref_assign_new(&pdata->Encoding, pencoding);
    pfont->client_data = pdata;
    pfont->FontType = ftype;
    pfont->FontMatrix = mat;
    pfont->orig_FontMatrix = omat;
    pfont->BitmapWidths = false;
    pfont->ExactSize = fbit_use_bitmaps;
    pfont->InBetweenSize = fbit_use_outlines;
    pfont->TransformedChar = fbit_use_outlines;
    pfont->WMode = 0;
    pfont->procs.encode_char = zfont_encode_char;
    pfont->procs.glyph_name = zfont_glyph_name;
    ialloc_set_space(idmemory, space);
    copy_font_name(&pfont->font_name, &fname);
    *ppfont = pfont;
    return 0;
}

Project: ghostpdl
File: zbfont.c

copy_font_name(gs_font_name * pfstr, const ref * pfname)
{
    uint size = r_size(pfname);

    if (size > gs_font_name_max)
        size = gs_font_name_max;
    memcpy(&pfstr->chars[0], pfname->value.const_bytes, size);
    /* Following is only for debugging printout. */
    pfstr->chars[size] = 0;
    pfstr->size = size;
}

Project: ghostpdl
File: gdevtxtw.c

txtwrite_dev_spec_op(gx_device *pdev, int dev_spec_op, void *data, int size)
{
    switch (dev_spec_op) {
        case gxdso_get_dev_param:
            {
                int code;
                dev_param_req_t *request = (dev_param_req_t *)data;
                code = txtwrite_get_param(pdev, request->Param, request->list);
                if (code != gs_error_undefined)
                    return code;
            }
    }
    return gx_default_dev_spec_op(pdev, dev_spec_op, data, size);
}

Project: ghostpdl
File: zbfont.c

define_gs_font(i_ctx_t *i_ctx_p, gs_font * pfont)
{
    return (pfont->base == pfont && pfont->dir == 0 ?
            /* i.e., unregistered original font */
            gs_definefont(ifont_dir, pfont) :
            0);
}

Project: ghostpdl
File: zbfont.c

get_GlyphNames2Unicode(i_ctx_t *i_ctx_p, gs_font *pfont, ref *pdref)
{
    ref *pfontinfo = NULL, *g2u = NULL;
    font_data *pdata;

    if (dict_find_string(pdref, "FontInfo", &pfontinfo) <= 0 ||
            !r_has_type(pfontinfo, t_dictionary) ||
            dict_find_string(pfontinfo, "GlyphNames2Unicode", &g2u) <= 0 ||
            !r_has_type(pfontinfo, t_dictionary))
        return;
    /*
     * Since build_gs_font may resize the dictionary and cause
     * pointers to become invalid, save Glyph2Unicode
     */
    pdata = pfont_data(pfont);
    ref_assign_new(&pdata->GlyphNames2Unicode, g2u);
}

Project: ghostpdl
File: zbfont.c

ENUM_PTRS_BEGIN_PROC(font_data_enum_ptrs)
{
    return ref_struct_enum_ptrs(mem, vptr, offset_of(font_data, u.type42.mru_sfnts_index)/*size*/, index, pep, pstype, gcst);
}

Project: ghostpdl
File: zbfont.c

build_proc_name_refs(const gs_memory_t *mem, build_proc_refs * pbuild,
                     const char *bcstr, const char *bgstr)
{
    int code;

    if (!bcstr)
        make_null(&pbuild->BuildChar);
    else {
        if ((code = name_ref(mem, (const byte *)bcstr,
                             strlen(bcstr), &pbuild->BuildChar, 0)) < 0)
            return code;
        r_set_attrs(&pbuild->BuildChar, a_executable);
    }
    if (!bgstr)
        make_null(&pbuild->BuildGlyph);
    else {
        if ((code = name_ref(mem, (const byte *)bgstr,
                             strlen(bgstr), &pbuild->BuildGlyph, 0)) < 0)
            return code;
        r_set_attrs(&pbuild->BuildGlyph, a_executable);
    }
    return 0;
}

Project: ghostpdl
File: zbfont.c

gs_font_map_glyph_to_unicode(gs_font *font, gs_glyph glyph, int ch, ushort *u, unsigned int length)
{
    font_data *pdata = pfont_data(font);
    const ref *UnicodeDecoding;
    uchar *unicode_return = (uchar *)u;

    if (r_type(&pdata->GlyphNames2Unicode) == t_dictionary) {
        int c = gs_font_map_glyph_by_dict(font->memory,
                                              &pdata->GlyphNames2Unicode, glyph, u, length);

        if (c != 0)
            return c;
        if (ch != -1) { /* -1 indicates a CIDFont */
            /* Its possible that we have a GlyphNames2Unicode dictionary
             * which contains integers and Unicode values, rather than names
             * and Unicode values. This happens if the input was PDF, the font
             * has a ToUnicode Cmap, but no Encoding. In this case we need to
             * use the character code as an index into the dictionary. Try that
             * now before we fall back to the UnicodeDecoding.
             */
            ref *v, n;

            make_int(&n, ch);
            if (dict_find(&pdata->GlyphNames2Unicode, &n, &v) > 0) {
                if (r_has_type(v, t_string)) {
                    int l = r_size(v);

                    if (l > length)
                        return l;

                    memcpy(unicode_return, v->value.const_bytes, l * sizeof(short));
                    return l;
                }
                if (r_type(v) == t_integer) {
                    if (v->value.intval > 65535) {
                        if (length < 4)
                            return 4;
                        unicode_return[0] = v->value.intval >> 24;
                        unicode_return[1] = (v->value.intval & 0x00FF0000) >> 16;
                        unicode_return[2] = (v->value.intval & 0x0000FF00) >> 8;
                        unicode_return[3] = v->value.intval & 0xFF;
                        return 4;
                    } else {
                        if (length < 2)
                            return 2;
                        unicode_return[0] = v->value.intval >> 8;
                        unicode_return[1] = v->value.intval & 0xFF;
                        return 2;
                    }
                }
            }
        }
        /*
         * Fall through, because test.ps for SF bug #529103 requres
         * to examine both tables. Due to that the Unicode Decoding resource
         * can't be a default value for FontInfo.GlyphNames2Unicode .
         */
    }
    if (glyph <= GS_MIN_CID_GLYPH && glyph != GS_NO_GLYPH) {
        UnicodeDecoding = zfont_get_to_unicode_map(font->dir);
        if (UnicodeDecoding != NULL && r_type(UnicodeDecoding) == t_dictionary)
            return gs_font_map_glyph_by_dict(font->memory, UnicodeDecoding, glyph, u, length);
    }
    return 0; /* No map. */
}

Project: ghostpdl
File: gdevtxtw.c

txtwrite_text_begin(gx_device * dev, gs_gstate * pgs,
                const gs_text_params_t * text, gs_font * font,
                gx_path * path, const gx_device_color * pdcolor,
                const gx_clip_path * pcpath,
                gs_memory_t * mem, gs_text_enum_t ** ppenum)
{
    gx_device_txtwrite_t *const tdev = (gx_device_txtwrite_t *) dev;
    textw_text_enum_t *penum;
    int code;

    /* If this is a stringwidth, we must let the default graphics library code handle it
     * in case there is no current point (this can happen if this is the first operation
     * we get, the current font is a CIDFont, and its descendant is a substitute type 1
     * font). If there is no current point we throw an error in text_process and that
     * messes up all the font handling. The test below is copied from pdfwrite
     * (gdev_pdf_text_begin) and seems to do the job.
     */
    if ((!(text->operation & TEXT_DO_DRAW) && pgs->text_rendering_mode != 3)
                    || path == 0 || !path_position_valid(path))
            return gx_default_text_begin(dev, pgs, text, font, path, pdcolor,
                                         pcpath, mem, ppenum);
    /* Allocate and initialize one of our text enumerators. */
    rc_alloc_struct_1(penum, textw_text_enum_t, &st_textw_text_enum, mem,
                      return_error(gs_error_VMerror), "gdev_textw_text_begin");
    penum->rc.free = rc_free_text_enum;
    penum->charproc_accum = false;
    penum->cdevproc_callout = false;
    penum->returned.total_width.x = penum->returned.total_width.y = 0;
    penum->TextBuffer = NULL;
    penum->TextBufferIndex = 0;
    penum->Widths = NULL;
    /* The enumerator's text_release method frees this memory */
    penum->text_state = (text_list_entry_t *)gs_malloc(tdev->memory->stable_memory, 1,
            sizeof(text_list_entry_t), "txtwrite alloc text state");
    if (!penum->text_state)
        return gs_note_error(gs_error_VMerror);
    memset(penum->text_state, 0x00, sizeof(text_list_entry_t));

    code = gs_text_enum_init((gs_text_enum_t *)penum, &textw_text_procs,
                             dev, pgs, text, font, path, pdcolor, pcpath, mem);
    if (code < 0) {
        /* Belt and braces; I'm not certain this is required, but its safe */
        gs_free(tdev->memory, penum->text_state, 1, sizeof(text_list_entry_t), "txtwrite free text state");
        penum->text_state = NULL;
        gs_free_object(mem, penum, "textwrite_text_begin");
        return code;
    }

    code = gx_path_current_point(penum->path, &penum->origin);
    if (code != 0)
       return code;

    *ppenum = (gs_text_enum_t *)penum;

    return 0;
}

Project: ghostpdl
File: gdevtxtw.c

static int merge_horizontally(gx_device_txtwrite_t *tdev)
{
#ifdef TRACE_TXTWRITE
    text_list_entry_t *debug_x;
#endif
    unsigned short UnicodeSpace = 0x20;
    page_text_list_t *y_list = tdev->PageData.y_ordered_list;

    while (y_list) {
        float average_width;
        text_list_entry_t *from, *to;
        from = y_list->x_ordered_list;
        to = from->next;

        while (from && to) {
            average_width = (from->end.x - from->start.x) / from->Unicode_Text_Size;

            if (to->start.x - from->end.x < average_width / 2) {
                /* consolidate fragments */
                unsigned short *NewText;
                float *NewWidths;

                NewText = (unsigned short *)gs_malloc(tdev->memory->stable_memory,
                    (from->Unicode_Text_Size + to->Unicode_Text_Size), sizeof(unsigned short), "txtwrite alloc working text buffer");
                NewWidths = (float *)gs_malloc(tdev->memory->stable_memory,
                    (from->Unicode_Text_Size + to->Unicode_Text_Size), sizeof(float), "txtwrite alloc Widths array");
                if (!NewText || !NewWidths) {
                    if (NewText)
                        gs_free(tdev->memory, NewText, from->Unicode_Text_Size + to->Unicode_Text_Size, sizeof (unsigned short), "free working text fragment");
                    /* ran out of memory, don't consolidate */
                    from = from->next;
                    to = to->next;
                } else {
#ifdef TRACE_TXTWRITE
                    gp_fprintf(tdev->DebugFile, "Consolidating two horizontal fragments in one line, before:\n\t");
                    gp_fwrite(from->Unicode_Text, sizeof(unsigned short), from->Unicode_Text_Size, tdev->DebugFile);
                    gp_fprintf(tdev->DebugFile, "\n\t");
                    gp_fwrite(to->Unicode_Text, sizeof(unsigned short), to->Unicode_Text_Size, tdev->DebugFile);
#endif
                    memcpy(NewText, from->Unicode_Text, from->Unicode_Text_Size * sizeof(unsigned short));
                    memcpy(&NewText[from->Unicode_Text_Size], to->Unicode_Text, to->Unicode_Text_Size * sizeof(unsigned short));
                    memcpy(NewWidths, from->Widths, from->Unicode_Text_Size * sizeof(float));
                    memcpy(&NewWidths[from->Unicode_Text_Size], to->Widths, to->Unicode_Text_Size * sizeof(float));
                    gs_free(tdev->memory, from->Unicode_Text, from->Unicode_Text_Size, sizeof (unsigned short), "free consolidated text fragment");
                    gs_free(tdev->memory, to->Unicode_Text, to->Unicode_Text_Size, sizeof (unsigned short), "free consolidated text fragment");
                    gs_free(tdev->memory, from->Widths, from->Unicode_Text_Size, sizeof (float), "free consolidated Widths array");
                    gs_free(tdev->memory, to->Widths, to->Unicode_Text_Size, sizeof (float), "free consolidated Widths array");
                    gs_free(tdev->memory, to->FontName, 1, strlen(from->FontName) + 1, "free FontName");
                    from->Unicode_Text = NewText;
                    from->Unicode_Text_Size += to->Unicode_Text_Size;
                    from->Widths = NewWidths;
#ifdef TRACE_TXTWRITE
                    gp_fprintf(tdev->DebugFile, "After:\n\t");
                    gp_fwrite(from->Unicode_Text, sizeof(unsigned short), from->Unicode_Text_Size, tdev->DebugFile);
#endif
                    from->end = to->end;
                    from->next = to->next;
                    if (from->next)
                        from->next->previous = from;
                    gs_free(tdev->memory, to, 1, sizeof(text_list_entry_t), "free consolidated fragment");
                    to = from->next;
                }
            } else {
                if (to->start.x - from->end.x < average_width *2){
                    unsigned short *NewText;
                    float *NewWidths;

                    NewText = (unsigned short *)gs_malloc(tdev->memory->stable_memory,
                        (from->Unicode_Text_Size + to->Unicode_Text_Size + 1), sizeof(unsigned short), "txtwrite alloc text state");
                    NewWidths = (float *)gs_malloc(tdev->memory->stable_memory,
                        (from->Unicode_Text_Size + to->Unicode_Text_Size + 1), sizeof(float), "txtwrite alloc Widths array");
                    if (!NewText || !NewWidths) {
                        if (NewText)
                            gs_free(tdev->memory, NewText, from->Unicode_Text_Size + to->Unicode_Text_Size, sizeof (unsigned short), "free working text fragment");
                        /* ran out of memory, don't consolidate */
                        from = from->next;
                        to = to->next;
                    } else {
                        memcpy(NewText, from->Unicode_Text, from->Unicode_Text_Size * sizeof(unsigned short));
                        memcpy(&NewText[from->Unicode_Text_Size], &UnicodeSpace, sizeof(unsigned short));
                        memcpy(&NewText[from->Unicode_Text_Size + 1], to->Unicode_Text, to->Unicode_Text_Size * sizeof(unsigned short));
                        memcpy(NewWidths, from->Widths, from->Unicode_Text_Size * sizeof(float));
                        NewWidths[from->Unicode_Text_Size] = to->start.x - from->end.x;
                        memcpy(&NewWidths[from->Unicode_Text_Size + 1], to->Widths, to->Unicode_Text_Size * sizeof(float));
                        gs_free(tdev->memory, from->Unicode_Text, from->Unicode_Text_Size, sizeof (unsigned short), "free consolidated text fragment");
                        gs_free(tdev->memory, to->Unicode_Text, to->Unicode_Text_Size, sizeof (unsigned short), "free consolidated text fragment");
                        gs_free(tdev->memory, from->Widths, from->Unicode_Text_Size, sizeof (float), "free consolidated Widths array");
                        gs_free(tdev->memory, to->Widths, to->Unicode_Text_Size, sizeof (float), "free consolidated Widths array");
                        gs_free(tdev->memory, to->FontName, 1, strlen(from->FontName) + 1, "free FontName");
                        from->Unicode_Text = NewText;
                        from->Unicode_Text_Size += to->Unicode_Text_Size + 1;
                        from->Widths = NewWidths;
                        from->end = to->end;
                        from->next = to->next;
                        if (from->next)
                            from->next->previous = from;
                        gs_free(tdev->memory, to, 1, sizeof(text_list_entry_t), "free consolidated fragment");
                        to = from->next;
                    }
                } else {
                    from = from->next;
                    to = to->next;
                }
            }
        }
        y_list = y_list->next;
    }
    return 0;
}

Project: ghostpdl
File: zbfont.c

build_gs_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font ** ppfont, font_type ftype,
              gs_memory_type_ptr_t pstype, const build_proc_refs * pbuild,
              build_font_options_t options)
{
    ref kname;			/* t_string */
    ref *pftype;
    ref *pencoding = 0;
    bool bitmapwidths;
    int exactsize, inbetweensize, transformedchar;
    int wmode;
    int code;
    gs_font *pfont;
    ref *pfid;
    ref *aop = dict_access_ref(op);
    bool cpsi_mode = gs_currentcpsimode(imemory);

    get_font_name(imemory, &kname, op - 1);
    if (dict_find_string(op, "FontType", &pftype) <= 0 ||
        !r_has_type(pftype, t_integer) ||
        pftype->value.intval != (int)ftype
        )
        return_error(gs_error_invalidfont);
    if (dict_find_string(op, "Encoding", &pencoding) <= 0) {
        if (!(options & bf_Encoding_optional))
            return_error(gs_error_invalidfont);
        pencoding = 0;
    } else {
        if (!r_is_array(pencoding))
            return_error(gs_error_invalidfont);
    }
    if (pencoding) {   /* observed Adobe behavior */
        int count = r_size(pencoding);
        int type = ftype ? t_name : t_integer;
        bool fixit = false;

        while (count--) {
           ref r;
           if ((code = array_get(imemory, pencoding, count, &r)) < 0 ||
             !(r_has_type(&r, type) || r_has_type(&r, t_null))) {
               if (!cpsi_mode && ftype == ft_user_defined) {
                   if (code < 0 || r_has_type(&r, t_null)) {
                       return_error(gs_error_typecheck);
                   }
                   fixit = true;
                   break;
               }
               else {
                   return_error(gs_error_typecheck);
               }
           }
        }

        /* For at least Type 3 fonts, Adobe Distiller will "fix" an Encoding array, as in, for example
         * Bug 692681 where the arrays contain integers rather than names. Once the font is instantiated
         * the integers have been converted to names.
         * It is preferable to to this manipulation here, rather than in Postscript, because we are less
         * restricted by read-only attributes and VM save levels.
         */
        if (fixit) {
            ref penc;
            uint size = 0;
            char buf[32], *bptr;
            avm_space curglob = ialloc_space(idmemory);
            avm_space useglob = r_is_local(pencoding) ? avm_local : avm_global;

            ialloc_set_space(idmemory, useglob);

            count = r_size(pencoding);
            if ((code = ialloc_ref_array(&penc, (r_type_attrs(pencoding) & a_readonly), count, "build_gs_font")) < 0)
                 return code;

            while (count--) {
               ref r;
               if (array_get(imemory, pencoding, count, &r) < 0){
                   return_error(gs_error_typecheck);
               }
               /* For type 3, we know the Encoding entries must be names */
               if (r_has_type(&r, t_name)){
                   ref_assign(&(penc.value.refs[count]), &r);
               }
               else {

                   if ((code = obj_cvs(imemory, &r, (byte *)buf, 32, &size, (const byte **)(&bptr))) < 0) {
                       return(code);
                   }
                   if ((code = name_ref(imemory, (const byte *)bptr, size, &r, true)) < 0)
                        return code;
                   ref_assign(&(penc.value.refs[count]), &r);
               }
            }

            if ((code = dict_put_string(osp, "Encoding", &penc, NULL)) < 0)
               return code;
            ialloc_set_space(idmemory, curglob);
        }
    }
    if ((code = dict_int_param(op, "WMode", 0, 1, 0, &wmode)) < 0 ||
        (code = dict_bool_param(op, "BitmapWidths", false, &bitmapwidths)) < 0 ||
        (code = dict_int_param(op, "ExactSize", 0, 2, fbit_use_bitmaps, &exactsize)) < 0 ||
        (code = dict_int_param(op, "InBetweenSize", 0, 2, fbit_use_outlines, &inbetweensize)) < 0 ||
        (code = dict_int_param(op, "TransformedChar", 0, 2, fbit_use_outlines, &transformedchar)) < 0
        )
        return code;
    code = dict_find_string(op, "FID", &pfid);
    if (code > 0 && r_has_type(pfid, t_fontID)) { /* silently ignore invalid FID per CET 13-05.ps */
        /*
         * If this font has a FID entry already, it might be a scaled font
         * made by makefont or scalefont; in a Level 2 environment, it might
         * be an existing font being registered under a second name, or a
         * re-encoded font (which was invalid in Level 1, but dvips did it
         * anyway).
         */
        pfont = r_ptr(pfid, gs_font);
        /*
         * If the following condition is false this is a re-encoded font,
         * or some other questionable situation in which the FID
         * was preserved.  Pretend the FID wasn't there.
         */
        if (obj_eq(pfont->memory, pfont_dict(pfont), op)) {
            if (pfont->base == pfont) {	/* original font */
                if (!level2_enabled)
                    return_error(gs_error_invalidfont);
                *ppfont = pfont;
                return 1;
            } else {		/* This was made by makefont or scalefont. */
                /* Just insert the new name. */
                gs_matrix mat;
                ref fname;			/* t_string */

                code = sub_font_params(imemory, op, &mat, NULL, &fname);
                if (code < 0)
                    return code;
                code = 1;
                copy_font_name(&pfont->font_name, &fname);
                goto set_name;
            }
        }
    }
    /* This is a new font. */
    if (!r_has_attr(aop, a_write))
        return_error(gs_error_invalidaccess);
    {
        ref encoding;

        /*
         * Since add_FID may resize the dictionary and cause
         * pencoding to become invalid, save the Encoding.
         */
        if (pencoding) {
            encoding = *pencoding;
            pencoding = &encoding;
        }
        code = build_gs_sub_font(i_ctx_p, op, &pfont, ftype, pstype,
                                 pbuild, pencoding, op);
        if (code < 0)
            return code;
    }
    pfont->BitmapWidths = bitmapwidths;
    pfont->ExactSize = (fbit_type)exactsize;
    pfont->InBetweenSize = (fbit_type)inbetweensize;
    pfont->TransformedChar = (fbit_type)transformedchar;
    pfont->WMode = wmode;
    pfont->procs.font_info = zfont_info;
    code = 0;
set_name:
    copy_font_name(&pfont->key_name, &kname);
    *ppfont = pfont;
    return code;
}

Project: ghostpdl
File: gdevtxtw.c

textw_text_process(gs_text_enum_t *pte)
{
    textw_text_enum_t *const penum = (textw_text_enum_t *)pte;
    gx_device_txtwrite_t *const tdev = (gx_device_txtwrite_t *) pte->dev;
    gs_font *font = pte->orig_font;
    gs_font_base *font_base = (gs_font_base *)pte->current_font;
    int code = 0;

    if (pte->text.size == 0)
        return 0;

    if (!penum->TextBuffer) {
        /* We can get up to 4 Unicode points per glyph, and a glyph can be
         * be represented by as little as one byte. So we make a very large
         * temporary buffer to hold the Unicode string as we assemble it. When
         * we copy it to the text fragment we will allocate only as many bytes
         * as are required to hold the actual nukmber of Unicode values we
         * decoded, and this temporary buffer will be discarded.
         */
        penum->TextBuffer = (unsigned short *)gs_malloc(tdev->memory->stable_memory,
            pte->text.size * 4, sizeof(unsigned short), "txtwrite temporary text buffer");
        if (!penum->TextBuffer)
            return gs_note_error(gs_error_VMerror);
        penum->Widths = (float *)gs_malloc(tdev->memory->stable_memory,
            pte->text.size, sizeof(float), "txtwrite temporary widths array");
        if (!penum->Widths)
            return gs_note_error(gs_error_VMerror);
    }
    {
        switch (font->FontType) {
        case ft_CID_encrypted:
        case ft_CID_TrueType:
        case ft_composite:
              code = txtwrite_process_cmap_text(pte);
            break;
        case ft_encrypted:
        case ft_encrypted2:
        case ft_TrueType:
        case ft_user_defined:
        case ft_PCL_user_defined:
        case ft_GL2_stick_user_defined:
        case ft_GL2_531:
            code = txtwrite_process_plain_text(pte);
            break;
        default:
	  return_error(gs_error_rangecheck);
            break;
        }
        if (code == 0) {
            if (font_base->FontBBox.p.x != font_base->FontBBox.q.x ||
                font_base->FontBBox.p.y != font_base->FontBBox.q.y) {
                gs_point p0, p1, p2, p3;
                gs_matrix m;

                m = ctm_only(pte->pgs);
                m.tx = m.ty = fixed2float(0);
                gs_matrix_multiply(&font_base->FontMatrix, &m, &m);
                gs_point_transform(font_base->FontBBox.p.x, font_base->FontBBox.p.y, &m, &p0);
                gs_point_transform(font_base->FontBBox.p.x, font_base->FontBBox.q.y, &m, &p1);
                gs_point_transform(font_base->FontBBox.q.x, font_base->FontBBox.p.y, &m, &p2);
                gs_point_transform(font_base->FontBBox.q.x, font_base->FontBBox.q.y, &m, &p3);
                penum->text_state->FontBBox_bottomleft.x = min(min(p0.x, p1.x), min(p1.x, p2.x));
                penum->text_state->FontBBox_topright.x = max(max(p0.x, p1.x), max(p1.x, p2.x));
                penum->text_state->FontBBox_bottomleft.y = min(min(p0.y, p1.y), min(p1.y, p2.y));
                penum->text_state->FontBBox_topright.y = max(max(p0.y, p1.y), max(p1.y, p2.y));
            }
            code = txt_shift_text_currentpoint(penum, &penum->returned.total_width);
            if (code != 0)
                return code;

            code = txt_add_fragment(tdev, penum);
        }
    }
    return code;
}

Project: ghostpdl
File: gdevtxtw.c

float txt_calculate_text_size(gs_gstate *pgs, gs_font *ofont,
                              const gs_matrix *pfmat, gs_matrix *smat, gs_matrix *tmat,
                              gs_font *font, gx_device *pdev)
{
    gs_matrix orig_matrix;
    double
        sx = pdev->HWResolution[0] / 72.0,
        sy = pdev->HWResolution[1] / 72.0;
    float size;

    /* Get the original matrix of the base font. */

    txtwrite_font_orig_matrix(ofont, -1, &orig_matrix);
    /* Compute the scaling matrix and combined matrix. */

    if (gs_matrix_invert(&orig_matrix, smat) < 0) {
        gs_make_identity(smat);
        return 1; /* Arbitrary */
    }
    gs_matrix_multiply(smat, pfmat, smat);
    *tmat = ctm_only(pgs);
    tmat->tx = tmat->ty = 0;
    gs_matrix_multiply(smat, tmat, tmat);

    /* Try to find a reasonable size value. */

    size = hypot(tmat->yx, tmat->yy) / sy;
    if (size < 0.01)
        size = hypot(tmat->xx, tmat->xy) / sx;
    if (size < 0.01)
        size = 1;

    return(size);
}

Project: ghostpdl
File: zbfont.c

get_font_name(const gs_memory_t *mem, ref * pfname, const ref * op)
{
    switch (r_type(op)) {
        case t_string:
            *pfname = *op;
            break;
        case t_name:
            name_string_ref(mem, op, pfname);
            break;
        default:
            /* This is weird, but legal.... */
            make_empty_string(pfname, a_readonly);
    }
}

Project: ghostpdl
File: gdevtxtw.c

txt_add_sorted_fragment(gx_device_txtwrite_t *tdev, textw_text_enum_t *penum)
{
    if (!tdev->PageData.y_ordered_list) {
        /* first entry, no need to sort, just store it */
        tdev->PageData.y_ordered_list = (page_text_list_t *)gs_malloc(tdev->memory->stable_memory, 1,
            sizeof(page_text_list_t), "txtwrite alloc Y list entry");
        if (!tdev->PageData.y_ordered_list)
            return gs_note_error(gs_error_VMerror);
        memset(tdev->PageData.y_ordered_list, 0x00, sizeof(page_text_list_t));
        tdev->PageData.y_ordered_list->x_ordered_list = penum->text_state;
        tdev->PageData.y_ordered_list->next = tdev->PageData.y_ordered_list->previous = NULL;
        tdev->PageData.y_ordered_list->start = penum->text_state->start;
    } else {
        page_text_list_t *Y_List = tdev->PageData.y_ordered_list;

        while (Y_List->next && Y_List->start.y < penum->text_state->start.y)
            Y_List = Y_List->next;

        if (Y_List->start.y == penum->text_state->start.y) {
            /* Already have text at this y-position */
            text_list_entry_t *X_List = Y_List->x_ordered_list;

            while (X_List->next && X_List->start.x < penum->text_state->start.x)
                X_List = X_List->next;

            if (X_List->start.x > penum->text_state->start.x) {
                /* Insert before */
                penum->text_state->next = X_List;
                penum->text_state->previous = X_List->previous;
                X_List->previous = penum->text_state;
                if (!penum->text_state->previous)
                    /* New head of list */
                    Y_List->x_ordered_list = penum->text_state;
                else
                    penum->text_state->previous->next = penum->text_state;
            } else {
                /* Insert after */
                penum->text_state->previous = X_List;
                penum->text_state->next = X_List->next;
                X_List->next = penum->text_state;
                if (penum->text_state->next)
                    penum->text_state->next->previous = penum->text_state;
            }
            if (penum->text_state->FontBBox_bottomleft.y < Y_List->MinY)
                Y_List->MinY = penum->text_state->FontBBox_bottomleft.y;
            if (penum->text_state->FontBBox_bottomleft.y > Y_List->MaxY)
                Y_List->MaxY = penum->text_state->FontBBox_bottomleft.y;
            if (penum->text_state->FontBBox_topright.y < Y_List->MinY)
                Y_List->MinY = penum->text_state->FontBBox_topright.y;
            if (penum->text_state->FontBBox_topright.y > Y_List->MaxY)
                Y_List->MaxY = penum->text_state->FontBBox_topright.y;
        } else {
            /* New y-position, make a Y list new record */
            page_text_list_t *Y_Entry = (page_text_list_t *)gs_malloc(tdev->memory->stable_memory, 1,
                sizeof(page_text_list_t), "txtwrite alloc Y-list");
            if (!Y_Entry)
                return gs_note_error(gs_error_VMerror);

            Y_Entry->x_ordered_list = penum->text_state;
            Y_Entry->start = penum->text_state->start;
            if (penum->text_state->FontBBox_bottomleft.y > penum->text_state->FontBBox_topright.y) {
                Y_Entry->MinY = penum->text_state->FontBBox_topright.y;
                Y_Entry->MaxY = penum->text_state->FontBBox_bottomleft.y;
            } else {
                Y_Entry->MaxY = penum->text_state->FontBBox_topright.y;
                Y_Entry->MinY = penum->text_state->FontBBox_bottomleft.y;
            }

            if (Y_List->start.y > penum->text_state->start.y) {
                /* Insert before */
                Y_Entry->next = Y_List;
                Y_Entry->previous = Y_List->previous;
                Y_List->previous = Y_Entry;
                if (!Y_Entry->previous)
                    /* New head of list */
                    tdev->PageData.y_ordered_list = Y_Entry;
                else
                    ((page_text_list_t *)Y_Entry->previous)->next = Y_Entry;
            } else {
                /* Insert after */
                Y_Entry->next = Y_List->next;
                Y_Entry->previous = Y_List;
                Y_List->next = Y_Entry;
                if (Y_Entry->next)
                    ((page_text_list_t *)(Y_Entry->next))->previous = Y_Entry;
            }
        }
    }
    penum->text_state = NULL;
    return 0;
}

Project: ghostpdl
File: zbfont.c

build_gs_primitive_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font_base ** ppfont,
                        font_type ftype, gs_memory_type_ptr_t pstype,
                        const build_proc_refs * pbuild,
                        build_font_options_t options)
{
    ref *pcharstrings = 0;
    ref CharStrings;
    gs_font_base *pfont;
    font_data *pdata;
    int code;

    if (dict_find_string(op, "CharStrings", &pcharstrings) <= 0) {
        if (!(options & bf_CharStrings_optional))
            return_error(gs_error_invalidfont);
    } else {
        ref *ignore;

        if (!r_has_type(pcharstrings, t_dictionary))
            return_error(gs_error_invalidfont);
        if ((options & bf_notdef_required) != 0 &&
            dict_find_string(pcharstrings, ".notdef", &ignore) <= 0
            )
            return_error(gs_error_invalidfont);
        /*
         * Since build_gs_simple_font may resize the dictionary and cause
         * pointers to become invalid, save CharStrings.
         */
        CharStrings = *pcharstrings;
    }
    code = build_gs_outline_font(i_ctx_p, op, ppfont, ftype, pstype, pbuild,
                                 options, build_gs_simple_font);
    if (code != 0)
        return code;
    pfont = *ppfont;
    pdata = pfont_data(pfont);
    if (pcharstrings)
        ref_assign(&pdata->CharStrings, &CharStrings);
    else
        make_null(&pdata->CharStrings);
    /* Check that the UniqueIDs match.  This is part of the */
    /* Adobe protection scheme, but we may as well emulate it. */
    if (uid_is_valid(&pfont->UID) &&
        !dict_check_uid_param(op, &pfont->UID)
        )
        uid_set_invalid(&pfont->UID);
    if (uid_is_valid(&pfont->UID)) {
        const gs_font *pfont0 = (const gs_font *)pfont;

        code = gs_font_find_similar(ifont_dir, &pfont0,
                       font_with_same_UID_and_another_metrics);
        if (code < 0)
            return code; /* Must not happen. */
        if (code)
            uid_set_invalid(&pfont->UID);
    }
    return 0;
}

Project: ghostpdl
File: gdevtxtw.c

textw_text_resync(gs_text_enum_t *pte, const gs_text_enum_t *pfrom)
{
    return gs_text_resync(pte, pfrom);
}

Project: ghostpdl
File: zbfont.c

build_gs_FDArray_font(i_ctx_t *i_ctx_p, ref *op,
                      gs_font_base **ppfont,
                      font_type ftype, gs_memory_type_ptr_t pstype,
                      const build_proc_refs * pbuild)
{
    gs_font_base *pfont;
    font_data *pdata;
    int code = build_gs_outline_font(i_ctx_p, op, &pfont, ftype, pstype,
                                     pbuild, bf_options_none,
                                     build_FDArray_sub_font);
    static const double bbox[4] = { 0, 0, 0, 0 };
    gs_uid uid;

    if (code < 0)
        return code;
    pdata = pfont_data(pfont);
    /* Fill in members normally set by build_gs_primitive_font. */
    make_null(&pdata->CharStrings);
    /* Fill in members normally set by build_gs_simple_font. */
    uid_set_invalid(&uid);
    init_gs_simple_font(pfont, bbox, &uid);
    pfont->encoding_index = ENCODING_INDEX_UNKNOWN;
    pfont->nearest_encoding_index = ENCODING_INDEX_UNKNOWN;
    /* Fill in members normally set by build_gs_font. */
    pfont->key_name = pfont->font_name;
    *ppfont = pfont;
    return 0;
}

Project: ghostpdl
File: gdevtxtw.c

txtwrite_get_params(gx_device * dev, gs_param_list * plist)
{
    int code;
    bool bool_T = true;
    gs_param_string ofns;
    gx_device_txtwrite_t *const tdev = (gx_device_txtwrite_t *) dev;

    code = gx_default_get_params(dev, plist);
    if (code < 0)
        return code;

    ofns.data = (const byte *)tdev->fname,
    ofns.size = strlen(tdev->fname),
    ofns.persistent = false;
    code = param_write_string(plist, "OutputFile", &ofns);
    if (code < 0)
        return code;

    code = param_write_bool(plist, "WantsToUnicode", &bool_T);
    if (code < 0)
        return code;

    code = param_write_bool(plist, "PreserveTrMode", &bool_T);
    if (code < 0)
        return code;

    code = param_write_bool(plist, "HighLevelDevice", &bool_T);
    if (code < 0)
        return code;

   code = gs_param_write_items(plist, tdev, NULL, txt_param_items);
   return code;
}

Project: ghostpdl
File: gdevtxtw.c

txtwrite_process_plain_text(gs_text_enum_t *pte)
{
    /* one byte regular font */
    textw_text_enum_t *const penum = (textw_text_enum_t *)pte;
    gs_font *font = pte->orig_font;
    const gs_glyph *gdata = NULL;
    gs_glyph glyph;
    gs_char ch = 0;
    int i, code;
    uint operation = pte->text.operation;
    txt_glyph_widths_t widths;
    gs_point wanted;	/* user space */
    gs_point dpt = {0,0};

    for (i=0;i<pte->text.size;i++) {
        if (operation & (TEXT_FROM_STRING | TEXT_FROM_BYTES)) {
            ch = pte->text.data.bytes[pte->index++];
        } else if (operation & (TEXT_FROM_CHARS | TEXT_FROM_SINGLE_CHAR)) {
            ch = pte->text.data.chars[pte->index++];
        } else if (operation & (TEXT_FROM_GLYPHS | TEXT_FROM_SINGLE_GLYPH)) {
            if (operation & TEXT_FROM_GLYPHS) {
                gdata = pte->text.data.glyphs + (pte->index++ * sizeof (gs_glyph));
            } else {
                gdata = &pte->text.data.d_glyph;
                pte->index++;
            }
        }
        glyph = (gdata == NULL ? pte->orig_font->procs.encode_char(pte->orig_font, ch, GLYPH_SPACE_NAME)
                           : *gdata);

        code = txt_glyph_widths(font, font->WMode, glyph, (gs_font *)font, &widths, NULL);
        if (code < 0)
            return code;

        penum->cdevproc_callout = false;
        code = txt_update_text_state(penum->text_state, (textw_text_enum_t *)pte, pte->orig_font, &font->FontMatrix);
        if (code < 0)
            return code;

        txt_char_widths_to_uts(pte->orig_font, &widths); /* convert design->text space */
        gs_distance_transform(widths.real_width.xy.x * penum->text_state->size,
                          widths.real_width.xy.y * penum->text_state->size,
                          &penum->text_state->matrix, &wanted);
        pte->returned.total_width.x += wanted.x;
        pte->returned.total_width.y += wanted.y;
        penum->Widths[pte->index - 1] = wanted.x;

        if (pte->text.operation & TEXT_ADD_TO_ALL_WIDTHS) {
            gs_point tpt;

            gs_distance_transform(pte->text.delta_all.x, pte->text.delta_all.y,
                              &ctm_only(pte->pgs), &tpt);
            dpt.x += tpt.x;
            dpt.y += tpt.y;
        }
        if (pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH && ch == pte->text.space.s_char) {
            gs_point tpt;

            gs_distance_transform(pte->text.delta_space.x, pte->text.delta_space.y,
                              &ctm_only(pte->pgs), &tpt);
            dpt.x += tpt.x;
            dpt.y += tpt.y;
        }
        pte->returned.total_width.x += dpt.x;
        pte->returned.total_width.y += dpt.y;

        penum->TextBufferIndex += get_unicode(penum, (gs_font *)pte->orig_font, glyph, ch, &penum->TextBuffer[penum->TextBufferIndex]);
        penum->Widths[pte->index - 1] += dpt.x;
    }
    return 0;
}

Project: ghostpdl
File: gdevtxtw.c

txt_char_widths_to_uts(gs_font *font /* may be NULL for non-Type3 */,
                       txt_glyph_widths_t *pwidths)
{
    if (font && (font->FontType == ft_user_defined ||
        font->FontType == ft_PCL_user_defined ||
        font->FontType == ft_GL2_stick_user_defined ||
        font->FontType == ft_GL2_531)) {
        gs_matrix *pmat = &font->orig_FontMatrix;

        pwidths->Width.xy.x *= pmat->xx; /* formula simplified based on wy in glyph space == 0 */
        pwidths->Width.xy.y  = 0.0; /* WMode == 0 for PDF Type 3 fonts */
        gs_distance_transform(pwidths->real_width.xy.x, pwidths->real_width.xy.y, pmat, &pwidths->real_width.xy);
    } else {
        /*
         * For other font types:
         * - PDF design->text space is a simple scaling by 0.001.
         * - The Width.xy.x/y that should be zeroed-out per 5.3.3 "Text Space Details" is already 0.
         */
        pwidths->Width.xy.x /= 1000.0;
        pwidths->Width.xy.y /= 1000.0;
        pwidths->real_width.xy.x /= 1000.0;
        pwidths->real_width.xy.y /= 1000.0;
    }
}

Project: ghostpdl
File: gdevtxtw.c

txt_add_fragment(gx_device_txtwrite_t *tdev, textw_text_enum_t *penum)
{
    text_list_entry_t *unsorted_entry, *t;

    /* Create a duplicate entry for the unsorted list */
    unsorted_entry = (text_list_entry_t *)gs_malloc(tdev->memory->stable_memory, 1,
            sizeof(text_list_entry_t), "txtwrite alloc sorted text state");
    if (!unsorted_entry)
        return gs_note_error(gs_error_VMerror);

    /* Calculate the start and end points of the text */
    penum->text_state->start.x = fixed2float(penum->origin.x);
    penum->text_state->start.y = fixed2float(penum->origin.y);
    penum->text_state->end.x = penum->text_state->start.x + penum->returned.total_width.x;
    penum->text_state->end.y = penum->text_state->start.y + penum->returned.total_width.y;
    penum->text_state->Unicode_Text_Size = penum->TextBufferIndex;

    *unsorted_entry = *(penum->text_state);

    /* Update the saved text state with the acccumulated Unicode data */
    /* The working buffer (penum->TextBuffer) is freed in the text_release method */
    penum->text_state->Unicode_Text = (unsigned short *)gs_malloc(tdev->memory->stable_memory,
        penum->TextBufferIndex, sizeof(unsigned short), "txtwrite alloc text buffer");
    if (!penum->text_state->Unicode_Text)
        return gs_note_error(gs_error_VMerror);
    memcpy(penum->text_state->Unicode_Text, penum->TextBuffer, penum->TextBufferIndex * sizeof(unsigned short));

    penum->text_state->Widths = (float *)gs_malloc(tdev->memory->stable_memory,
        penum->TextBufferIndex, sizeof(float), "txtwrite alloc widths array");
    if (!penum->text_state->Widths)
        return gs_note_error(gs_error_VMerror);
    memcpy(penum->text_state->Widths, penum->Widths, penum->TextBufferIndex * sizeof(float));

    unsorted_entry->Unicode_Text = (unsigned short *)gs_malloc(tdev->memory->stable_memory,
        penum->TextBufferIndex, sizeof(unsigned short), "txtwrite alloc sorted text buffer");
    if (!unsorted_entry->Unicode_Text)
        return gs_note_error(gs_error_VMerror);
    memcpy(unsorted_entry->Unicode_Text, penum->TextBuffer, penum->TextBufferIndex * sizeof(unsigned short));

    unsorted_entry->Widths = (float *)gs_malloc(tdev->memory->stable_memory,
        penum->TextBufferIndex, sizeof(float), "txtwrite alloc widths array");
    if (!unsorted_entry->Widths)
        return gs_note_error(gs_error_VMerror);
    memcpy(unsorted_entry->Widths, penum->Widths, penum->TextBufferIndex * sizeof(float));

    unsorted_entry->FontName = (char *)gs_malloc(tdev->memory->stable_memory,
        (strlen(penum->text_state->FontName) + 1), sizeof(unsigned char), "txtwrite alloc sorted text buffer");
    if (!unsorted_entry->FontName)
        return gs_note_error(gs_error_VMerror);
    memcpy(unsorted_entry->FontName, penum->text_state->FontName, strlen(penum->text_state->FontName) * sizeof(unsigned char));
    unsorted_entry->FontName[strlen(penum->text_state->FontName)] = 0x00;

    /* First add one entry to the unsorted list */
    if (!tdev->PageData.unsorted_text_list) {
        tdev->PageData.unsorted_text_list = unsorted_entry;
        unsorted_entry->next = unsorted_entry->previous = NULL;
    } else {
        t = tdev->PageData.unsorted_text_list;
        while (t->next)
            t = t->next;
        t->next = unsorted_entry;
        unsorted_entry->next = NULL;
        unsorted_entry->previous = t;
    }

    /* Then add the other entry to the sorted list */
    return txt_add_sorted_fragment(tdev, penum);
}

Project: ghostpdl
File: gdevtxtw.c

transform_delta_inverse(const gs_point *pdelta, const gs_matrix *pmat,
                        gs_point *ppt)
{
    int code = gs_distance_transform_inverse(pdelta->x, pdelta->y, pmat, ppt);
    gs_point delta;

    if (code < 0)
        return code;
    if (ppt->y == 0)
        return 0;
    /* Check for numerical fuzz. */
    code = gs_distance_transform(ppt->x, 0.0, pmat, &delta);
    if (code < 0)
        return 0;                /* punt */
    if (fabs(delta.x - pdelta->x) < 0.01 && fabs(delta.y - pdelta->y) < 0.01) {
        /* Close enough to y == 0: device space error < 0.01 pixel. */
        ppt->y = 0;
    }
    return 0;
}

Project: ghostpdl
File: gdevtxtw.c

textw_text_current_width(const gs_text_enum_t *pte, gs_point *pwidth)
{
    return gs_text_current_width(pte, pwidth);
}

Project: ghostpdl
File: zbfont.c

build_gs_font_procs(os_ptr op, build_proc_refs * pbuild)
{
    int ccode, gcode;
    ref *pBuildChar;
    ref *pBuildGlyph;

    check_type(*op, t_dictionary);
    ccode = dict_find_string(op, "BuildChar", &pBuildChar);
    gcode = dict_find_string(op, "BuildGlyph", &pBuildGlyph);
    if (ccode <= 0) {
        if (gcode <= 0)
            return_error(gs_error_invalidfont);
        make_null(&pbuild->BuildChar);
    } else {
        check_proc(*pBuildChar);
        pbuild->BuildChar = *pBuildChar;
    }
    if (gcode <= 0)
        make_null(&pbuild->BuildGlyph);
    else {
        check_proc(*pBuildGlyph);
        pbuild->BuildGlyph = *pBuildGlyph;
    }
    return 0;
}

Project: ghostpdl
File: gdevtxtw.c

txt_update_text_state(text_list_entry_t *ppts,
                      const textw_text_enum_t *penum,
                      gs_font *ofont, const gs_matrix *pfmat)
{
    gx_device *const pdev = penum->dev;
    gs_font *font = penum->current_font;
    gs_fixed_point cpt;
    gs_matrix smat, tmat;
    float size;
    int mask = 0;
    int code = gx_path_current_point(penum->path, &cpt);

    if (code < 0)
        return code;

    size = txt_calculate_text_size(penum->pgs, ofont, pfmat, &smat, &tmat, penum->current_font, pdev);
    /* Check for spacing parameters we can handle, and transform them. */

    if (penum->text.operation & TEXT_ADD_TO_ALL_WIDTHS) {
        if (penum->current_font->WMode == 0) {
            gs_point pt;

            code = transform_delta_inverse(&penum->text.delta_all, &smat, &pt);
            if (code < 0 || pt.y != 0)
                mask |= TEXT_ADD_TO_ALL_WIDTHS;
        }
        else
            mask |= TEXT_ADD_TO_ALL_WIDTHS;
    }

    if (penum->text.operation & TEXT_ADD_TO_SPACE_WIDTH) {
        gs_point pt;

        code = transform_delta_inverse(&penum->text.delta_space, &smat, &pt);
        if (code < 0 || pt.y != 0 || penum->text.space.s_char != 32)
            mask |= TEXT_ADD_TO_SPACE_WIDTH;
    }
    /* Store the updated values. */

    tmat.xx /= size;
    tmat.xy /= size;
    tmat.yx /= size;
    tmat.yy /= size;
    tmat.tx += fixed2float(cpt.x);
    tmat.ty += fixed2float(cpt.y);

    ppts->size = size;
    ppts->matrix = tmat;
    ppts->render_mode = penum->pgs->text_rendering_mode;
    ppts->FontName = (char *)gs_malloc(pdev->memory->stable_memory, 1,
        font->font_name.size + 1, "txtwrite alloc font name");
    if (!ppts->FontName)
        return gs_note_error(gs_error_VMerror);
    memcpy(ppts->FontName, font->font_name.chars, font->font_name.size);
    ppts->FontName[font->font_name.size] = 0x00;
    ppts->render_mode = font->WMode;

    if (font->PaintType == 2 && penum->pgs->text_rendering_mode == 0)
    {
        gs_gstate *pgs = penum->pgs;
        gs_font *font = penum->current_font;
        double scaled_width = font->StrokeWidth != 0 ? font->StrokeWidth : 0.001;
        double saved_width = pgs->line_params.half_width;
        /*
         * See stream_to_text in gdevpdfu.c re the computation of
         * the scaling value.
         */
        double scale = 72.0 / pdev->HWResolution[1];

        if (font->FontMatrix.yy != 0)
            scaled_width *= fabs(font->orig_FontMatrix.yy) * size * tmat.yy * scale;
        else
            scaled_width *= fabs(font->orig_FontMatrix.xy) * size * tmat.xy * scale;

        ppts->render_mode = 1;
        ppts->PaintType0Width = scaled_width;

        pgs->line_params.half_width = scaled_width / 2;
        if (code < 0)
            return code;

        pgs->line_params.half_width = saved_width;
    }
    return (code < 0 ? code : mask);
}

Project: ghostpdl
File: gdevtxtw.c

txtwrite_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
                    gx_color_index color)
{
    return 0;
}

Project: ghostpdl
File: zbfont.c

static int font_with_same_UID_and_another_metrics(const gs_font *pfont0, const gs_font *pfont1)
{
    const gs_font_base *pbfont0 = (const gs_font_base *)pfont0;
    const gs_font_base *pbfont1 = (const gs_font_base *)pfont1;

    if (uid_equal(&pbfont0->UID, &pbfont1->UID)) {
        const ref *pfdict0 = &pfont_data(gs_font_parent(pbfont0))->dict;
        const ref *pfdict1 = &pfont_data(gs_font_parent(pbfont1))->dict;
        ref *pmdict0, *pmdict1;

        if (pbfont0->WMode || dict_find_string(pfdict0, "Metrics", &pmdict0) <= 0)
            pmdict0 = NULL;
        if (pbfont1->WMode || dict_find_string(pfdict1, "Metrics", &pmdict1) <= 0)
            pmdict1 = NULL;
        if (!pmdict0 != !pmdict1)
            return 1;
        if (pmdict0 != NULL && !obj_eq(pfont0->memory, pmdict0, pmdict1))
            return 1;
        if (!pbfont0->WMode || dict_find_string(pfdict0, "Metrics2", &pmdict0) <= 0)
            pmdict0 = NULL;
        if (!pbfont0->WMode || dict_find_string(pfdict1, "Metrics2", &pmdict1) <= 0)
            pmdict1 = NULL;
        if (!pmdict0 != !pmdict1)
            return 1;
        if (pmdict0 != NULL && !obj_eq(pfont0->memory, pmdict0, pmdict1))
            return 1;
    }
    return 0;
}

Project: ghostpdl
File: gdevtxtw.c

txtwrite_close_device(gx_device * dev)
{
    int code = 0;
    gx_device_txtwrite_t *const tdev = (gx_device_txtwrite_t *) dev;

    if (tdev->file) {
        code = gx_device_close_output_file(dev, tdev->fname, tdev->file);
        tdev->file = 0;
    }

#ifdef TRACE_TXTWRITE
    fclose(tdev->DebugFile);
#endif
    return code;
}

Project: ghostpdl
File: gdevtxtw.c

txtwrite_strip_copy_rop(gx_device * dev,
                    const byte * sdata, int sourcex, uint sraster,
                    gx_bitmap_id id,
                    const gx_color_index * scolors,
                    const gx_strip_bitmap * textures,
                    const gx_color_index * tcolors,
                    int x, int y, int w, int h,
                    int phase_x, int phase_y, gs_logical_operation_t lop)
{
    return 0;
}

Project: ghostpdl
File: zbfont.c

build_gs_outline_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font_base ** ppfont,
                      font_type ftype, gs_memory_type_ptr_t pstype,
                      const build_proc_refs * pbuild,
                      build_font_options_t options,
                      build_base_font_proc_t build_base_font)
{
    int painttype;
    float strokewidth;
    gs_font_base *pfont;
    int code = dict_int_param(op, "PaintType", 0, 3, 0, &painttype);

    if (code < 0)
        return code;
    code = dict_float_param(op, "StrokeWidth", 0.0, &strokewidth);
    if (code < 0)
        return code;
    code = build_base_font(i_ctx_p, op, ppfont, ftype, pstype, pbuild,
                           options);
    if (code != 0)
        return code;
    pfont = *ppfont;
    pfont->PaintType = painttype;
    pfont->StrokeWidth = strokewidth;
    return 0;
}

Project: ghostpdl
File: gdevtxtw.c

txtwrite_fill_path(gx_device * dev, const gs_gstate * pgs, gx_path * ppath,
               const gx_fill_params * params, const gx_device_color * pdevc,
               const gx_clip_path * pcpath)
{
        return 0;
}

Project: ghostpdl
File: zbfont.c

zfont_glyph_name(gs_font *font, gs_glyph index, gs_const_string *pstr)
{
    ref nref, sref;

    if (index >= GS_MIN_CID_GLYPH) {	/* Fabricate a numeric name. */
        char cid_name[sizeof(gs_glyph) * 3 + 1];
        int code;

        gs_sprintf(cid_name, "%lu", (ulong) index);
        code = name_ref(font->memory, (const byte *)cid_name, strlen(cid_name),
                        &nref, 1);
        if (code < 0)
            return code;
    } else
        name_index_ref(font->memory, index, &nref);
    name_string_ref(font->memory, &nref, &sref);
    pstr->data = sref.value.const_bytes;
    pstr->size = r_size(&sref);
    return 0;
}

Project: ghostpdl
File: zbfont.c

zfont_encode_char(gs_font *pfont, gs_char chr, gs_glyph_space_t gspace)
{
    font_data *pdata = pfont_data(pfont);
    const ref *pencoding = &pdata->Encoding;
    ulong index = chr;	/* work around VAX widening bug */
    ref cname;
    int code = array_get(pfont->memory, pencoding, (long)index, &cname);

    if (code < 0 || !r_has_type(&cname, t_name))
        return GS_NO_GLYPH;
    if (pfont->FontType == ft_user_defined && r_type(&pdata->BuildGlyph) == t_null) {
        ref nsref, tname;

        name_string_ref(pfont->memory, &cname, &nsref);
        if (r_size(&nsref) == 7 &&
            !memcmp(nsref.value.const_bytes, ".notdef", r_size(&nsref))) {
            /* A special support for high level devices.
               They need a glyph name but the font doesn't provide one
               due to an instandard BuildChar.
               Such fonts don't conform to PLRM section 5.3.7,
               but we've got real examples that we want to handle (Bug 686982).
               Construct a name here.
               Low level devices don't pass here, because regular PS interpretation
               doesn't need such names.
            */
            char buf[20];
            int code;

            if (gspace == GLYPH_SPACE_NOGEN)
                return GS_NO_GLYPH;
            gs_sprintf(buf, "j%ld", chr); /* 'j' is arbutrary. */
            code = name_ref(pfont->memory, (const byte *)buf, strlen(buf), &tname, 1);
            if (code < 0) {
                /* Can't propagate the error due to interface limitation,
                   return with .notdef */
            } else
                cname = tname;
        }
    }
    return (gs_glyph)name_index(pfont->memory, &cname);
}

Project: ghostpdl
File: gdevtxtw.c

static int txtwrite_get_param(gx_device *dev, char *Param, void *list)
{
    gx_device_txtwrite_t *const tdev = (gx_device_txtwrite_t *) dev;
    gs_param_list * plist = (gs_param_list *)list;
    bool bool_T = true;

    if (strcmp(Param, "OutputFile") == 0) {
        gs_param_string ofns;

        ofns.data = (const byte *)tdev->fname,
        ofns.size = strlen(tdev->fname),
        ofns.persistent = false;
        return param_write_string(plist, "OutputFile", &ofns);
    }
    if (strcmp(Param, "WantsToUnicode") == 0) {
        return param_write_bool(plist, "WantsToUnicode", &bool_T);
    }
    if (strcmp(Param, "PreserveTrMode") == 0) {
        return param_write_bool(plist, "PreserveTrMode", &bool_T);
    }
    if (strcmp(Param, "HighLevelDevice") == 0) {
        return param_write_bool(plist, "HighLevelDevice", &bool_T);
    }
    return_error(gs_error_undefined);
}

Project: ghostpdl
File: gdevtxtw.c

glyph_orig_matrix(const gs_font *font, gs_glyph cid, gs_matrix *pmat)
{
    int code = txtwrite_font_orig_matrix(font, cid, pmat);
    if (code >= 0) {
        if (font->FontType == ft_CID_encrypted) {
            int fidx;

            if (cid < GS_MIN_CID_GLYPH)
                cid = GS_MIN_CID_GLYPH;
            code = ((gs_font_cid0 *)font)->cidata.glyph_data((gs_font_base *)font,
                                cid, NULL, &fidx);
            if (code < 0) {
                code = ((gs_font_cid0 *)font)->cidata.glyph_data((gs_font_base *)font,
                                (gs_glyph)GS_MIN_CID_GLYPH, NULL, &fidx);
            }
            if (code >= 0) {
                gs_matrix_multiply(&(gs_cid0_indexed_font(font, fidx)->FontMatrix),
                                pmat, pmat);
            }
        }
    }
    return code;
}

Project: ghostpdl
File: gdevtxtw.c

textw_text_retry(gs_text_enum_t *pte)
{
    return gs_text_retry(pte);
}

Project: ghostpdl
File: gdevtxtw.c

txtwrite_open_device(gx_device * dev)
{
    gx_device_txtwrite_t *const tdev = (gx_device_txtwrite_t *) dev;
    int code = 0;

    gx_device_fill_in_procs(dev);
    if (tdev->fname[0] == 0)
        return_error(gs_error_undefinedfilename);

    tdev->PageData.PageNum = 0;
    tdev->PageData.y_ordered_list = NULL;
    tdev->file = NULL;
#ifdef TRACE_TXTWRITE
    tdev->DebugFile = gp_fopen(dev->memory,"/temp/txtw_dbg.txt", "wb+");
#endif
    dev->color_info.separable_and_linear = GX_CINFO_SEP_LIN;
    set_linear_color_bits_mask_shift(dev);
    dev->interpolate_control = 0;

    code = install_internal_subclass_devices((gx_device **)&dev, NULL);
    return code;
}

Project: ghostpdl
File: gdevtxtw.c

static int escaped_Unicode (unsigned short Unicode, char *Buf)
{
    switch (Unicode)
    {
    case 0x3C: gs_sprintf(Buf, "&lt;"); break;
    case 0x3E: gs_sprintf(Buf, "&gt;"); break;
    case 0x26: gs_sprintf(Buf, "&amp;"); break;
    case 0x22: gs_sprintf(Buf, "&quot;"); break;
    case 0x27: gs_sprintf(Buf, "&apos;"); break;
    default:
        if (Unicode >= 32 && Unicode <= 127)
            gs_sprintf(Buf, "%c", Unicode);
        else
            gs_sprintf(Buf, "&#x%x;", Unicode);
        break;
    }

    return 0;
}

Project: ghostpdl
File: zbfont.c

gs_font_map_glyph_by_dict(const gs_memory_t *mem, const ref *map, gs_glyph glyph, ushort *u, unsigned int length)
{
    ref *v, n;
    uchar *unicode_return = (uchar *)u;
    if (glyph >= GS_MIN_CID_GLYPH) {
        uint cid = glyph - GS_MIN_CID_GLYPH;

        if (dict_find_string(map, "CIDCount", &v) > 0) {
            /* This is a CIDDEcoding resource. */
            make_int(&n, cid / 256);
            if (dict_find(map, &n, &v) > 0) {
                ref vv;

                if (array_get(mem, v, cid % 256, &vv) == 0 && r_type(&vv) == t_integer) {
                    if (v->value.intval > 65535) {
                        if (length < 4)
                            return 4;
                        unicode_return[0] = v->value.intval >> 24;
                        unicode_return[1] = (v->value.intval & 0x00FF0000) >> 16;
                        unicode_return[2] = (v->value.intval & 0x0000FF00) >> 8;
                        unicode_return[3] = v->value.intval & 0xFF;
                        return 4;
                    } else {
                        if (length < 2)
                            return 2;
                        unicode_return[0] = v->value.intval >> 8;
                        unicode_return[1] = v->value.intval & 0xFF;
                        return 2;
                    }
                }
            }
            return 0; /* Absent in the map. */
        }
        /* This is GlyphNames2Unicode dictionary. */
        make_int(&n, cid);
    } else
        name_index_ref(mem, glyph, &n);
     if (dict_find(map, &n, &v) > 0) {
        if (r_has_type(v, t_string)) {
            int l = r_size(v);

            if (length < l)
                return l;
            memcpy(unicode_return, v->value.const_bytes, l);
            return l;
        }
        if (r_type(v) == t_integer) {
            if (v->value.intval > 65535) {
                if (length < 4)
                    return 4;
                unicode_return[0] = v->value.intval >> 24;
                unicode_return[1] = (v->value.intval & 0x00FF0000) >> 16;
                unicode_return[2] = (v->value.intval & 0x0000FF00) >> 8;
                unicode_return[3] = v->value.intval & 0xFF;
                return 4;
            } else {
                if (length < 2)
                    return 2;
                unicode_return[0] = v->value.intval >> 8;
                unicode_return[1] = v->value.intval & 0xFF;
                return 2;
            }
        }
    }
    return 0; /* Absent in the map. */
}

Project: ghostpdl
File: gdevtxtw.c

txt_glyph_widths(gs_font *font, int wmode, gs_glyph glyph,
                 gs_font *orig_font, txt_glyph_widths_t *pwidths,
                 const double cdevproc_result[10])
{
    gs_font *ofont = orig_font;
    gs_glyph_info_t info;
    gs_matrix scale_c, scale_o;
    int code, rcode = 0;
    gs_point v;
    int allow_cdevproc_callout = (orig_font->FontType == ft_CID_TrueType
                || orig_font->FontType == ft_CID_encrypted
                ? GLYPH_INFO_CDEVPROC : 0); /* fixme : allow more font types. */

    if (ofont->FontType == ft_composite)
        return_error(gs_error_unregistered); /* Must not happen. */
    code = glyph_orig_matrix((const gs_font *)font, glyph, &scale_c);
    if (code < 0)
        return code;
    code = glyph_orig_matrix(ofont, glyph, &scale_o);
    if (code < 0)
        return code;
    gs_matrix_scale(&scale_c, 1000.0, 1000.0, &scale_c);
    gs_matrix_scale(&scale_o, 1000.0, 1000.0, &scale_o);
    pwidths->Width.v.x = pwidths->Width.v.y = 0;
    pwidths->real_width.v.x = pwidths->real_width.v.y = 0;
    pwidths->replaced_v = false;
    if (glyph == GS_NO_GLYPH)
        return get_missing_width(font, wmode, &scale_c, pwidths);
    code = font->procs.glyph_info((gs_font *)font, glyph, NULL,
                                    GLYPH_INFO_WIDTH0 |
                                    (GLYPH_INFO_WIDTH0 << wmode) |
                                    GLYPH_INFO_OUTLINE_WIDTHS |
                                    (GLYPH_INFO_VVECTOR0 << wmode),
                                    &info);
    /* For CID fonts the PDF spec requires the x-component of v-vector
       to be equal to half glyph width, and AR5 takes it from W, DW.
       So make a compatibe data here.
     */
    if (font->FontType != ft_PCL_user_defined && font->FontType != ft_GL2_stick_user_defined &&
        font->FontType != ft_GL2_531
        && (code == gs_error_undefined || !(info.members & (GLYPH_INFO_WIDTH0 << wmode)))) {
        code = get_missing_width(font, wmode, &scale_c, pwidths);
        if (code < 0)
            v.y = 0;
        else
            v.y = pwidths->Width.v.y;
        if (wmode && (ofont->FontType == ft_CID_encrypted ||
            ofont->FontType == ft_CID_TrueType)) {
            txt_glyph_widths_t widths1;

            if (get_missing_width(font, 0, &scale_c, &widths1) < 0)
                v.x = 0;
            else
                v.x = widths1.Width.w / 2;
        } else
            v.x = pwidths->Width.v.x;
    } else if (code < 0)
        return code;
    else {
        code = store_glyph_width(&pwidths->Width, wmode, &scale_c, &info);
        if (code < 0)
            return code;
        rcode |= code;
        if (info.members  & (GLYPH_INFO_VVECTOR0 << wmode))
            gs_distance_transform(info.v.x, info.v.y, &scale_c, &v);
        else
            v.x = v.y = 0;
        if (wmode && (ofont->FontType == ft_CID_encrypted ||
            ofont->FontType == ft_CID_TrueType)) {
            if (info.members & (GLYPH_INFO_WIDTH0 << wmode)) {
                gs_point xy;

                gs_distance_transform(info.width[0].x, info.width[0].y, &scale_c, &xy);
                v.x = xy.x / 2;
            } else {
                txt_glyph_widths_t widths1;

                if (get_missing_width(font, 0, &scale_c, &widths1) < 0)
                    v.x = 0;
                else
                    v.x = widths1.Width.w / 2;
            }
        }
    }
    pwidths->Width.v = v;
    /* Skip only if not paralel to the axis. */
    if (code > 0 && ofont->FontType != ft_CID_encrypted &&
            ofont->FontType != ft_CID_TrueType)
        pwidths->Width.xy.x = pwidths->Width.xy.y = pwidths->Width.w = 0;
    if (cdevproc_result == NULL) {
        info.members = 0;
        code = ofont->procs.glyph_info(ofont, glyph, NULL,
                                            (GLYPH_INFO_WIDTH0 << wmode) |
                                            (GLYPH_INFO_VVECTOR0 << wmode) |
                                            allow_cdevproc_callout,
                                            &info);
        /* fixme : Move this call before cfont->procs.glyph_info. */
        if (info.members & GLYPH_INFO_CDEVPROC) {
            if (allow_cdevproc_callout)
                return TEXT_PROCESS_CDEVPROC;
        else
            return_error(gs_error_rangecheck);
        }
    } else {
        info.width[0].x = cdevproc_result[0];
        info.width[0].y = cdevproc_result[1];
        info.width[1].x = cdevproc_result[6];
        info.width[1].y = cdevproc_result[7];
        info.v.x = (wmode ? cdevproc_result[8] : 0);
        info.v.y = (wmode ? cdevproc_result[9] : 0);
        info.members = (GLYPH_INFO_WIDTH0 << wmode) |
                       (wmode ? GLYPH_INFO_VVECTOR1 : 0);
        code = 0;
    }
    if (code == gs_error_undefined || !(info.members & (GLYPH_INFO_WIDTH0 << wmode)))
        pwidths->real_width = pwidths->Width;
    else if (code < 0)
        return code;
    else {
        if ((info.members & (GLYPH_INFO_VVECTOR0 | GLYPH_INFO_VVECTOR1)) != 0)
            pwidths->replaced_v = true;
        else
            info.v.x = info.v.y = 0;
        code = store_glyph_width(&pwidths->real_width, wmode, &scale_o, &info);
        if (code < 0)
            return code;
        rcode |= code;
        gs_distance_transform(info.v.x, info.v.y, &scale_o, &pwidths->real_width.v);
    }
    return rcode;
}

Project: ghostpdl
File: gdevtxtw.c

static int get_unicode(textw_text_enum_t *penum, gs_font *font, gs_glyph glyph, gs_char ch, unsigned short *Buffer)
{
    int code;
    gs_const_string gnstr;
    unsigned short fallback = ch;
    ushort *unicode = NULL;
    int length;

    length = font->procs.decode_glyph((gs_font *)font, glyph, ch, NULL, 0);
    if (length == 0) {
        if (glyph != GS_NO_GLYPH) {
            code = font->procs.glyph_name(font, glyph, &gnstr);
            if (code >= 0 && gnstr.size == 7) {
                if (!memcmp(gnstr.data, "uni", 3)) {
                    static const char *hexdigits = "0123456789ABCDEF";
                    char *d0 = strchr(hexdigits, gnstr.data[3]);
                    char *d1 = strchr(hexdigits, gnstr.data[4]);
                    char *d2 = strchr(hexdigits, gnstr.data[5]);
                    char *d3 = strchr(hexdigits, gnstr.data[6]);

                    if (d0 != NULL && d1 != NULL && d2 != NULL && d3 != NULL) {
                        *Buffer++ = ((d0 - hexdigits) << 12) + ((d1 - hexdigits) << 8) + ((d2 - hexdigits) << 4) + (d3 - hexdigits);
                        return 1;
                    }
                }
            }
            if (length == 0) {
                single_glyph_list_t *sentry = (single_glyph_list_t *)&SingleGlyphList;
                double_glyph_list_t *dentry = (double_glyph_list_t *)&DoubleGlyphList;
                treble_glyph_list_t *tentry = (treble_glyph_list_t *)&TrebleGlyphList;
                quad_glyph_list_t *qentry = (quad_glyph_list_t *)&QuadGlyphList;

                /* Search glyph to single Unicode value table */
                while (sentry->Glyph != 0) {
                    if (sentry->Glyph[0] < gnstr.data[0]) {
                        sentry++;
                        continue;
                    }
                    if (sentry->Glyph[0] > gnstr.data[0]){
                        break;
                    }
                    if (strlen(sentry->Glyph) == gnstr.size) {
                        if(memcmp(gnstr.data, sentry->Glyph, gnstr.size) == 0) {
                            *Buffer = sentry->Unicode;
                            return 1;
                        }
                    }
                    sentry++;
                }

                /* Search glyph to double Unicode value table */
                while (dentry->Glyph != 0) {
                    if (dentry->Glyph[0] < gnstr.data[0]) {
                        dentry++;
                        continue;
                    }
                    if (dentry->Glyph[0] > gnstr.data[0]){
                        break;
                    }
                    if (strlen(dentry->Glyph) == gnstr.size) {
                        if(memcmp(gnstr.data, dentry->Glyph, gnstr.size) == 0) {
                            memcpy(Buffer, dentry->Unicode, 2);
                            return 2;
                        }
                    }
                    dentry++;
                }

                /* Search glyph to triple Unicode value table */
                while (tentry->Glyph != 0) {
                    if (tentry->Glyph[0] < gnstr.data[0]) {
                        tentry++;
                        continue;
                    }
                    if (tentry->Glyph[0] > gnstr.data[0]){
                        break;
                    }
                    if (strlen(tentry->Glyph) == gnstr.size) {
                        if(memcmp(gnstr.data, tentry->Glyph, gnstr.size) == 0) {
                            memcpy(Buffer, tentry->Unicode, 3);
                            return 3;
                        }
                    }
                    tentry++;
                }

                /* Search glyph to quadruple Unicode value table */
                while (qentry->Glyph != 0) {
                    if (qentry->Glyph[0] < gnstr.data[0]) {
                        qentry++;
                        continue;
                    }
                    if (qentry->Glyph[0] > gnstr.data[0]){
                        break;
                    }
                    if (strlen(qentry->Glyph) == gnstr.size) {
                        if(memcmp(gnstr.data, qentry->Glyph, gnstr.size) == 0) {
                            memcpy(Buffer, qentry->Unicode, 4);
                            return 4;
                        }
                    }
                    qentry++;
                }
            }
        }
        *Buffer = fallback;
        return 1;
    } else {
        char *b, *u;
        int l = length - 1;

        unicode = (ushort *)gs_alloc_bytes(penum->dev->memory, length, "temporary Unicode array");
        length = font->procs.decode_glyph((gs_font *)font, glyph, ch, unicode, length);
#if ARCH_IS_BIG_ENDIAN
        memcpy(Buffer, unicode, length);
#else
        b = (char *)Buffer;
        u = (char *)unicode;
        while (l >= 0) {
            *b++ = *(u + l);
            l--;
        }

#endif
        gs_free_object(penum->dev->memory, unicode, "free temporary unicode buffer");
        return length / sizeof(short);
    }
}

Project: ghostpdl
File: gdevtxtw.c

textw_text_set_cache(gs_text_enum_t *pte, const double *pw,
                   gs_text_cache_control_t control)
{
    textw_text_enum_t *const penum = (textw_text_enum_t *)pte;

    switch (control) {
        case TEXT_SET_CHAR_WIDTH:
        case TEXT_SET_CACHE_DEVICE:
            return gs_text_set_cache(pte, pw, control);
        case TEXT_SET_CACHE_DEVICE2:
            if (penum->cdevproc_callout) {
                memcpy(penum->cdevproc_result, pw, sizeof(penum->cdevproc_result));
                return 0;
            }
            return gs_text_set_cache(pte, pw, control);
        default:
            return_error(gs_error_rangecheck);
    }
    return 0;
}

Project: ghostpdl
File: gdevtxtw.c

get_missing_width(gs_font *font, int wmode, const gs_matrix *scale_c,
                    txt_glyph_widths_t *pwidths)
{
    gs_font_info_t finfo;
    int code;

    code = font->procs.font_info((gs_font *)font, NULL,
                                  FONT_INFO_MISSING_WIDTH, &finfo);
    if (code < 0)
        return code;
    if (wmode) {
        gs_distance_transform(0.0, -finfo.MissingWidth, scale_c, &pwidths->real_width.xy);
        pwidths->Width.xy.x = 0;
        pwidths->Width.xy.y = pwidths->real_width.xy.y;
        pwidths->Width.w = pwidths->real_width.w =
                pwidths->Width.xy.y;
        pwidths->Width.v.x = - pwidths->Width.xy.y / 2;
        pwidths->Width.v.y = - pwidths->Width.xy.y;
    } else {
        gs_distance_transform(finfo.MissingWidth, 0.0, scale_c, &pwidths->real_width.xy);
        pwidths->Width.xy.x = pwidths->real_width.xy.x;
        pwidths->Width.xy.y = 0;
        pwidths->Width.w = pwidths->real_width.w =
                pwidths->Width.xy.x;
        pwidths->Width.v.x = pwidths->Width.v.y = 0;
    }
    /*
     * Don't mark the width as known, just in case this is an
     * incrementally defined font.
     */
    return 1;
}

Project: ghostpdl
File: gdevtxtw.c

txtwrite_output_page(gx_device * dev, int num_copies, int flush)
{
    int code;
    gx_device_txtwrite_t *const tdev = (gx_device_txtwrite_t *) dev;
    text_list_entry_t * x_entry, *next_x;
    page_text_list_t *y_list;
    gs_parsed_file_name_t parsed;
    const char *fmt;
    const short BOM = 0xFEFF;

    if (!tdev->file) {
        /* Either this is the first page, or we're doing one file per page */
        code = gx_device_open_output_file(dev, tdev->fname,
                true, false, &tdev->file); /* binary, sequential */
        if (code < 0)
            return code;
    }

    switch(tdev->TextFormat) {
        case 0:
        case 1:
            code = decorated_text_output(tdev);
            if (code < 0)
                return code;
            break;

        case 2:
            gp_fwrite (&BOM, sizeof(unsigned short), 1, tdev->file);
            /* fall through */
        case 3:
            code = simple_text_output(tdev);
            if (code < 0)
                return code;
            break;

        default:
            return gs_note_error(gs_error_rangecheck);
            break;
    }

    code =  gx_default_output_page(dev, num_copies, flush);
    if (code < 0)
        return code;

    /* free the sorted fragment list! */
    y_list = tdev->PageData.y_ordered_list;
    while (y_list) {
        x_entry = y_list->x_ordered_list;
        while (x_entry) {
            gs_free(tdev->memory, x_entry->Unicode_Text, x_entry->Unicode_Text_Size, sizeof (usnigned short), "txtwrite free text fragment text buffer");
            gs_free(tdev->memory, x_entry->Widths, x_entry->Unicode_Text_Size, sizeof (float), "txtwrite free widths array");
            gs_free(tdev->memory, x_entry->FontName, 1, strlen(x_entry->FontName) + 1, "txtwrite free Font Name");
            if (x_entry->next) {
                x_entry = x_entry->next;
                gs_free(tdev->memory, x_entry->previous, 1, sizeof(text_list_entry_t), "txtwrite free text fragment");
            } else {
                gs_free(tdev->memory, x_entry, 1, sizeof(text_list_entry_t), "txtwrite free text fragment");
                x_entry = NULL;
            }
        }
        if (y_list->next) {
            y_list = y_list->next;
            gs_free(tdev->memory, y_list->previous, 1, sizeof(page_text_list_t), "txtwrite free text list");
        } else {
            gs_free(tdev->memory, y_list, 1, sizeof(page_text_list_t), "txtwrite free text list");
            y_list = NULL;
        }
    }
    tdev->PageData.y_ordered_list = NULL;

    /* free the unsorted fragment list */
    x_entry = tdev->PageData.unsorted_text_list;
    while (x_entry) {
        next_x = x_entry->next;
        gs_free(tdev->memory, x_entry->Unicode_Text, x_entry->Unicode_Text_Size, sizeof (usnigned short), "txtwrite free unsorted text fragment text buffer");
        gs_free(tdev->memory, x_entry->Widths, x_entry->Unicode_Text_Size, sizeof (float), "txtwrite free widths array");
        gs_free(tdev->memory, x_entry->FontName, 1, strlen(x_entry->FontName) + 1, "txtwrite free Font Name");
        gs_free(tdev->memory, x_entry, 1, sizeof(text_list_entry_t), "txtwrite free unsorted text fragment");
        x_entry = next_x;
    }
    tdev->PageData.unsorted_text_list = NULL;

    code = gx_parse_output_file_name(&parsed, &fmt, tdev->fname,
                                         strlen(tdev->fname), tdev->memory);

    if (code >= 0 && fmt) { /* file per page */
        code = gx_device_close_output_file(dev, tdev->fname, tdev->file);
        tdev->file = NULL;
    }
    return code;
}

Project: ghostpdl
File: gdevtxtw.c

static int decorated_text_output(gx_device_txtwrite_t *tdev)
{
    int i;
    text_list_entry_t * x_entry, *next_x;
    char TextBuffer[512], Escaped[32];
    float xpos;
    page_text_list_t *y_list;
#ifdef TRACE_TXTWRITE
    text_list_entry_t *debug_x;
#endif

    if (tdev->TextFormat == 0) {
        gp_fwrite("<page>\n", sizeof(unsigned char), 7, tdev->file);
        x_entry = tdev->PageData.unsorted_text_list;
        while (x_entry) {
            next_x = x_entry->next;
            gs_sprintf(TextBuffer, "<span bbox=\"%0.0f %0.0f %0.0f %0.0f\" font=\"%s\" size=\"%0.4f\">\n", x_entry->start.x, x_entry->start.y,
                x_entry->end.x, x_entry->end.y, x_entry->FontName,x_entry->size);
            gp_fwrite(TextBuffer, 1, strlen(TextBuffer), tdev->file);
            xpos = x_entry->start.x;
            for (i=0;i<x_entry->Unicode_Text_Size;i++) {
                escaped_Unicode(x_entry->Unicode_Text[i], (char *)&Escaped);
                gs_sprintf(TextBuffer, "<char bbox=\"%0.0f %0.0f %0.0f %0.0f\" c=\"%s\"/>\n", xpos,
                    x_entry->start.y, xpos + x_entry->Widths[i], x_entry->end.y, Escaped);
                gp_fwrite(TextBuffer, 1, strlen(TextBuffer), tdev->file);
                xpos += x_entry->Widths[i];
            }
            gp_fwrite("</span>\n", sizeof(unsigned char), 8, tdev->file);

            x_entry = next_x;
        }
        gp_fwrite("</page>\n", sizeof(unsigned char), 8, tdev->file);
    } else {

        merge_vertically(tdev);
        merge_horizontally(tdev);

        y_list = tdev->PageData.y_ordered_list;
        gp_fwrite("<page>\n", sizeof(unsigned char), 7, tdev->file);
        /* Walk the list looking for 'blocks' */
        do {
            page_text_list_t *temp;
            page_text_t block;
            page_text_list_t *block_line;
            float BBox[4];

            memset(&block, 0x00, sizeof(page_text_t));
            memset(BBox, 0x00, sizeof(float) * 4);

            while (y_list) {
                if (block.y_ordered_list) {
                    text_list_entry_t *x_entry = y_list->x_ordered_list;

                    block_line = block.y_ordered_list;
                    while (x_entry) {
                        if (x_entry->start.x > BBox[2] || x_entry->end.x < BBox[0] ||
                            x_entry->start.y > (BBox[1] + (BBox[3] - BBox[1]))) {
                                ;
                        } else {
                            block_line->next = (page_text_list_t *)gs_malloc(tdev->memory->stable_memory, 1,
                                sizeof(page_text_list_t), "txtwrite alloc Y-list");
                            memset(block_line->next, 0x00, sizeof(page_text_list_t));
                            block_line = block_line->next;
                            block_line->x_ordered_list = x_entry;
                            if(x_entry->next)
                                x_entry->next->previous = x_entry->previous;
                            if (x_entry->previous)
                                x_entry->previous->next = x_entry->next;
                            else {
                                if (x_entry->next == 0x00) {
                                    /* remove Y entry */
                                    temp = y_list->next;
                                    if (y_list->previous)
                                        y_list->previous->next = y_list->next;
                                    if (y_list->next)
                                        y_list->next->previous = y_list->previous;
                                    else {
                                        if (y_list->previous == 0x00) {
                                            tdev->PageData.y_ordered_list = 0x00;
                                        }
                                    }
                                    gs_free(tdev->memory, y_list, 1, sizeof(page_text_list_t), "txtwrite free text list");
                                    if (tdev->PageData.y_ordered_list == y_list)
                                        tdev->PageData.y_ordered_list = temp;
                                    y_list = temp;
                                    x_entry = x_entry->next;
                                    continue;
                                }
                            }
                            if (block_line->x_ordered_list->start.x < BBox[0])
                                BBox[0] = block_line->x_ordered_list->start.x;
                            if (block_line->x_ordered_list->start.y < BBox[1])
                                BBox[1] = block_line->x_ordered_list->start.y;
                            if (block_line->x_ordered_list->end.x < BBox[2])
                                BBox[2] = block_line->x_ordered_list->end.x;
                            if (block_line->x_ordered_list->end.y + block_line->x_ordered_list->FontBBox_topright.y < BBox[3])
                                BBox[3] = block_line->x_ordered_list->end.y + block_line->x_ordered_list->FontBBox_topright.y;
                        }
                        x_entry = x_entry->next;
                    }
                } else {
                    block.y_ordered_list = block_line = (page_text_list_t *)gs_malloc(tdev->memory->stable_memory, 1,
                        sizeof(page_text_list_t), "txtwrite alloc Y-list");
                    memset(block_line, 0x00, sizeof(page_text_list_t));
                    block_line->x_ordered_list = y_list->x_ordered_list;
                    y_list->x_ordered_list = y_list->x_ordered_list->next;
                    if (y_list->x_ordered_list == 0x00) {
                        temp = y_list->next;
                        if (y_list->previous)
                            y_list->previous->next = y_list->next;
                        if (y_list->next)
                            y_list->next->previous = y_list->previous;
                        else {
                            if (y_list->previous == 0x00) {
                                tdev->PageData.y_ordered_list = 0x00;
                            }
                        }
                        gs_free(tdev->memory, y_list, 1, sizeof(page_text_list_t), "txtwrite free text list");
                        if (tdev->PageData.y_ordered_list == y_list)
                            tdev->PageData.y_ordered_list = temp;
                        y_list = temp;
                        continue;
                    }
                    block_line->x_ordered_list->next = block_line->x_ordered_list->previous = 0x00;
                    BBox[0] = block_line->x_ordered_list->start.x;
                    BBox[1] = block_line->x_ordered_list->start.y;
                    BBox[2] = block_line->x_ordered_list->end.x;
                    BBox[3] = block_line->x_ordered_list->end.y + block_line->x_ordered_list->FontBBox_topright.y;
                }
                if (y_list)
                    y_list = y_list->next;
            }
            /* FIXME - need to free the used memory in here */
            gp_fwrite("<block>\n", sizeof(unsigned char), 8, tdev->file);
            block_line = block.y_ordered_list;
            while (block_line) {
                gp_fwrite("<line>\n", sizeof(unsigned char), 7, tdev->file);
                x_entry = block_line->x_ordered_list;
                while(x_entry) {
                    gs_sprintf(TextBuffer, "<span bbox=\"%0.0f %0.0f %0.0f %0.0f\" font=\"%s\" size=\"%0.4f\">\n", x_entry->start.x, x_entry->start.y,
                        x_entry->end.x, x_entry->end.y, x_entry->FontName,x_entry->size);
                    gp_fwrite(TextBuffer, 1, strlen(TextBuffer), tdev->file);
                    xpos = x_entry->start.x;
                    for (i=0;i<x_entry->Unicode_Text_Size;i++) {
                        escaped_Unicode(x_entry->Unicode_Text[i], (char *)&Escaped);
                        gs_sprintf(TextBuffer, "<char bbox=\"%0.0f %0.0f %0.0f %0.0f\" c=\"%s\"/>\n", xpos,
                            x_entry->start.y, xpos + x_entry->Widths[i], x_entry->end.y, Escaped);
                        gp_fwrite(TextBuffer, 1, strlen(TextBuffer), tdev->file);
                        xpos += x_entry->Widths[i];
                    }
                    gp_fwrite("</span>\n", sizeof(unsigned char), 8, tdev->file);
                    x_entry = x_entry->next;
                }
                gp_fwrite("</line>\n", sizeof(unsigned char), 8, tdev->file);
                block_line = block_line->next;
            }
            gp_fwrite("</block>\n", sizeof(unsigned char), 9, tdev->file);
            y_list = tdev->PageData.y_ordered_list;
        } while (y_list);

        gp_fwrite("</page>\n", sizeof(unsigned char), 8, tdev->file);
    }
    return 0;
}

Project: ghostpdl
File: zbfont.c

build_FDArray_sub_font(i_ctx_t *i_ctx_p, ref *op,
                       gs_font_base **ppfont,
                       font_type ftype, gs_memory_type_ptr_t pstype,
                       const build_proc_refs * pbuild,
                       build_font_options_t ignore_options)
{
    gs_font *pfont;
    int code = build_gs_sub_font(i_ctx_p, op, &pfont, ftype, pstype, pbuild,
                                 NULL, op);

    if (code >= 0)
        *ppfont = (gs_font_base *)pfont;
    return code;
}

Project: ghostpdl
File: zbfont.c

lookup_gs_simple_font_encoding(gs_font_base * pfont)
{
    const ref *pfe = &pfont_data(pfont)->Encoding;
    int index = -1;

    pfont->encoding_index = index;
    if (r_type(pfe) == t_array && r_size(pfe) <= 256) {
        /* Look for an encoding that's "close". */
        uint esize = r_size(pfe);
        int near_index = -1;
        uint best = esize / 3;	/* must match at least this many */
        gs_const_string fstrs[256];
        int i;

        /* Get the string names of the glyphs in the font's Encoding. */
        for (i = 0; i < esize; ++i) {
            ref fchar;

            if (array_get(pfont->memory, pfe, (long)i, &fchar) < 0 ||
                !r_has_type(&fchar, t_name)
                )
                fstrs[i].data = 0, fstrs[i].size = 0;
            else {
                ref nsref;

                name_string_ref(pfont->memory, &fchar, &nsref);
                fstrs[i].data = nsref.value.const_bytes;
                fstrs[i].size = r_size(&nsref);
            }
        }
        /* Compare them against the known encodings. */
        for (index = 0; index < NUM_KNOWN_REAL_ENCODINGS; ++index) {
            uint match = esize;

            for (i = esize; --i >= 0;) {
                gs_const_string rstr;

                gs_c_glyph_name(gs_c_known_encode((gs_char)i, index), &rstr);
                if (rstr.size == fstrs[i].size &&
                    !memcmp(rstr.data, fstrs[i].data, rstr.size)
                    )
                    continue;
                if (--match <= best)
                    break;
            }
            if (match > best) {
                best = match;
                near_index = index;
                /* If we have a perfect match, stop now. */
                if (best == esize)
                    break;
            }
        }
        index = near_index;
        if (best == esize)
            pfont->encoding_index = index;
    }
    pfont->nearest_encoding_index = index;
}

Project: ghostpdl
File: gdevtxtw.c

static int simple_text_output(gx_device_txtwrite_t *tdev)
{
    int chars_wide;
    float char_size, min_size, min_width_size;
#ifdef TRACE_TXTWRITE
    text_list_entry_t *debug_x;
#endif
    text_list_entry_t * x_entry;
    page_text_list_t *y_list;
    unsigned short UnicodeSpace = 0x20, UnicodeEOL[2] = {0x00D, 0x0a};

    merge_vertically(tdev);

    merge_horizontally(tdev);

    min_size = (float)tdev->width;
    /* Estimate maximum text density */
    y_list = tdev->PageData.y_ordered_list;
    while (y_list) {
        x_entry = y_list->x_ordered_list;
        while (x_entry) {
            if (x_entry->size < min_size)
                min_size = x_entry->size;
            x_entry = x_entry->next;
        }
        y_list = y_list->next;
    }

    min_width_size = min_size;
    y_list = tdev->PageData.y_ordered_list;
    while (y_list) {
        float width;

        x_entry = y_list->x_ordered_list;
        while (x_entry) {
            width = (x_entry->end.x - x_entry->start.x) / x_entry->Unicode_Text_Size;
            if (x_entry->next) {
                /* If we have following text, check to see if *not* using the newly calculated size would result in
                 * the end of the text going past the beginning of the following text. If it does then we must
                 * use the new minimum, regardless of how small it is! The foregoing comment isn't quite true...
                 * we never used a width of 0 because that would result in an endless loop, we need to allow a little
                 * slop in case rounding errors mean that the x difference from start to end of the text is almost,
                 * but not quite, zero.
                 */
                if (x_entry->start.x + ((x_entry->Unicode_Text_Size + 1) * min_width_size) > x_entry->next->start.x && width > 0.001)
                    min_width_size = width;
            } else {
                if (width < min_width_size && width >= (float)min_size * 0.75)
                    min_width_size = width;
            }
            x_entry = x_entry->next;
        }
        y_list = y_list->next;
    }

    min_size = min_width_size;
    chars_wide = (int)ceil(tdev->width / min_size);
    char_size = (float)tdev->width / (float)chars_wide;

    y_list = tdev->PageData.y_ordered_list;
    while (y_list) {
        float xpos = 0;
        x_entry = y_list->x_ordered_list;
        while (x_entry) {
            while (xpos < x_entry->start.x) {
                write_simple_text(&UnicodeSpace, 1, tdev);
                xpos += char_size;
            }
            write_simple_text(x_entry->Unicode_Text, x_entry->Unicode_Text_Size, tdev);
            xpos += x_entry->Unicode_Text_Size * char_size;
            if (x_entry->next) {
                x_entry = x_entry->next;
            } else {
                x_entry = NULL;
            }
        }
        write_simple_text((unsigned short *)&UnicodeEOL, 2, tdev);
        if (y_list->next) {
            y_list = y_list->next;
        } else {
            y_list = NULL;
        }
    }
    return 0;
}

Project: ghostpdl
File: zbfont.c

RELOC_PTRS_BEGIN(font_data_reloc_ptrs)
{
    ref_struct_reloc_ptrs(vptr, offset_of(font_data, u.type42.mru_sfnts_index)/*size*/, pstype, gcst);
}

Project: ghostpdl
File: gdevtxtw.c

static int merge_vertically(gx_device_txtwrite_t *tdev)
{
#ifdef TRACE_TXTWRITE
    text_list_entry_t *debug_x;
#endif
    page_text_list_t *y_list = tdev->PageData.y_ordered_list;

    while (y_list && y_list->next) {
        page_text_list_t *next = y_list->next;
        bool collision = false;
        float overlap = (y_list->start.y + y_list->MaxY) - (next->start.y + next->MinY);

        if (overlap >= (y_list->MaxY - y_list->MinY) / 4) {
            /* At least a 25% overlap, lets test for x collisions */
            text_list_entry_t *upper = y_list->x_ordered_list, *lower;
            while (upper && !collision) {
                lower = next->x_ordered_list;
                while (lower && !collision) {
                    if (upper->start.x >= lower->start.x) {
                        if (upper->start.x <= lower->end.x) {
                            /* Collision */
                            collision = true;
                            break;
                        }
                    } else {
                        if (upper->end.x > lower->start.x) {
                            /* Collision */
                            collision = true;
                            break;
                        }
                    }
                    lower = lower->next;
                }
                upper = upper->next;
            }
            if (!collision) {
                text_list_entry_t *from, *to, *new_order, *current;
                /* Consolidate y lists */
                to = y_list->x_ordered_list;
                from = next->x_ordered_list;
#ifdef TRACE_TXTWRITE
                fprintf(tdev->DebugFile, "\nConsolidating two horizontal lines, line 1:");
                debug_x = from;
                while (debug_x) {
                    gp_fprintf(tdev->DebugFile, "\n\t");
                    gp_fwrite(debug_x->Unicode_Text, sizeof(unsigned short), debug_x->Unicode_Text_Size, tdev->DebugFile);
                    debug_x = debug_x->next;
                }
                fprintf(tdev->DebugFile, "\nConsolidating two horizontal lines, line 2");
                debug_x = to;
                while (debug_x) {
                    gp_fprintf(tdev->DebugFile, "\n\t");
                    gp_fwrite(debug_x->Unicode_Text, sizeof(unsigned short), debug_x->Unicode_Text_Size, tdev->DebugFile);
                    debug_x = debug_x->next;
                }
#endif
                if (from->start.x < to->start.x) {
                    current = new_order = from;
                    from = from->next;
                } else {
                    current = new_order = to;
                    to = to->next;
                }
                while (to && from) {
                    if (to->start.x < from->start.x) {
                        current->next = to;
                        to->previous = current;
                        to = to->next;
                    } else {
                        current->next = from;
                        from->previous = current;
                        from = from->next;
                    }
                    current = current->next;
                }
                if (to) {
                    to->previous = current;
                    current->next = to;
                } else {
                    if (from) {
                        from->previous = current;
                        current->next = from;
                    }
                }
                y_list->x_ordered_list = new_order;
#ifdef TRACE_TXTWRITE
                fprintf(tdev->DebugFile, "\nAfter:");
                debug_x = new_order;
                while (debug_x) {
                    gp_fprintf(tdev->DebugFile, "\n\t");
                    gp_fwrite(debug_x->Unicode_Text, sizeof(unsigned short), debug_x->Unicode_Text_Size, tdev->DebugFile);
                    debug_x = debug_x->next;
                }
                fprintf(tdev->DebugFile, "\n");
#endif
                y_list->next = next->next;
                if (next->next)
                    next->next->previous = y_list;
                gs_free(tdev->memory, next, 1, sizeof(page_text_list_entry_t), "txtwrite free text list");
            } else
                y_list = next;
        } else
            y_list = next;
    }
    return 0;
}

Project: ghostpdl
File: gdevtxtw.c

txt_shift_text_currentpoint(textw_text_enum_t *penum, gs_point *wpt)
{
    return gs_moveto_aux(penum->pgs, gx_current_path(penum->pgs),
                              fixed2float(penum->origin.x) + wpt->x,
                              fixed2float(penum->origin.y) + wpt->y);
}

Project: ghostpdl
File: zbfont.c

init_gs_simple_font(gs_font_base *pfont, const double bbox[4],
                    const gs_uid *puid)
{
    pfont->FontBBox.p.x = bbox[0];
    pfont->FontBBox.p.y = bbox[1];
    pfont->FontBBox.q.x = bbox[2];
    pfont->FontBBox.q.y = bbox[3];
    pfont->UID = *puid;
}

Project: ghostpdl
File: gdevtxtw.c

txtwrite_stroke_path(gx_device * dev, const gs_gstate * pgs, gx_path * ppath,
                 const gx_stroke_params * params,
                 const gx_drawing_color * pdevc, const gx_clip_path * pcpath)
{
    return 0;
}

Project: ghostpdl
File: zbfont.c

zbuildfont3(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    int code;
    build_proc_refs build;
    gs_font_base *pfont;

    check_type(*op, t_dictionary);
    code = build_gs_font_procs(op, &build);
    if (code < 0)
        return code;
    code = build_gs_simple_font(i_ctx_p, op, &pfont, ft_user_defined,
                                &st_gs_font_base, &build, bf_options_none);
    if (code < 0)
        return code;
    return define_gs_font(i_ctx_p, (gs_font *) pfont);
}

Project: ghostpdl
File: gdevtxtw.c

txtwrite_process_cmap_text(gs_text_enum_t *pte)
{
    textw_text_enum_t *const penum = (textw_text_enum_t *)pte;
    unsigned int rcode = 0;
    gs_text_enum_t scan = *(gs_text_enum_t *)pte;

    /* Composite font using a CMap */
    for ( ; ; ) {
        gs_glyph glyph;
        int font_code, code;
        gs_font *subfont;
        gs_char chr;
        txt_glyph_widths_t widths;
        gs_matrix m3;
        gs_point wanted;	/* user space */
        gs_point dpt = {0,0};

        font_code = scan.orig_font->procs.next_char_glyph
                (&scan, &chr, &glyph);

        subfont = scan.fstack.items[scan.fstack.depth].font;

        switch (font_code) {
            case 0:		/* no font change */
            case 1:		/* font change */
                code = txt_glyph_widths(subfont, scan.orig_font->WMode, glyph, (gs_font *)subfont, &widths,
                        penum->cdevproc_callout ? penum->cdevproc_result : NULL);
                if (code == TEXT_PROCESS_CDEVPROC) {
                    penum->cdevproc_callout = true;
                    pte->returned.current_glyph = glyph;
                    scan.returned.current_glyph = glyph;
                    pte->current_font = subfont;
                    scan.current_font = subfont;
                    rcode = TEXT_PROCESS_CDEVPROC;
                    break;
                }
                else {
                    penum->cdevproc_callout = false;
                    pte->index = scan.index;
                }
                code = gs_matrix_multiply(&subfont->FontMatrix, &pte->orig_font->FontMatrix, &m3);
                if (code < 0)
                    return code;
                code = txt_update_text_state(penum->text_state, (textw_text_enum_t *)pte, pte->orig_font, &m3);
                if (code < 0)
                    return code;
                txt_char_widths_to_uts(pte->orig_font, &widths); /* convert design->text space */
                gs_distance_transform(widths.real_width.xy.x * penum->text_state->size,
                          widths.real_width.xy.y * penum->text_state->size,
                          &penum->text_state->matrix, &wanted);
                pte->returned.total_width.x += wanted.x;
                pte->returned.total_width.y += wanted.y;
                penum->Widths[penum->TextBufferIndex] = wanted.x;

                if (pte->text.operation & TEXT_ADD_TO_ALL_WIDTHS) {
                    gs_point tpt;

                    gs_distance_transform(pte->text.delta_all.x, pte->text.delta_all.y,
                              &ctm_only(pte->pgs), &tpt);
                    dpt.x += tpt.x;
                    dpt.y += tpt.y;
                }
                if (pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH && chr == pte->text.space.s_char) {
                    gs_point tpt;

                    gs_distance_transform(pte->text.delta_space.x, pte->text.delta_space.y,
                              &ctm_only(pte->pgs), &tpt);
                    dpt.x += tpt.x;
                    dpt.y += tpt.y;
                }
                pte->returned.total_width.x += dpt.x;
                pte->returned.total_width.y += dpt.y;

                penum->Widths[penum->TextBufferIndex] += dpt.x;
                penum->TextBufferIndex += get_unicode(penum, (gs_font *)pte->orig_font, glyph, chr, &penum->TextBuffer[penum->TextBufferIndex]);
                break;
            case 2:		/* end of string */
                return 0;
            default:	        /* error */
                return font_code;
        }
        if (rcode || pte->index >= pte->text.size)
            break;
    }
    return rcode;
}

Project: ghostpdl
File: zbfont.c

build_gs_simple_font(i_ctx_t *i_ctx_p, os_ptr op, gs_font_base ** ppfont,
                     font_type ftype, gs_memory_type_ptr_t pstype,
                     const build_proc_refs * pbuild,
                     build_font_options_t options)
{
    double bbox[4];
    gs_uid uid;
    int code;
    gs_font_base *pfont;
    uint space = ialloc_space(idmemory);

    code = font_bbox_param(imemory, op, bbox);
    if (code < 0)
        return code;
    /*
     * Make sure that we allocate uid
     * in the same VM as the font dictionary
     * (see build_gs_sub_font).
     */
    ialloc_set_space(idmemory, r_space(op));
    code = dict_uid_param(op, &uid, 0, imemory, i_ctx_p);
    ialloc_set_space(idmemory, space);
    if (code < 0)
        return code;
    if ((options & bf_UniqueID_ignored) && uid_is_UniqueID(&uid))
        uid_set_invalid(&uid);
    code = build_gs_font(i_ctx_p, op, (gs_font **) ppfont, ftype, pstype,
                         pbuild, options);
    if (code != 0)		/* invalid or scaled font */
        return code;
    pfont = *ppfont;
    pfont->procs.init_fstack = gs_default_init_fstack;
    pfont->procs.define_font = gs_no_define_font;
    pfont->procs.decode_glyph = gs_font_map_glyph_to_unicode;
    pfont->procs.make_font = zbase_make_font;
    pfont->procs.next_char_glyph = gs_default_next_char_glyph;
    pfont->FAPI = 0;
    pfont->FAPI_font_data = 0;
    init_gs_simple_font(pfont, bbox, &uid);
    lookup_gs_simple_font_encoding(pfont);
    get_GlyphNames2Unicode(i_ctx_p, (gs_font *)pfont, op);
    return 0;
}

Project: ghostpdl
File: gdevtxtw.c

txtwrite_put_params(gx_device * dev, gs_param_list * plist)
{
    gx_device_txtwrite_t *tdev = (gx_device_txtwrite_t *) dev;
    int ecode = 0;
    int code;
    const char *param_name;
    gs_param_string ofs;
    bool dummy;

    switch (code = param_read_string(plist, (param_name = "OutputFile"), &ofs)) {
        case 0:
            if (dev->LockSafetyParams &&
                    bytes_compare(ofs.data, ofs.size,
                        (const byte *)tdev->fname, strlen(tdev->fname))) {
                ecode = gs_note_error(gs_error_invalidaccess);
                goto ofe;
            }
            if (ofs.size >= gp_file_name_sizeof)
                ecode = gs_error_limitcheck;
            else
                break;
            goto ofe;
        default:
            ecode = code;
          ofe:param_signal_error(plist, param_name, ecode);
        /* fall through */
        case 1:
            ofs.data = 0;
            break;
    }

    if (ecode < 0)
        return ecode;

    code = param_read_int(plist, "TextFormat", &tdev->TextFormat);
    if (code < 0)
        return code;

    code = param_read_bool(plist, "WantsToUnicode", &dummy);
    if (code < 0)
        return code;

    code = param_read_bool(plist, "HighLevelDevice", &dummy);
    if (code < 0)
        return code;

    code = param_read_bool(plist, "PreserveTrMode", &dummy);
    if (code < 0)
        return code;

    code = gx_default_put_params(dev, plist);
    if (code < 0)
        return code;

    dev->interpolate_control = 0;

    if (ofs.data != 0) {	/* Close the file if it's open. */
        if (tdev->file != 0) {
            gp_fclose(tdev->file);
            tdev->file = 0;
        }
        memcpy(tdev->fname, ofs.data, ofs.size);
        tdev->fname[ofs.size] = 0;
    }
    return 0;
}

Project: ghostpdl
File: gdevtxtw.c

txtwrite_font_orig_matrix(const gs_font *font, gs_glyph cid, gs_matrix *pmat)
{
    int code;

    switch (font->FontType) {
    case ft_composite:                /* subfonts have their own FontMatrix */
    case ft_TrueType:
    case ft_CID_TrueType:
        /* The TrueType FontMatrix is 1 unit per em, which is what we want. */
        gs_make_identity(pmat);
        return 0;
    case ft_encrypted:
    case ft_encrypted2:
    case ft_CID_encrypted:
    case ft_user_defined:
    case ft_PCL_user_defined:
    case ft_GL2_stick_user_defined:
    case ft_GL2_531:
        /*
         * Type 1 fonts are supposed to use a standard FontMatrix of
         * [0.001 0 0 0.001 0 0], with a 1000-unit cell.  However,
         * Windows NT 4.0 creates Type 1 fonts, apparently derived from
         * TrueType fonts, that use a 2048-unit cell and corresponding
         * FontMatrix.  Also, some PS programs perform font scaling by
         * replacing FontMatrix like this :
         *
         *   /f12 /Times-Roman findfont
         *   copyfont          % (remove FID)
         *   dup /FontMatrix [0.012 0 0 0.012 0 0] put
         *   definefont
         *   /f12 1 selectfont
         *
         * Such fonts are their own "base font", but the orig_matrix
         * must still be set to 0.001, not 0.012 .
         *
         * The old code used a heuristic to detect and correct for this here.
         * Unfortunately it doesn't work properly when it meets a font
         * with FontMatrix like this :
         *
         *   /FontMatrix [1 2288 div 0 0 1 2288 div 0 0 ] def
         *
         * (the bug 686970). Also comparefiles\455690.pdf appears to
         * have similar problem. Therefore we added a support to lib/gs_fonts.ps,
         * src/zbfont.c, src/gsfont.c that provides an acces to the original
         * font via a special key OrigFont added to the font dictionary while definefont.
         * Now we work through this access with PS interpreter,
         * but keep the old heuristic for other clients.
         */
        {
            const gs_font *base_font = font;

            while (base_font->base != base_font)
                base_font = base_font->base;
            if (font->FontType == ft_user_defined ||
                font->FontType == ft_PCL_user_defined ||
                font->FontType == ft_GL2_stick_user_defined ||
                font->FontType == ft_GL2_531)
                *pmat = base_font->FontMatrix;
            else if (base_font->orig_FontMatrix.xx != 0 || base_font->orig_FontMatrix.xy != 0 ||
                base_font->orig_FontMatrix.yx != 0 || base_font->orig_FontMatrix.yy != 0)
                *pmat = base_font->orig_FontMatrix;
            else {
                /*  Must not happen with PS interpreter.
                    Provide a hewuristic for other clients.
                */
                if (base_font->FontMatrix.xx == 1.0/2048 &&
                    base_font->FontMatrix.xy == 0 &&
                    base_font->FontMatrix.yx == 0 &&
                    any_abs(base_font->FontMatrix.yy) == 1.0/2048
                    )
                    *pmat = base_font->FontMatrix;
                else
                    gs_make_scaling(0.001, 0.001, pmat);
            }
        }
        if (font->FontType == ft_CID_encrypted && cid != -1) {
            int fidx;

            if (cid < GS_MIN_CID_GLYPH)
                cid = GS_MIN_CID_GLYPH;
            code = ((gs_font_cid0 *)font)->cidata.glyph_data((gs_font_base *)font,
                                cid, NULL, &fidx);
            if (code < 0) {
                code = ((gs_font_cid0 *)font)->cidata.glyph_data((gs_font_base *)font,
                                (gs_glyph)GS_MIN_CID_GLYPH, NULL, &fidx);
            }
            if (code >= 0) {
                gs_matrix_multiply(&(gs_cid0_indexed_font(font, fidx)->FontMatrix),
                                pmat, pmat);
            }
        }
        return 0;
    default:
        return_error(gs_error_rangecheck);
    }
}

Project: ghostpdl
File: gdevtxtw.c

store_glyph_width(txt_glyph_width_t *pwidth, int wmode, const gs_matrix *scale,
                  const gs_glyph_info_t *pinfo)
{
    double w, v;

    gs_distance_transform(pinfo->width[wmode].x, pinfo->width[wmode].y, scale, &pwidth->xy);
    if (wmode)
        w = pwidth->xy.y, v = pwidth->xy.x;
    else
        w = pwidth->xy.x, v = pwidth->xy.y;
    if (v != 0)
        return 1;
    pwidth->w = w;
    gs_distance_transform(pinfo->v.x, pinfo->v.y, scale, &pwidth->v);
    return 0;
}

Project: ghostpdl
File: gdevtxtw.c

textw_text_is_width_only(const gs_text_enum_t *pte)
{
    return false;
}

Project: ghostpdl
File: gdevtxtw.c

textw_text_release(gs_text_enum_t *pte, client_name_t cname)
{
    textw_text_enum_t *const penum = (textw_text_enum_t *)pte;
    gx_device_txtwrite_t *const tdev = (gx_device_txtwrite_t *) pte->dev;

    /* Free the working buffer where the Unicode was assembled from the enumerated text */
    if (penum->TextBuffer)
        gs_free(tdev->memory, penum->TextBuffer, 1, penum->TextBufferIndex, "txtwrite free temporary text buffer");
    if (penum->Widths)
        gs_free(tdev->memory, penum->Widths, sizeof(float), pte->text.size, "txtwrite free temporary widths array");
    /* If this is copied away when we complete the text enumeration succesfully, then
     * we set the pointer to NULL, if we get here with it non-NULL , then there was
     * an error.
     */
    if (penum->text_state)
        gs_free(tdev->memory, penum->text_state, 1, sizeof(penum->text_state), "txtwrite free text state");

    gs_text_release(pte, cname);
}