コード例 #1
0
ファイル: zfsample.c プロジェクト: hackqiang/gs
/*
 * We have collected all of the sample data.  Create a type 0 function stucture.
 */
static int
sampled_data_finish(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    gs_sampled_data_enum *penum = senum;
    /* Build a type 0 function using the given parameters */
    gs_function_Sd_params_t * params =
        (gs_function_Sd_params_t *)&penum->pfn->params;
    gs_function_t * pfn;
    ref cref;			/* closure */
    int code = gs_function_Sd_init(&pfn, params, imemory);

    if (code < 0)
        return code;

    code = ialloc_ref_array(&cref, a_executable | a_execute, 2,
                            "sampled_data_finish(cref)");
    if (code < 0)
        return code;

    make_istruct_new(cref.value.refs, a_executable | a_execute, pfn);
    make_oper_new(cref.value.refs + 1, 0, zexecfunction);
    ref_assign(op, &cref);

    esp -= estack_storage;
    ifree_object(penum->pfn, "sampled_data_finish(pfn)");
    ifree_object(penum, "sampled_data_finish(enum)");
    return o_pop_estack;
}
コード例 #2
0
ファイル: zcrd.c プロジェクト: MasterPlexus/vendor_goldenve
int
cie_cache_joint(i_ctx_t *i_ctx_p, const ref_cie_render_procs * pcrprocs,
		const gs_cie_common *pcie, gs_state * pgs)
{
    const gs_cie_render *pcrd = gs_currentcolorrendering(pgs);
    gx_cie_joint_caches *pjc = gx_unshare_cie_caches(pgs);
    gs_ref_memory_t *imem = (gs_ref_memory_t *) gs_state_memory(pgs);
    ref pqr_procs;
    uint space;
    int code;
    int i;

    if (pcrd == 0)		/* cache is not set up yet */
	return 0;
    if (pjc == 0)		/* must already be allocated */
	return_error(e_VMerror);
    if (r_has_type(&pcrprocs->TransformPQR, t_null)) {
	/*
	 * This CRD came from a driver, not from a PostScript dictionary.
	 * Resample TransformPQR in C code.
	 */
	return gs_cie_cs_complete(pgs, true);
    }
    gs_cie_compute_points_sd(pjc, pcie, pcrd);
    code = ialloc_ref_array(&pqr_procs, a_readonly, 3 * (1 + 4 + 4 * 6),
			    "cie_cache_common");
    if (code < 0)
	return code;
    /* When we're done, deallocate the procs and complete the caches. */
    check_estack(3);
    cie_cache_push_finish(i_ctx_p, cie_tpqr_finish, imem, pgs);
    *++esp = pqr_procs;
    space = r_space(&pqr_procs);
    for (i = 0; i < 3; i++) {
	ref *p = pqr_procs.value.refs + 3 + (4 + 4 * 6) * i;
	const float *ppt = (float *)&pjc->points_sd;
	int j;

	make_array(pqr_procs.value.refs + i, a_readonly | a_executable | space,
		   4, p);
	make_array(p, a_readonly | space, 4 * 6, p + 4);
	p[1] = pcrprocs->TransformPQR.value.refs[i];
	make_oper(p + 2, 0, cie_exec_tpqr);
	make_oper(p + 3, 0, cie_post_exec_tpqr);
	for (j = 0, p += 4; j < 4 * 6; j++, p++, ppt++)
	    make_real(p, *ppt);
    }
    return cie_prepare_cache3(i_ctx_p, &pcrd->RangePQR,
			      pqr_procs.value.const_refs,
			      pjc->TransformPQR.caches,
			      pjc, imem, "Transform.PQR");
}
コード例 #3
0
ファイル: zarray.c プロジェクト: 99years/plan9
/* <int> array <array> */
int
zarray(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    uint size;
    int code;

    check_int_leu(*op, max_array_size);
    size = op->value.intval;
    code = ialloc_ref_array((ref *)op, a_all, size, "array");
    if (code < 0)
	return code;
    refset_null(op->value.refs, size);
    return 0;
}
コード例 #4
0
ファイル: zfunc.c プロジェクト: computersforpeace/ghostpdl
/* Create a function procedure from a function structure. */
static int
make_function_proc(i_ctx_t *i_ctx_p, ref *op, gs_function_t *pfn)
{
    ref cref;			/* closure */
    int code;

    code = ialloc_ref_array(&cref, a_executable | a_execute, 2,
                            ".buildfunction");
    if (code < 0)
        return code;
    make_istruct_new(cref.value.refs, a_executable | a_execute, pfn);
    make_oper_new(cref.value.refs + 1, 0, zexecfunction);
    ref_assign(op, &cref);
    return 0;
}
コード例 #5
0
ファイル: zarray.c プロジェクト: computersforpeace/ghostpdl
/* <int> array <array> */
int
zarray(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    uint size;
    int code;

    check_type(*op, t_integer);
    if (op->value.intval < 0)
        return_error(gs_error_rangecheck);
    if (op->value.intval > max_array_size)
        return_error(gs_error_limitcheck);
    size = op->value.intval;
    code = ialloc_ref_array((ref *)op, a_all, size, "array");
    if (code < 0)
        return code;
    refset_null(op->value.refs, size);
    return 0;
}
コード例 #6
0
ファイル: iinit.c プロジェクト: jonathan-mui/ruby-ghostscript
/* Create an op_array table. */
static int
alloc_op_array_table(i_ctx_t *i_ctx_p, uint size, uint space,
                     op_array_table *opt)
{
    uint save_space = ialloc_space(idmemory);
    int code;

    ialloc_set_space(idmemory, space);
    code = ialloc_ref_array(&opt->table, a_readonly, size,
                            "op_array table");
    ialloc_set_space(idmemory, save_space);
    if (code < 0)
        return code;
    refset_null(opt->table.value.refs, size);
    opt->nx_table =
        (ushort *) ialloc_byte_array(size, sizeof(ushort),
                                     "op_array nx_table");
    if (opt->nx_table == 0)
        return_error(e_VMerror);
    opt->count = 0;
    opt->attrs = space | a_executable;
    return 0;
}
コード例 #7
0
ファイル: iinit.c プロジェクト: MasterPlexus/vendor_goldenve
/* initialize the dictionaries that hold operator definitions. */
int
obj_init(i_ctx_t **pi_ctx_p, gs_dual_memory_t *idmem)
{
    int level = gs_op_language_level();
    ref system_dict;
    i_ctx_t *i_ctx_p;
    int code;

    /*
     * Create systemdict.  The context machinery requires that
     * we do this before initializing the interpreter.
     */
    code = dict_alloc(idmem->space_global,
		      (level >= 3 ? SYSTEMDICT_LL3_SIZE :
		       level >= 2 ? SYSTEMDICT_LEVEL2_SIZE : SYSTEMDICT_SIZE),
		      &system_dict);
    if (code < 0)
	return code;

    /* Initialize the interpreter. */
    code = gs_interp_init(pi_ctx_p, &system_dict, idmem);
    if (code < 0)
	return code;
    i_ctx_p = *pi_ctx_p;

    {
#define icount countof(initial_dictionaries)
	ref idicts[icount];
	int i;
	const op_def *const *tptr;

	min_dstack_size = MIN_DSTACK_SIZE;

	refset_null(idicts, icount);

	/* Put systemdict on the dictionary stack. */
	if (level >= 2) {
	    dsp += 2;
	    /*
	     * For the moment, let globaldict be an alias for systemdict.
	     */
	    dsp[-1] = system_dict;
	    min_dstack_size++;
	} else {
	    ++dsp;
	}
	*dsp = system_dict;

	/* Create dictionaries which are to be homes for operators. */
	for (tptr = op_defs_all; *tptr != 0; tptr++) {
	    const op_def *def;

	    for (def = *tptr; def->oname != 0; def++)
		if (op_def_is_begin_dict(def)) {
		    if (make_initial_dict(i_ctx_p, def->oname, idicts) == 0)
			return_error(e_VMerror);
		}
	}

	/* Set up the initial dstack. */
	for (i = 0; i < countof(initial_dstack); i++) {
	    const char *dname = initial_dstack[i];

	    ++dsp;
	    if (!strcmp(dname, "userdict"))
		dstack_userdict_index = dsp - dsbot;
	    ref_assign(dsp, make_initial_dict(i_ctx_p, dname, idicts));
	}

	/* Enter names of referenced initial dictionaries into systemdict. */
	initial_enter_name("systemdict", systemdict);
	for (i = 0; i < icount; i++) {
	    ref *idict = &idicts[i];

	    if (!r_has_type(idict, t_null)) {
		/*
		 * Note that we enter the dictionary in systemdict
		 * even if it is in local VM.  There is a special
		 * provision in the garbage collector for this:
		 * see ivmspace.h for more information.
		 * In order to do this, we must temporarily
		 * identify systemdict as local, so that the
		 * store check in dict_put won't fail.
		 */
		uint save_space = r_space(systemdict);

		r_set_space(systemdict, avm_local);
		code = initial_enter_name(initial_dictionaries[i].name,
					  idict);
		r_set_space(systemdict, save_space);
		if (code < 0)
		    return code;
	    }
	}
#undef icount
    }

    gs_interp_reset(i_ctx_p);

    {
	ref vnull, vtrue, vfalse;

	make_null(&vnull);
	make_true(&vtrue);
	make_false(&vfalse);
	if ((code = initial_enter_name("null", &vnull)) < 0 ||
	    (code = initial_enter_name("true", &vtrue)) < 0 ||
	    (code = initial_enter_name("false", &vfalse)) < 0
	    )
	    return code;
    }

    /* Create the error name table */
    {
	int n = countof(gs_error_names) - 1;
	int i;
	ref era;

	code = ialloc_ref_array(&era, a_readonly, n, "ErrorNames");
	if (code < 0)
	    return code;
	for (i = 0; i < n; i++)
	  if ((code = name_enter_string(imemory, (const char *)gs_error_names[i],
					  era.value.refs + i)) < 0)
		return code;
	return initial_enter_name("ErrorNames", &era);
    }
}
コード例 #8
0
/* .getnativefonts [ [<name> <path>] ... ] */
static int
z_fontenum(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    void *enum_state;
    int code = 0;
    int e,elements;
    char *fontname, *path;
    fontenum_t *r, *results;
    ref array;
    uint length;
    byte *string;
	
    enum_state = gp_enumerate_fonts_init(imemory);
    if (enum_state == NULL) {
      /* put false on the stack and return */
      push(1);
      make_bool(op, false);
      return code;
    }

    r = results = gs_malloc(imemory->non_gc_memory, 1, sizeof(fontenum_t), "fontenum list");
    elements = 0;
    while((code = gp_enumerate_fonts_next(enum_state, &fontname, &path )) > 0) {
	if (fontname == NULL || path == NULL) {
	    gp_enumerate_fonts_free(enum_state);
	    return_error(e_ioerror);
	}

	length = strlen(fontname) + 1;
	r->fontname = gs_malloc(imemory->non_gc_memory, length, 1, "native font name");
	memcpy(r->fontname, fontname, length);

	length = strlen(path) + 1;
	    r->path = gs_malloc(imemory->non_gc_memory, length, 1, "native font path");
	    memcpy(r->path, path, length);

	    r->next = gs_malloc(imemory->non_gc_memory, 1, sizeof(fontenum_t), "fontenum list");
	    r = r->next;
	    elements += 1;
	}
	
	gp_enumerate_fonts_free(enum_state);

	code = ialloc_ref_array(&array, a_all | icurrent_space, elements, "native fontmap");

	r = results;
	for (e = 0; e < elements; e++) {
	    ref mapping;
	
	    code = ialloc_ref_array(&mapping, a_all | icurrent_space, 2, "native font mapping");
		
	    length = strlen(r->fontname);
	    string = ialloc_string(length, "native font name");
	    if (string == NULL)
		return_error(e_VMerror);
	    memcpy(string, r->fontname, length);
	    make_string(&(mapping.value.refs[0]), a_all | icurrent_space, length, string);
	 	
	    length = strlen(r->path);
	    string = ialloc_string(length, "native font path");
	    if (string == NULL)
		return_error(e_VMerror);
	    memcpy(string, r->path, length);
	    make_string(&(mapping.value.refs[1]), a_all | icurrent_space, length, string);
	 	
	    ref_assign(&(array.value.refs[e]), &mapping);
	    results = r;
	    r = r->next;

	    gs_free(imemory->non_gc_memory, 
		    results->fontname, strlen(results->fontname) + 1, 1, "native font name");
	    gs_free(imemory->non_gc_memory, 
		    results->path, strlen(results->path) + 1, 1, "native font path");
	    gs_free(imemory->non_gc_memory, 
		    results, 1, sizeof(fontenum_t), "fontenum list");
	}

    push(2);   
    ref_assign(op-1, &array);
    make_bool(op, true);
	
    return code;
}
コード例 #9
0
ファイル: zupath.c プロジェクト: BorodaZizitopa/ghostscript
static int
zgetpath(i_ctx_t *i_ctx_p)
{
    os_ptr op = osp;
    int i, code, path_size, leaf_count;
    ref *main_ref, *operators[5];

    push(1);
    path_size = code = path_length_for_upath(igs->path);
    if (code < 0)
        return code;
    leaf_count = (path_size + max_array_size - 1) / max_array_size;
    code = ialloc_ref_array(op, a_all, leaf_count, "zgetpath_master");
    if (code < 0)
        return code;
    if (path_size == 0)
        return 0;

    if (dict_find_string(systemdict, "moveto", &operators[1]) <= 0 ||
        dict_find_string(systemdict, "lineto", &operators[2]) <= 0 ||
        dict_find_string(systemdict, "curveto", &operators[3]) <= 0 ||
        dict_find_string(systemdict, "closepath", &operators[4]) <= 0)
          return_error(e_undefined);

    main_ref = op->value.refs;
    for (i = 0; i < leaf_count; i++) {
       int leaf_size = ( i == leaf_count - 1) ? path_size - i * max_array_size : max_array_size;
       code = ialloc_ref_array(&main_ref[i], a_all | a_executable, leaf_size, "zgetpath_leaf");
       if (code < 0)
            return code;
    }

    {
        int pe, j, k;
        gs_path_enum penum;
        static const int oper_count[5] = { 0, 2, 2, 6, 0 };
        gs_point pts[3];
        const double  *fts[6];

        fts[0] = &pts[0].x;
        fts[1] = &pts[0].y;
        fts[2] = &pts[1].x;
        fts[3] = &pts[1].y;
        fts[4] = &pts[2].x;
        fts[5] = &pts[2].y;

        main_ref = op->value.refs;
        gs_path_enum_copy_init(&penum, igs, false);
        pe = gs_path_enum_next(&penum, pts);
        if (pe < 0)
            return pe;
        k = 0;

        for (i = 0; i < leaf_count; i++) {
            int leaf_size = ( i == leaf_count - 1) ? path_size - i * max_array_size : max_array_size;
            ref *leaf_ref = main_ref[i].value.refs;

            for (j = 0; j < leaf_size; j++) {
                if (k < oper_count[pe])
                   make_real_new(&leaf_ref[j], (float)*fts[k++]);
                else {
                    k = 0;
                    ref_assign(&leaf_ref[j], operators[pe]);
                    pe = gs_path_enum_next(&penum, pts);
                    if (pe <= 0)
                        return pe;
                    if (pe >= 5)
                        return_error(e_unregistered);
                }
            }
        }
     }
  return 0;
}
コード例 #10
0
ファイル: zupath.c プロジェクト: BorodaZizitopa/ghostscript
int
make_upath(i_ctx_t *i_ctx_p, ref *rupath, gs_state *pgs, gx_path *ppath,
           bool with_ucache)
{
    int size = (with_ucache ? 6 : 5);
    gs_path_enum penum;
    gs_rect bbox;
    int op;
    ref *next;
    int code;

    /* Compute the bounding box. */
    if ((code = gs_upathbbox(pgs, &bbox, true)) < 0) {
        /*
         * Note: Adobe throws 'nocurrentpoint' error, but the PLRM does
         * not list this as a possible error from 'upath', so if we are
         * not in CPSI compatibility mode, we set a reasonable default
         * bbox instead.
         */
        if (code != e_nocurrentpoint || gs_currentcpsimode(imemory))
            return code;
        bbox.p.x = bbox.p.y = bbox.q.x = bbox.q.y = 0;
    }

    code = path_length_for_upath(ppath);
    if (code < 0)
        return code;
    size += code;
    if (size >= 65536)
        return_error(e_limitcheck);

    code = ialloc_ref_array(rupath, a_all | a_executable, size,
                            "make_upath");
    if (code < 0)
        return code;
    /* Construct the path. */
    next = rupath->value.refs;
    if (with_ucache) {
        if ((code = name_enter_string(pgs->memory, "ucache", next)) < 0)
            return code;
        r_set_attrs(next, a_executable | l_new);
        ++next;
    }
    make_real_new(next, bbox.p.x);
    make_real_new(next + 1, bbox.p.y);
    make_real_new(next + 2, bbox.q.x);
    make_real_new(next + 3, bbox.q.y);
    next += 4;
    if ((code = name_enter_string(pgs->memory, "setbbox", next)) < 0)
        return code;
    r_set_attrs(next, a_executable | l_new);
    ++next;
    {
        gs_point pts[3];

        /* Patch the path in the gstate to set up the enumerator. */
        gx_path *save_path = pgs->path;

        pgs->path = ppath;
        gs_path_enum_copy_init(&penum, pgs, false);
        pgs->path = save_path;
        while ((op = gs_path_enum_next(&penum, pts)) != 0) {
            const char *opstr;

            switch (op) {
                case gs_pe_moveto:
                    opstr = "moveto";
                    goto ml;
                case gs_pe_lineto:
                    opstr = "lineto";
                  ml:make_real_new(next, pts[0].x);
                    make_real_new(next + 1, pts[0].y);
                    next += 2;
                    break;
                case gs_pe_curveto:
                    opstr = "curveto";
                    make_real_new(next, pts[0].x);
                    make_real_new(next + 1, pts[0].y);
                    make_real_new(next + 2, pts[1].x);
                    make_real_new(next + 3, pts[1].y);
                    make_real_new(next + 4, pts[2].x);
                    make_real_new(next + 5, pts[2].y);
                    next += 6;
                    break;
                case gs_pe_closepath:
                    opstr = "closepath";
                    break;
                default:
                    return_error(e_unregistered);
            }
            if ((code = name_enter_string(pgs->memory, opstr, next)) < 0)
                return code;
            r_set_attrs(next, a_executable);
            ++next;
        }
    }
    return 0;
}
コード例 #11
0
ファイル: zbfont.c プロジェクト: BorodaZizitopa/ghostscript
/* or a negative error code. */
int
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(e_invalidfont);
    if (dict_find_string(op, "Encoding", &pencoding) <= 0) {
        if (!(options & bf_Encoding_optional))
            return_error(e_invalidfont);
        pencoding = 0;
    } else {
        if (!r_is_array(pencoding))
            return_error(e_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(e_typecheck);
                   }
                   fixit = true;
                   break;
               }
               else {
                   return_error(e_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(e_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(e_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(e_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;
}