/* Copyright (C) 1990, 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
/* Operators related to user paths */
private int upath_append(P1(os_ptr
));
private int upath_stroke(P1(os_ptr
));
/* ------ Insideness testing ------ */
private int in_test(P2(os_ptr
, int (*)(P1(gs_state
*))));
private int in_path(P1(os_ptr
));
private int in_path_result(P3(os_ptr
, int, int));
private int in_utest(P2(os_ptr
, int (*)(P1(gs_state
*))));
private int in_upath(P1(os_ptr
));
private int in_upath_result(P3(os_ptr
, int, int));
/* We use invalidexit, which the painting procedures cannot generate, */
/* as an "error" to indicate that the hit detection device found a hit. */
#define e_hit e_invalidexit
{ return in_test(op
, gs_eofill
);
{ return in_test(op
, gs_fill
);
{ return in_test(op
, gs_stroke
);
{ return in_utest(op
, gs_eofill
);
{ return in_utest(op
, gs_fill
);
{ /* This is different because of the optional matrix operand. */
int code
= gs_gsave(igs
);
if ( code
< 0 ) return code
;
if ( (spop
= upath_stroke(op
)) < 0 ||
(npop
= in_path(op
- spop
)) < 0
return in_upath_result(op
, npop
+ spop
, code
);
/* ------ Internal routines ------ */
/* Define a minimal device for insideness testing. */
/* It returns e_hit whenever it is asked to actually paint any pixels. */
private dev_proc_fill_rectangle(hit_fill_rectangle
);
private gx_device_procs hit_procs
= {
NULL
, /* get_initial_matrix */
gx_default_map_rgb_color
,
gx_default_map_color_rgb
,
NULL
, /* tile_rectangle */
private gx_device hit_device
=
0, 0, 1, 1, no_margins
, dci_black_and_white
, 0 /* generic */
/* Test for a hit when filling a rectangle. */
hit_fill_rectangle(gx_device
*dev
, int x
, int y
, int w
, int h
,
{ return (w
> 0 && h
> 0 ? e_hit
: 0);
/* Do the work of the non-user-path insideness operators. */
in_test(os_ptr op
, int (*paintproc
)(P1(gs_state
*)))
{ int npop
= in_path(op
);
if ( npop
< 0 ) return npop
;
code
= (*paintproc
)(igs
);
return in_path_result(op
, npop
, code
);
/* Set up a clipping path and device for insideness testing. */
{ int code
= gs_gsave(igs
);
if ( code
< 0 ) return code
;
code
= num_params(op
, 2, uxy
);
{ /* Aperture is a single pixel. */
gs_transform(igs
, uxy
[0], uxy
[1], &dxy
);
fr
.p
.x
= fixed_truncated(float2fixed(dxy
.x
));
fr
.p
.y
= fixed_truncated(float2fixed(dxy
.y
));
fr
.q
.x
= fr
.p
.x
+ int2fixed(1);
fr
.q
.y
= fr
.p
.y
+ int2fixed(1);
code
= gx_clip_to_rectangle(igs
, &fr
);
{ /* Aperture is a user path. */
if ( (code
= upath_append(op
)) >= 0 )
code
= gx_clip_to_path(igs
);
/* Install the hit detection device. */
gx_set_device_only(igs
, &hit_device
);
/* Finish an insideness test. */
in_path_result(os_ptr op
, int npop
, int code
)
case e_hit
: /* found a hit */
case 0: /* completed painting without a hit */
/* Do the work of the user-path insideness operators. */
in_utest(os_ptr op
, int (*paintproc
)(P1(gs_state
*)))
{ int npop
= in_upath(op
);
if ( npop
< 0 ) return npop
;
code
= (*paintproc
)(igs
);
return in_upath_result(op
, npop
, code
);
/* Set up a clipping path and device for insideness testing */
{ int code
= gs_gsave(igs
);
if ( code
< 0 ) return code
;
if ( (code
= upath_append(op
)) < 0 ||
(npop
= in_path(op
- 1)) < 0
/* Finish an insideness test with a user path. */
in_upath_result(os_ptr op
, int npop
, int code
)
{ gs_grestore(igs
); /* undo the extra gsave */
return in_path_result(op
, npop
, code
);
/* ------ User paths ------ */
/* User path operator codes */
static byte up_nargs
[upath_op_max
+ 1] =
{ 4, 2, 2, 2, 2, 6, 6, 5, 5, 5, 0, 0 };
#define zp(proc) extern int proc(P1(os_ptr))
zp(zsetbbox
); zp(zmoveto
); zp(zrmoveto
);
zp(zlineto
); zp(zrlineto
); zp(zcurveto
); zp(zrcurveto
);
zp(zarc
); zp(zarcn
); zp(zarct
); zp(zclosepath
); zp(zucache
);
static op_proc_p up_ops
[upath_op_max
+ 1] =
{ zsetbbox
, zmoveto
, zrmoveto
, zlineto
, zrlineto
,
zcurveto
, zrcurveto
, zarc
, zarcn
, zarct
,
/* Imported procedures */
extern int array_get(P3(ref
*, long, ref
*));
zuappend(register os_ptr op
)
{ int code
= gs_gsave(igs
);
if ( code
< 0 ) return code
;
if ( (code
= upath_append(op
)) >= 0 )
code
= gs_upmergepath(igs
);
if ( code
< 0 ) return code
;
zueofill(register os_ptr op
)
{ int code
= gs_gsave(igs
);
if ( code
< 0 ) return code
;
if ( (code
= upath_append(op
)) >= 0 )
if ( code
< 0 ) return code
;
zufill(register os_ptr op
)
{ int code
= gs_gsave(igs
);
if ( code
< 0 ) return code
;
if ( (code
= upath_append(op
)) >= 0 )
if ( code
< 0 ) return code
;
zustroke(register os_ptr op
)
{ int code
= gs_gsave(igs
);
if ( code
< 0 ) return code
;
if ( (code
= npop
= upath_stroke(op
)) >= 0 )
if ( code
< 0 ) return code
;
zustrokepath(register os_ptr op
)
{ int code
= gs_gsave(igs
);
if ( code
< 0 ) return code
;
if ( (code
= npop
= upath_stroke(op
)) < 0 ||
(code
= gs_strokepath(igs
)) < 0 ||
(code
= gs_upmergepath(igs
)) < 0
if ( code
< 0 ) return code
;
/* --- Internal routines --- */
/* Append a user path to the current path. */
/****** ROUND tx AND ty ******/
if ( r_has_type(op
, t_array
) && r_size(op
) == 2 &&
r_has_type(op
->value
.refs
+ 1, t_string
)
{ /* 1st element is operators, 2nd is operands */
code
= sread_num_array(&st
, op
->value
.refs
);
if ( code
< 0 ) return code
;
opp
= op
->value
.refs
[1].value
.bytes
;
ocount
= r_size(&op
->value
.refs
[1]);
else if ( opx
> upath_op_max
)
{ byte opargs
= up_nargs
[opx
];
code
= sget_encoded_number(&st
, op
);
r_set_type_attrs(op
, t_integer
, 0);
r_set_type_attrs(op
, t_real
, 0);
code
= (*up_ops
[opx
])(op
);
if ( code
< 0 ) return code
;
{ /* Ordinary executable array */
uint ocount
= r_size(op
);
int (*oproc
)(P1(os_ptr
));
for ( ; index
< ocount
; index
++ )
switch ( array_get(arp
, index
, &rup
), r_type(&rup
) )
if ( !r_has_attr(&rup
, a_executable
) )
if ( dict_find(&systemdict
, &rup
, &defp
) <= 0 )
if ( r_btype(defp
) != t_operator
)
xop
: if ( !r_has_attr(defp
, a_executable
) )
oproc
= real_opproc(defp
);
for ( opx
= 0; opx
<= upath_op_max
; opx
++ )
if ( oproc
== up_ops
[opx
] ) break;
if ( opx
> upath_op_max
|| argcount
!= up_nargs
[opx
] )
if ( code
< 0 ) return code
;
op
= osp
; /* resync ostack pointer */
if ( argcount
) return e_typecheck
; /* leftover args */
/* Append a user path to the current path, and then apply */
/* a transformation if one is supplied. */
upath_stroke(register os_ptr op
)
if ( (code
= read_matrix(op
, &mat
)) >= 0 )
{ if ( (code
= upath_append(op
- 1)) >= 0 )
code
= gs_concat(igs
, &mat
);
{ code
= upath_append(op
);
return (code
< 0 ? code
: npop
);
/* ------ Initialization procedure ------ */
op_def zupath_op_defs
[] = {
{"1ineofill", zineofill
},
{"1instroke", zinstroke
},
{"2inueofill", zinueofill
},
{"2inustroke", zinustroke
},
{"1ustrokepath", zustrokepath
},