/* Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved.
Distributed by Free Software Foundation, Inc.
This file is part of Ghostscript.
Ghostscript is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
to anyone for the consequences of using it or for whether it serves any
particular purpose or works at all, unless he says so in writing. Refer
to the Ghostscript General Public License for full details.
Everyone is granted permission to copy, modify and redistribute
Ghostscript, but only under the conditions described in the Ghostscript
General Public License. A copy of this license is supposed to have been
given to you along with Ghostscript so you can know your rights and
responsibilities. It should be in a file named COPYING. Among other
things, the copyright notice and this notice must be preserved on all
/* Character operators for Ghostscript */
#include "gxfixed.h" /* for gstype1.h */
#include "gxmatrix.h" /* for font.h */
#include "gxdevice.h" /* for gxfont.h */
#include "gzpath.h" /* for type1addpath: see below */
#include "dstack.h" /* for systemdict */
/* All the character rendering operators use the execution stack */
/* for loop control -- see estack.h for details. */
/* The information pushed by these operators is as follows: */
/* the enumerator (t_string, but points to a gs_show_enum); */
/* a slot for the procedure for kshow, unused otherwise; */
/* the procedure to be called at the end of the enumeration */
/* (t_operator, but called directly, not by the interpreter); */
/* the usual e-stack mark (t_null). */
#define senum (gs_show_enum *)(esp->value.bytes)
extern int array_get(P3(ref
*, long, ref
*));
extern ref name_StandardEncoding
;
private int setup_show(P3(ref
*, op_proc_p
, int));
private int show_continue(P1(os_ptr
));
private int i_show_continue
;
private int finish_show(P1(os_ptr
));
private int i_finish_show
;
private int finish_stringwidth(P1(os_ptr
));
private int i_finish_stringwidth
;
private gs_show_enum
*find_show(P0());
private void free_show(P0());
zshow(register os_ptr op
)
{ int code
= setup_show(op
, finish_show
, i_finish_show
);
if ( code
< 0 ) return code
;
if ( (code
= gs_show_n_init(senum
, igs
, (char *)op
->value
.bytes
, r_size(op
))) < 0 )
return show_continue(op
);
zashow(register os_ptr op
)
if ( (code
= num_params(op
- 1, 2, axy
)) < 0 ||
(code
= setup_show(op
, finish_show
, i_finish_show
)) < 0
if ( (code
= gs_ashow_n_init(senum
, igs
, axy
[0], axy
[1], (char *)op
->value
.bytes
, r_size(op
))) < 0 )
return show_continue(op
);
zwidthshow(register os_ptr op
)
check_type(op
[-1], t_integer
);
if ( (ulong
)(op
[-1].value
.intval
) > 255 ) return e_rangecheck
;
if ( (code
= num_params(op
- 2, 2, cxy
)) < 0 ||
(code
= setup_show(op
, finish_show
, i_finish_show
)) < 0
if ( (code
= gs_widthshow_n_init(senum
, igs
, cxy
[0], cxy
[1],
(char)op
[-1].value
.intval
,
return show_continue(op
);
zawidthshow(register os_ptr op
)
check_type(op
[-3], t_integer
);
if ( (ulong
)(op
[-3].value
.intval
) > 255 ) return e_rangecheck
;
if ( (code
= num_params(op
- 4, 2, cxy
)) < 0 ||
(code
= num_params(op
- 1, 2, axy
)) < 0 ||
(code
= setup_show(op
, finish_show
, i_finish_show
)) < 0
if ( (code
= gs_awidthshow_n_init(senum
, igs
, cxy
[0], cxy
[1],
(char)op
[-3].value
.intval
,
return show_continue(op
);
zkshow(register os_ptr op
)
if ( (code
= setup_show(op
, finish_show
, i_finish_show
)) < 0 ) return code
;
if ( (code
= gs_kshow_n_init(senum
, igs
, (char *)op
->value
.bytes
, r_size(op
))) < 0 )
sslot
= op
[-1]; /* save kerning proc */
return show_continue(op
);
/* Common finish procedure for all show operations. */
/* Doesn't have to do anything. */
zstringwidth(register os_ptr op
)
{ int code
= setup_show(op
, finish_stringwidth
, i_finish_stringwidth
);
if ( code
< 0 ) return code
;
if ( (code
= gs_stringwidth_n_init(senum
, igs
, (char *)op
->value
.bytes
, r_size(op
))) < 0 )
return show_continue(op
);
/* Finishing procedure for stringwidth. */
/* Pushes the accumulated width. */
finish_stringwidth(register os_ptr op
)
gs_show_width(senum
, &width
);
make_real(op
- 1, width
.x
);
zcharpath(register os_ptr op
)
check_type(*op
, t_boolean
);
code
= setup_show(op
- 1, finish_show
, i_finish_show
);
if ( code
< 0 ) return code
;
if ( (code
= gs_charpath_n_init(senum
, igs
, (char *)op
[-1].value
.bytes
, r_size(op
- 1), op
->value
.index
)) < 0 )
return show_continue(op
);
zsetcachedevice(register os_ptr op
)
gs_show_enum
*penum
= find_show();
int code
= num_params(op
, 6, wbox
);
if ( penum
== 0 ) return e_undefined
;
{ /* P*stScr*pt implementations apparently allow the */
/* bounding box to be specified as a 4-element array. */
/* Check for this here. */
num_params(op
- 1, 2, wbox
) < 0 ||
num_params(op
->value
.refs
+ 3, 4, wbox
+ 2) < 0
if ( (code
= gs_setcachedevice(penum
, igs
, wbox
[0], wbox
[1], wbox
[2], wbox
[3], wbox
[4], wbox
[5])) < 0 )
zsetcharwidth(register os_ptr op
)
gs_show_enum
*penum
= find_show();
int code
= num_params(op
, 2, width
);
if ( penum
== 0 ) return e_undefined
;
(code
= gs_setcharwidth(penum
, igs
, width
[0], width
[1])) < 0
zsetmetrics(register os_ptr op
)
gs_show_enum
*penum
= find_show();
if ( penum
== 0 ) return e_undefined
;
switch ( (size
= r_size(op
)) )
default: return e_invalidfont
;
code
= num_params(op
->value
.refs
+ size
- 1, size
, params
);
if ( code
< 0 ) return code
;
sb
.y
= params
[1], w
.x
= params
[2], w
.y
= params
[3];
sb
.y
= 0, w
.x
= params
[1], w
.y
= 0;
code
= gs_setmetrics(penum
, igs
, &sb
, &w
);
code
= real_param(op
, params
);
if ( code
< 0 ) return code
;
code
= gs_setmetrics(penum
, igs
, 0, &w
);
fixed
*osptr
; /* fake interpreter operand stack */
ztype1addpath(register os_ptr op
)
gs_show_enum
*penum
= find_show();
gs_font
*pfont
= gs_currentfont(igs
);
font_data
*pfdata
= (font_data
*)pfont
->client_data
;
if ( penum
== 0 ) return e_undefined
;
check_type(*op
, t_string
);
tdata
= pfont
->data
.base
.type1_data
;
zdata
.osptr
= zdata
.ostack
;
tdata
.proc_data
= (char *)&zdata
;
if ( r_size(op
) <= tdata
.lenIV
)
{ /* String is empty, or too short. Just ignore it. */
pis
= (gs_type1_state
*)alloc(1, gs_type1_state_sizeof
, "type1addpath");
if ( pis
== 0 ) return e_VMerror
;
code
= gs_type1_init(pis
, penum
,
gs_show_in_charpath(penum
), tdata
.PaintType
,
{ alloc_free((char *)pis
, 1, gs_type1_state_sizeof
, "type1addpath");
charstring
= op
->value
.bytes
;
more
: code
= gs_type1_interpret(pis
, charstring
, &value
);
if ( dict_find(&systemdict
,
&name_StandardEncoding
, &pstdenc
) <= 0 )
code
= array_get(pstdenc
, (long)value
, &enc_entry
);
if ( code
< 0 ) return code
;
if ( dict_find(&pfdata
->CharStrings
,
&enc_entry
, &pcstr
) <= 0 )
if ( !r_has_type(pcstr
, t_string
) )
charstring
= pcstr
->value
.bytes
;
case type1_result_callothersubr
:
{ /* We aren't prepared to call the interpreter here, */
/* so we fake the Flex feature. */
gx_path
*ppath
= igs
->path
;
gs_type1_pop(pis
, &discard
); /* pop # of args */
/* We have to do something really sleazy here, */
/* namely, make it look as though the rmovetos */
/* never really happened, because we don't want */
/* to interrupt the current subpath. */
gx_path_current_point(ppath
, &ept
);
gx_path_add_point(ppath
, spt
.x
, spt
.y
);
ppath
->subpath_open
= flex_path_was_open
;
gx_path_add_line(ppath
, ept
.x
, ept
.y
);
/* Transfer endpoint coordinates to 'ostack' */
gs_type1_pop(pis
, &zdata
.ostack
[0]);
gs_type1_pop(pis
, &zdata
.ostack
[1]);
gs_type1_pop(pis
, &discard
);
zdata
.osptr
= &zdata
.ostack
[2];
gx_path_current_point(ppath
, &spt
);
flex_path_was_open
= ppath
->subpath_open
;
gs_type1_pop(pis
, &discard
); /* pop subr# */
zdata
.ostack
[0] = int2fixed(3);
zdata
.osptr
= &zdata
.ostack
[1];
/* Unrecognized othersubr */
alloc_free((char *)pis
, 1, gs_type1_state_sizeof
, "type1addpath");
ztype1imagepath(register os_ptr op
)
check_type(op
[-7], t_string
);
check_type(op
[-6], t_integer
);
check_type(op
[-5], t_integer
);
if ( (code
= num_params(op
- 1, 4, woxy
)) < 0 ) return code
;
check_write_type(*op
, t_string
);
code
= gs_type1imagepath(igs
, op
[-7].value
.bytes
,
(int)op
[-6].value
.intval
, (int)op
[-5].value
.intval
,
woxy
[0], woxy
[1], woxy
[2], woxy
[3],
op
->value
.bytes
, r_size(op
));
if ( code
< 0 ) return code
;
r_set_size(op
- 7, code
);
/* ------ Auxiliary procedures for type 1 fonts ------ */
z1_subr_proc(gs_type1_data
*pdata
, int index
, byte
**pstr
)
{ gs_font
*pfont
= ((z1_data
*)(pdata
->proc_data
))->pfont
;
font_data
*pfdata
= (font_data
*)(pfont
->client_data
);
if ( index
< 0 || index
>= r_size(&pfdata
->Subrs
) )
psubr
= pfdata
->Subrs
.value
.refs
+ index
;
check_type(*psubr
, t_string
);
*pstr
= psubr
->value
.bytes
;
z1_pop_proc(gs_type1_data
*pdata
, fixed
*pf
)
{ *pf
= *--(((z1_data
*)(pdata
->proc_data
))->osptr
);
/* ------ Initialization procedure ------ */
op_def zchar_op_defs
[] = {
{"6awidthshow", zawidthshow
},
{"2charpath", zcharpath
},
{"3setcachedevice", zsetcachedevice
},
{"2setcharwidth", zsetcharwidth
},
{"1.setmetrics", zsetmetrics
},
{"1stringwidth", zstringwidth
},
{"1type1addpath", ztype1addpath
},
{"8type1imagepath", ztype1imagepath
},
{"4widthshow", zwidthshow
},
{"0%finish_show", finish_show
, &i_finish_show
},
{"0%finish_stringwidth", finish_stringwidth
, &i_finish_stringwidth
},
{"0%show_continue", show_continue
, &i_show_continue
},
/* ------ Internal routines ------ */
/* Set up for a show operator. */
/* The top stack element must be the string to be scanned. */
/* The caller has already done all other argument checking. */
setup_show(ref
*op
, op_proc_p endproc
/* end procedure */, int proc_index
)
check_read_type(*op
, t_string
);
check_estack(snumpush
+ 2);
if ( (penum
= (gs_show_enum
*)alloc(1, gs_show_enum_sizeof
, "setup_show")) == 0 )
push_op_estack(endproc
, proc_index
);
make_tv(esp
, t_null
, index
, 0); /* reserve slot */
make_tasv(esp
, t_string
, 0, gs_show_enum_sizeof
, bytes
, (byte
*)penum
);
/* Continuation operator for character rendering. */
show_continue(register os_ptr op
)
{ gs_show_enum
*penum
= senum
;
int code
= gs_show_next(penum
);
code
= (*real_opproc(&seproc
))(op
);
return (code
>= 0 ? o_pop_estack
: code
);
make_int(op
- 1, gs_kshow_previous_char(penum
));
make_int(op
, gs_kshow_next_char(penum
));
push_op_estack(show_continue
, i_show_continue
); /* continue after kerning */
*++esp
= *pslot
; /* kerning procedure */
{ font_data
*pfont
= (font_data
*)gs_currentfont(igs
)->client_data
;
op
[-1] = pfont
->dict
; /* push the font */
make_int(op
, gs_show_current_char(penum
));
push_op_estack(show_continue
, i_show_continue
);
*++esp
= pfont
->BuildChar
;
/* Find the current show enumerator on the e-stack. */
while ( !(r_has_type(ep
, t_null
) && ep
->value
.index
== es_show
) )
{ if ( --ep
< esbot
) return 0; /* no mark */
return (gs_show_enum
*)ep
[snumpush
- 1].value
.bytes
;
/* Discard the show record (after an error, or at the end). */
{ alloc_free((char *)senum
, 1, gs_show_enum_sizeof
, "free_show");