13ff48bf5SDavid du Colombier /* Copyright (C) 1995, 2000 Aladdin Enterprises. All rights reserved.
27dd7cddfSDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
57dd7cddfSDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier
17*593dc095SDavid du Colombier /*$Id: gxclpath.c,v 1.21 2005/10/10 18:58:18 leonardo Exp $ */
187dd7cddfSDavid du Colombier /* Higher-level path operations for band lists */
197dd7cddfSDavid du Colombier #include "math_.h"
207dd7cddfSDavid du Colombier #include "memory_.h"
217dd7cddfSDavid du Colombier #include "gx.h"
227dd7cddfSDavid du Colombier #include "gpcheck.h"
237dd7cddfSDavid du Colombier #include "gserrors.h"
247dd7cddfSDavid du Colombier #include "gxdevice.h"
257dd7cddfSDavid du Colombier #include "gxdevmem.h" /* must precede gxcldev.h */
267dd7cddfSDavid du Colombier #include "gxcldev.h"
277dd7cddfSDavid du Colombier #include "gxclpath.h"
287dd7cddfSDavid du Colombier #include "gxcolor2.h"
297dd7cddfSDavid du Colombier #include "gxdcolor.h"
307dd7cddfSDavid du Colombier #include "gxpaint.h" /* for gx_fill/stroke_params */
317dd7cddfSDavid du Colombier #include "gzpath.h"
327dd7cddfSDavid du Colombier #include "gzcpath.h"
337dd7cddfSDavid du Colombier #include "stream.h"
34*593dc095SDavid du Colombier #include "gsserial.h"
357dd7cddfSDavid du Colombier
367dd7cddfSDavid du Colombier /* Statistics */
377dd7cddfSDavid du Colombier #ifdef DEBUG
387dd7cddfSDavid du Colombier ulong stats_cmd_diffs[5];
397dd7cddfSDavid du Colombier #endif
407dd7cddfSDavid du Colombier
417dd7cddfSDavid du Colombier /* Forward declarations */
42*593dc095SDavid du Colombier private int cmd_put_path(gx_device_clist_writer * cldev,
437dd7cddfSDavid du Colombier gx_clist_state * pcls, const gx_path * ppath,
447dd7cddfSDavid du Colombier fixed ymin, fixed ymax, byte op,
45*593dc095SDavid du Colombier bool implicit_close, segment_notes keep_notes);
467dd7cddfSDavid du Colombier
477dd7cddfSDavid du Colombier /* ------ Utilities ------ */
487dd7cddfSDavid du Colombier
497dd7cddfSDavid du Colombier /* Compute the colors used by a colored halftone. */
507dd7cddfSDavid du Colombier private gx_color_index
colored_halftone_colors_used(gx_device_clist_writer * cldev,const gx_drawing_color * pdcolor)517dd7cddfSDavid du Colombier colored_halftone_colors_used(gx_device_clist_writer *cldev,
527dd7cddfSDavid du Colombier const gx_drawing_color *pdcolor)
537dd7cddfSDavid du Colombier {
547dd7cddfSDavid du Colombier /*
557dd7cddfSDavid du Colombier * We only know how to compute an accurate color set for the
567dd7cddfSDavid du Colombier * standard CMYK color mapping function.
577dd7cddfSDavid du Colombier */
587dd7cddfSDavid du Colombier if (dev_proc(cldev, map_cmyk_color) != cmyk_1bit_map_cmyk_color)
597dd7cddfSDavid du Colombier return ((gx_color_index)1 << cldev->color_info.depth) - 1;
607dd7cddfSDavid du Colombier /*
617dd7cddfSDavid du Colombier * Note that c_base[0], and the low-order bit of plane_mask,
627dd7cddfSDavid du Colombier * correspond to cyan: this requires reversing the bit order of
637dd7cddfSDavid du Colombier * the plane mask.
647dd7cddfSDavid du Colombier */
657dd7cddfSDavid du Colombier return
667dd7cddfSDavid du Colombier ((pdcolor->colors.colored.c_base[0] << 3) |
677dd7cddfSDavid du Colombier (pdcolor->colors.colored.c_base[1] << 2) |
687dd7cddfSDavid du Colombier (pdcolor->colors.colored.c_base[2] << 1) |
697dd7cddfSDavid du Colombier (pdcolor->colors.colored.c_base[3]) |
707dd7cddfSDavid du Colombier (byte_reverse_bits[pdcolor->colors.colored.plane_mask] >> 4));
717dd7cddfSDavid du Colombier }
727dd7cddfSDavid du Colombier
737dd7cddfSDavid du Colombier /*
747dd7cddfSDavid du Colombier * Compute whether a drawing operation will require the slow (full-pixel)
757dd7cddfSDavid du Colombier * RasterOp implementation. If pdcolor is not NULL, it is the texture for
767dd7cddfSDavid du Colombier * the RasterOp.
777dd7cddfSDavid du Colombier */
787dd7cddfSDavid du Colombier bool
cmd_slow_rop(gx_device * dev,gs_logical_operation_t lop,const gx_drawing_color * pdcolor)797dd7cddfSDavid du Colombier cmd_slow_rop(gx_device *dev, gs_logical_operation_t lop,
807dd7cddfSDavid du Colombier const gx_drawing_color *pdcolor)
817dd7cddfSDavid du Colombier {
827dd7cddfSDavid du Colombier gs_rop3_t rop = lop_rop(lop);
837dd7cddfSDavid du Colombier
847dd7cddfSDavid du Colombier if (pdcolor != 0 && gx_dc_is_pure(pdcolor)) {
857dd7cddfSDavid du Colombier gx_color_index color = gx_dc_pure_color(pdcolor);
867dd7cddfSDavid du Colombier
877dd7cddfSDavid du Colombier if (color == gx_device_black(dev))
887dd7cddfSDavid du Colombier rop = rop3_know_T_0(rop);
897dd7cddfSDavid du Colombier else if (color == gx_device_white(dev))
907dd7cddfSDavid du Colombier rop = rop3_know_T_1(rop);
917dd7cddfSDavid du Colombier }
927dd7cddfSDavid du Colombier return !(rop == rop3_0 || rop == rop3_1 ||
937dd7cddfSDavid du Colombier rop == rop3_D || rop == rop3_S || rop == rop3_T);
947dd7cddfSDavid du Colombier }
957dd7cddfSDavid du Colombier
967dd7cddfSDavid du Colombier /* Write out the color for filling, stroking, or masking. */
977dd7cddfSDavid du Colombier /* We should be able to share this with clist_tile_rectangle, */
987dd7cddfSDavid du Colombier /* but I don't see how to do it without adding a level of procedure. */
997dd7cddfSDavid du Colombier int
cmd_put_drawing_color(gx_device_clist_writer * cldev,gx_clist_state * pcls,const gx_drawing_color * pdcolor)1007dd7cddfSDavid du Colombier cmd_put_drawing_color(gx_device_clist_writer * cldev, gx_clist_state * pcls,
1017dd7cddfSDavid du Colombier const gx_drawing_color * pdcolor)
1027dd7cddfSDavid du Colombier {
103*593dc095SDavid du Colombier const gx_device_halftone * pdht = pdcolor->type->get_dev_halftone(pdcolor);
104*593dc095SDavid du Colombier int code, di;
105*593dc095SDavid du Colombier uint dc_size = 0, req_size;
106*593dc095SDavid du Colombier gx_device_color_saved * psdc = &pcls->sdc;
1077dd7cddfSDavid du Colombier byte * dp;
108*593dc095SDavid du Colombier byte * dp0;
109*593dc095SDavid du Colombier gs_int_point color_phase;
1107dd7cddfSDavid du Colombier
111*593dc095SDavid du Colombier /* see if the halftone must be inserted in the command list */
112*593dc095SDavid du Colombier if ( pdht != NULL &&
113*593dc095SDavid du Colombier pdht->id != cldev->device_halftone_id ) {
114*593dc095SDavid du Colombier if ((code = cmd_put_halftone(cldev, pdht)) < 0)
1157dd7cddfSDavid du Colombier return code;
116*593dc095SDavid du Colombier color_unset(psdc);
1177dd7cddfSDavid du Colombier }
1187dd7cddfSDavid du Colombier
119*593dc095SDavid du Colombier /* see if phase informaiton must be inserted in the command list */
120*593dc095SDavid du Colombier if ( pdcolor->type->get_phase(pdcolor, &color_phase) &&
121*593dc095SDavid du Colombier (color_phase.x != pcls->tile_phase.x ||
122*593dc095SDavid du Colombier color_phase.y != pcls->tile_phase.y ) &&
123*593dc095SDavid du Colombier (code = cmd_set_tile_phase( cldev,
124*593dc095SDavid du Colombier pcls,
125*593dc095SDavid du Colombier color_phase.x,
126*593dc095SDavid du Colombier color_phase.y )) < 0 )
1277dd7cddfSDavid du Colombier return code;
1287dd7cddfSDavid du Colombier
129*593dc095SDavid du Colombier /*
130*593dc095SDavid du Colombier * Get the device color type index and the required size.
131*593dc095SDavid du Colombier *
132*593dc095SDavid du Colombier * The complete cmd_opv_ext_put_drawing_color consists of:
133*593dc095SDavid du Colombier * comand code (2 bytes)
134*593dc095SDavid du Colombier * device color type index (1)
135*593dc095SDavid du Colombier * length of serialized device color (enc_u_sizew(dc_size))
136*593dc095SDavid du Colombier * the serialized device color itself (dc_size)
137*593dc095SDavid du Colombier */
138*593dc095SDavid du Colombier di = gx_get_dc_type_index(pdcolor);
139*593dc095SDavid du Colombier code = pdcolor->type->write( pdcolor,
140*593dc095SDavid du Colombier psdc,
141*593dc095SDavid du Colombier (gx_device *)cldev,
142*593dc095SDavid du Colombier 0,
143*593dc095SDavid du Colombier &dc_size );
1447dd7cddfSDavid du Colombier
145*593dc095SDavid du Colombier /* if the returned value is > 0, no change in the color is necessary */
146*593dc095SDavid du Colombier if (code > 0)
147*593dc095SDavid du Colombier return 0;
148*593dc095SDavid du Colombier else if (code < 0 && code != gs_error_rangecheck)
149*593dc095SDavid du Colombier return code;
150*593dc095SDavid du Colombier req_size = dc_size + 2 + 1 + enc_u_sizew(dc_size);
151*593dc095SDavid du Colombier
152*593dc095SDavid du Colombier /*
153*593dc095SDavid du Colombier * Encoded device colors are small in comparison to the command
154*593dc095SDavid du Colombier * buffer size (< 64 bytes), so we can just clear space in the
155*593dc095SDavid du Colombier * command buffer for them.
156*593dc095SDavid du Colombier */
157*593dc095SDavid du Colombier if ((code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_extend, req_size)) < 0)
158*593dc095SDavid du Colombier return code;
159*593dc095SDavid du Colombier dp0 = dp;
160*593dc095SDavid du Colombier dp[1] = cmd_opv_ext_put_drawing_color;
161*593dc095SDavid du Colombier dp += 2;
162*593dc095SDavid du Colombier *dp++ = di;
163*593dc095SDavid du Colombier enc_u_putw(dc_size, dp);
164*593dc095SDavid du Colombier code = pdcolor->type->write( pdcolor,
165*593dc095SDavid du Colombier &pcls->sdc,
166*593dc095SDavid du Colombier (gx_device *)cldev,
167*593dc095SDavid du Colombier dp,
168*593dc095SDavid du Colombier &dc_size );
169*593dc095SDavid du Colombier if (code < 0) {
170*593dc095SDavid du Colombier cldev->cnext = dp0;
1717dd7cddfSDavid du Colombier return code;
1727dd7cddfSDavid du Colombier }
173*593dc095SDavid du Colombier
174*593dc095SDavid du Colombier /* should properly calculate colors_used, but for now just punt */
175*593dc095SDavid du Colombier pcls->colors_used.or = ((gx_color_index)1 << cldev->color_info.depth) - 1;
176*593dc095SDavid du Colombier
177*593dc095SDavid du Colombier /* record the color we have just serialized color */
178*593dc095SDavid du Colombier pdcolor->type->save_dc(pdcolor, &pcls->sdc);
179*593dc095SDavid du Colombier
180*593dc095SDavid du Colombier return code;
1817dd7cddfSDavid du Colombier }
1827dd7cddfSDavid du Colombier
1837dd7cddfSDavid du Colombier /* Compute the colors used by a drawing color. */
1847dd7cddfSDavid du Colombier gx_color_index
cmd_drawing_colors_used(gx_device_clist_writer * cldev,const gx_drawing_color * pdcolor)1857dd7cddfSDavid du Colombier cmd_drawing_colors_used(gx_device_clist_writer *cldev,
1867dd7cddfSDavid du Colombier const gx_drawing_color * pdcolor)
1877dd7cddfSDavid du Colombier {
1887dd7cddfSDavid du Colombier if (gx_dc_is_pure(pdcolor))
1897dd7cddfSDavid du Colombier return gx_dc_pure_color(pdcolor);
1907dd7cddfSDavid du Colombier else if (gx_dc_is_binary_halftone(pdcolor))
1917dd7cddfSDavid du Colombier return gx_dc_binary_color0(pdcolor) | gx_dc_binary_color1(pdcolor);
1927dd7cddfSDavid du Colombier else if (gx_dc_is_colored_halftone(pdcolor))
1937dd7cddfSDavid du Colombier return colored_halftone_colors_used(cldev, pdcolor);
1947dd7cddfSDavid du Colombier else
1957dd7cddfSDavid du Colombier return ((gx_color_index)1 << cldev->color_info.depth) - 1;
1967dd7cddfSDavid du Colombier }
1977dd7cddfSDavid du Colombier
1987dd7cddfSDavid du Colombier
1997dd7cddfSDavid du Colombier /* Clear (a) specific 'known' flag(s) for all bands. */
2007dd7cddfSDavid du Colombier /* We must do this whenever the value of a 'known' parameter changes. */
2017dd7cddfSDavid du Colombier void
cmd_clear_known(gx_device_clist_writer * cldev,uint known)2027dd7cddfSDavid du Colombier cmd_clear_known(gx_device_clist_writer * cldev, uint known)
2037dd7cddfSDavid du Colombier {
2043ff48bf5SDavid du Colombier uint unknown = ~known;
2057dd7cddfSDavid du Colombier gx_clist_state *pcls = cldev->states;
2067dd7cddfSDavid du Colombier int i;
2077dd7cddfSDavid du Colombier
2087dd7cddfSDavid du Colombier for (i = cldev->nbands; --i >= 0; ++pcls)
2097dd7cddfSDavid du Colombier pcls->known &= unknown;
2107dd7cddfSDavid du Colombier }
2117dd7cddfSDavid du Colombier
2127dd7cddfSDavid du Colombier /* Check whether we need to change the clipping path in the device. */
2137dd7cddfSDavid du Colombier bool
cmd_check_clip_path(gx_device_clist_writer * cldev,const gx_clip_path * pcpath)2147dd7cddfSDavid du Colombier cmd_check_clip_path(gx_device_clist_writer * cldev, const gx_clip_path * pcpath)
2157dd7cddfSDavid du Colombier {
2167dd7cddfSDavid du Colombier if (pcpath == NULL)
2177dd7cddfSDavid du Colombier return false;
2187dd7cddfSDavid du Colombier /* The clip path might have moved in memory, so even if the */
2197dd7cddfSDavid du Colombier /* ids match, update the pointer. */
2207dd7cddfSDavid du Colombier cldev->clip_path = pcpath;
2217dd7cddfSDavid du Colombier if (pcpath->id == cldev->clip_path_id)
2227dd7cddfSDavid du Colombier return false;
2237dd7cddfSDavid du Colombier cldev->clip_path_id = pcpath->id;
2247dd7cddfSDavid du Colombier return true;
2257dd7cddfSDavid du Colombier }
2267dd7cddfSDavid du Colombier
2273ff48bf5SDavid du Colombier /*
2283ff48bf5SDavid du Colombier * Check the graphics state elements that need to be up to date for filling
2293ff48bf5SDavid du Colombier * or stroking.
2303ff48bf5SDavid du Colombier */
2313ff48bf5SDavid du Colombier #define FILL_KNOWN\
2323ff48bf5SDavid du Colombier (cj_ac_sa_known | flatness_known | op_bm_tk_known | opacity_alpha_known |\
2333ff48bf5SDavid du Colombier shape_alpha_known | fill_adjust_known | alpha_known | clip_path_known)
2343ff48bf5SDavid du Colombier private void
cmd_check_fill_known(gx_device_clist_writer * cdev,const gs_imager_state * pis,floatp flatness,const gs_fixed_point * padjust,const gx_clip_path * pcpath,uint * punknown)2353ff48bf5SDavid du Colombier cmd_check_fill_known(gx_device_clist_writer *cdev, const gs_imager_state *pis,
2363ff48bf5SDavid du Colombier floatp flatness, const gs_fixed_point *padjust,
2373ff48bf5SDavid du Colombier const gx_clip_path *pcpath, uint *punknown)
2383ff48bf5SDavid du Colombier {
2393ff48bf5SDavid du Colombier /*
2403ff48bf5SDavid du Colombier * stroke_adjust is not needed for fills, and none of these are needed
2413ff48bf5SDavid du Colombier * if the path has no curves, but it's easier to update them all.
2423ff48bf5SDavid du Colombier */
2433ff48bf5SDavid du Colombier if (state_neq(line_params.curve_join) || state_neq(accurate_curves) ||
2443ff48bf5SDavid du Colombier state_neq(stroke_adjust)
2453ff48bf5SDavid du Colombier ) {
2463ff48bf5SDavid du Colombier *punknown |= cj_ac_sa_known;
2473ff48bf5SDavid du Colombier state_update(line_params.curve_join);
2483ff48bf5SDavid du Colombier state_update(accurate_curves);
2493ff48bf5SDavid du Colombier state_update(stroke_adjust);
2503ff48bf5SDavid du Colombier }
2513ff48bf5SDavid du Colombier if (cdev->imager_state.flatness != flatness) {
2523ff48bf5SDavid du Colombier *punknown |= flatness_known;
2533ff48bf5SDavid du Colombier cdev->imager_state.flatness = flatness;
2543ff48bf5SDavid du Colombier }
255*593dc095SDavid du Colombier /*
256*593dc095SDavid du Colombier * Note: overprint and overprint_mode are implemented via a compositor
257*593dc095SDavid du Colombier * device, which is passed separately through the command list. Hence,
258*593dc095SDavid du Colombier * though both parameters are passed in the state as well, this usually
259*593dc095SDavid du Colombier * has no effect.
260*593dc095SDavid du Colombier */
2613ff48bf5SDavid du Colombier if (state_neq(overprint) || state_neq(overprint_mode) ||
2623ff48bf5SDavid du Colombier state_neq(blend_mode) || state_neq(text_knockout)
2633ff48bf5SDavid du Colombier ) {
2643ff48bf5SDavid du Colombier *punknown |= op_bm_tk_known;
2653ff48bf5SDavid du Colombier state_update(overprint);
2663ff48bf5SDavid du Colombier state_update(overprint_mode);
2673ff48bf5SDavid du Colombier state_update(blend_mode);
2683ff48bf5SDavid du Colombier state_update(text_knockout);
2693ff48bf5SDavid du Colombier }
2703ff48bf5SDavid du Colombier if (state_neq(opacity.alpha)) {
2713ff48bf5SDavid du Colombier *punknown |= opacity_alpha_known;
2723ff48bf5SDavid du Colombier state_update(opacity.alpha);
2733ff48bf5SDavid du Colombier }
2743ff48bf5SDavid du Colombier if (state_neq(shape.alpha)) {
2753ff48bf5SDavid du Colombier *punknown |= shape_alpha_known;
2763ff48bf5SDavid du Colombier state_update(shape.alpha);
2773ff48bf5SDavid du Colombier }
2783ff48bf5SDavid du Colombier if (cdev->imager_state.fill_adjust.x != padjust->x ||
2793ff48bf5SDavid du Colombier cdev->imager_state.fill_adjust.y != padjust->y
2803ff48bf5SDavid du Colombier ) {
2813ff48bf5SDavid du Colombier *punknown |= fill_adjust_known;
2823ff48bf5SDavid du Colombier cdev->imager_state.fill_adjust = *padjust;
2833ff48bf5SDavid du Colombier }
2843ff48bf5SDavid du Colombier if (cdev->imager_state.alpha != pis->alpha) {
2853ff48bf5SDavid du Colombier *punknown |= alpha_known;
2863ff48bf5SDavid du Colombier state_update(alpha);
2873ff48bf5SDavid du Colombier }
2883ff48bf5SDavid du Colombier if (cmd_check_clip_path(cdev, pcpath))
2893ff48bf5SDavid du Colombier *punknown |= clip_path_known;
2903ff48bf5SDavid du Colombier }
2913ff48bf5SDavid du Colombier
292*593dc095SDavid du Colombier /* Compute the written CTM length. */
293*593dc095SDavid du Colombier int
cmd_write_ctm_return_length(gx_device_clist_writer * cldev,const gs_matrix * m)294*593dc095SDavid du Colombier cmd_write_ctm_return_length(gx_device_clist_writer * cldev, const gs_matrix *m)
295*593dc095SDavid du Colombier {
296*593dc095SDavid du Colombier stream s;
297*593dc095SDavid du Colombier
298*593dc095SDavid du Colombier s_init(&s, cldev->memory);
299*593dc095SDavid du Colombier swrite_position_only(&s);
300*593dc095SDavid du Colombier sput_matrix(&s, m);
301*593dc095SDavid du Colombier return (uint)stell(&s);
302*593dc095SDavid du Colombier }
303*593dc095SDavid du Colombier
304*593dc095SDavid du Colombier /* Write out CTM. */
305*593dc095SDavid du Colombier int
cmd_write_ctm(const gs_matrix * m,byte * dp,int len)306*593dc095SDavid du Colombier cmd_write_ctm(const gs_matrix *m, byte *dp, int len)
307*593dc095SDavid du Colombier {
308*593dc095SDavid du Colombier stream s;
309*593dc095SDavid du Colombier
310*593dc095SDavid du Colombier swrite_string(&s, dp + 1, len);
311*593dc095SDavid du Colombier sput_matrix(&s, m);
312*593dc095SDavid du Colombier return 0;
313*593dc095SDavid du Colombier }
314*593dc095SDavid du Colombier
3157dd7cddfSDavid du Colombier /* Write out values of any unknown parameters. */
3167dd7cddfSDavid du Colombier int
cmd_write_unknown(gx_device_clist_writer * cldev,gx_clist_state * pcls,uint must_know)3177dd7cddfSDavid du Colombier cmd_write_unknown(gx_device_clist_writer * cldev, gx_clist_state * pcls,
3187dd7cddfSDavid du Colombier uint must_know)
3197dd7cddfSDavid du Colombier {
3203ff48bf5SDavid du Colombier uint unknown = ~pcls->known & must_know;
3213ff48bf5SDavid du Colombier uint misc2_unknown = unknown & misc2_all_known;
3227dd7cddfSDavid du Colombier byte *dp;
3237dd7cddfSDavid du Colombier int code;
3247dd7cddfSDavid du Colombier
3253ff48bf5SDavid du Colombier if (misc2_unknown) {
3263ff48bf5SDavid du Colombier byte buf[
3273ff48bf5SDavid du Colombier 1 + /* cap_join */
3283ff48bf5SDavid du Colombier 1 + /* cj_ac_sa */
3293ff48bf5SDavid du Colombier sizeof(float) + /* flatness */
3303ff48bf5SDavid du Colombier sizeof(float) + /* line width */
3313ff48bf5SDavid du Colombier sizeof(float) + /* miter limit */
3323ff48bf5SDavid du Colombier 1 + /* op_bm_tk */
3333ff48bf5SDavid du Colombier sizeof(float) * 2 + /* opacity/shape alpha */
3343ff48bf5SDavid du Colombier sizeof(cldev->imager_state.alpha)
3353ff48bf5SDavid du Colombier ];
3363ff48bf5SDavid du Colombier byte *bp = buf;
3373ff48bf5SDavid du Colombier
3383ff48bf5SDavid du Colombier if (unknown & cap_join_known) {
3393ff48bf5SDavid du Colombier *bp++ = (cldev->imager_state.line_params.cap << 3) +
3403ff48bf5SDavid du Colombier cldev->imager_state.line_params.join;
3413ff48bf5SDavid du Colombier }
3423ff48bf5SDavid du Colombier if (unknown & cj_ac_sa_known) {
3433ff48bf5SDavid du Colombier *bp++ =
3443ff48bf5SDavid du Colombier ((cldev->imager_state.line_params.curve_join + 1) << 2) +
3453ff48bf5SDavid du Colombier (cldev->imager_state.accurate_curves ? 2 : 0) +
3463ff48bf5SDavid du Colombier (cldev->imager_state.stroke_adjust ? 1 : 0);
3473ff48bf5SDavid du Colombier }
3487dd7cddfSDavid du Colombier if (unknown & flatness_known) {
3493ff48bf5SDavid du Colombier memcpy(bp, &cldev->imager_state.flatness, sizeof(float));
3503ff48bf5SDavid du Colombier bp += sizeof(float);
3513ff48bf5SDavid du Colombier }
3523ff48bf5SDavid du Colombier if (unknown & line_width_known) {
3533ff48bf5SDavid du Colombier float width =
3543ff48bf5SDavid du Colombier gx_current_line_width(&cldev->imager_state.line_params);
3553ff48bf5SDavid du Colombier
3563ff48bf5SDavid du Colombier memcpy(bp, &width, sizeof(width));
3573ff48bf5SDavid du Colombier bp += sizeof(width);
3583ff48bf5SDavid du Colombier }
3593ff48bf5SDavid du Colombier if (unknown & miter_limit_known) {
3603ff48bf5SDavid du Colombier memcpy(bp, &cldev->imager_state.line_params.miter_limit,
3613ff48bf5SDavid du Colombier sizeof(float));
3623ff48bf5SDavid du Colombier bp += sizeof(float);
3633ff48bf5SDavid du Colombier }
3643ff48bf5SDavid du Colombier if (unknown & op_bm_tk_known) {
3653ff48bf5SDavid du Colombier *bp++ =
3663ff48bf5SDavid du Colombier ((int)cldev->imager_state.blend_mode << 3) +
3673ff48bf5SDavid du Colombier (cldev->imager_state.text_knockout << 2) +
3683ff48bf5SDavid du Colombier (cldev->imager_state.overprint_mode << 1) +
3693ff48bf5SDavid du Colombier cldev->imager_state.overprint;
3703ff48bf5SDavid du Colombier }
3713ff48bf5SDavid du Colombier if (unknown & opacity_alpha_known) {
3723ff48bf5SDavid du Colombier memcpy(bp, &cldev->imager_state.opacity.alpha, sizeof(float));
3733ff48bf5SDavid du Colombier bp += sizeof(float);
3743ff48bf5SDavid du Colombier }
3753ff48bf5SDavid du Colombier if (unknown & shape_alpha_known) {
3763ff48bf5SDavid du Colombier memcpy(bp, &cldev->imager_state.shape.alpha, sizeof(float));
3773ff48bf5SDavid du Colombier bp += sizeof(float);
3783ff48bf5SDavid du Colombier }
3793ff48bf5SDavid du Colombier if (unknown & alpha_known) {
3803ff48bf5SDavid du Colombier memcpy(bp, &cldev->imager_state.alpha,
3813ff48bf5SDavid du Colombier sizeof(cldev->imager_state.alpha));
3823ff48bf5SDavid du Colombier bp += sizeof(cldev->imager_state.alpha);
3833ff48bf5SDavid du Colombier }
3847dd7cddfSDavid du Colombier code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_misc2,
3853ff48bf5SDavid du Colombier 1 + cmd_sizew(misc2_unknown) + bp - buf);
3867dd7cddfSDavid du Colombier if (code < 0)
3873ff48bf5SDavid du Colombier return 0;
3883ff48bf5SDavid du Colombier memcpy(cmd_put_w(misc2_unknown, dp + 1), buf, bp - buf);
3893ff48bf5SDavid du Colombier pcls->known |= misc2_unknown;
3907dd7cddfSDavid du Colombier }
3917dd7cddfSDavid du Colombier if (unknown & fill_adjust_known) {
3927dd7cddfSDavid du Colombier code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_fill_adjust,
3937dd7cddfSDavid du Colombier 1 + sizeof(fixed) * 2);
3947dd7cddfSDavid du Colombier if (code < 0)
3957dd7cddfSDavid du Colombier return code;
3967dd7cddfSDavid du Colombier memcpy(dp + 1, &cldev->imager_state.fill_adjust.x, sizeof(fixed));
3977dd7cddfSDavid du Colombier memcpy(dp + 1 + sizeof(fixed), &cldev->imager_state.fill_adjust.y, sizeof(fixed));
3987dd7cddfSDavid du Colombier pcls->known |= fill_adjust_known;
3997dd7cddfSDavid du Colombier }
4007dd7cddfSDavid du Colombier if (unknown & ctm_known) {
401*593dc095SDavid du Colombier int len = cmd_write_ctm_return_length(cldev, &ctm_only(&cldev->imager_state));
4027dd7cddfSDavid du Colombier
4037dd7cddfSDavid du Colombier code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_ctm, len + 1);
4047dd7cddfSDavid du Colombier if (code < 0)
4057dd7cddfSDavid du Colombier return code;
406*593dc095SDavid du Colombier code = cmd_write_ctm(&ctm_only(&cldev->imager_state), dp, len);
407*593dc095SDavid du Colombier if (code < 0)
408*593dc095SDavid du Colombier return code;
4097dd7cddfSDavid du Colombier pcls->known |= ctm_known;
4107dd7cddfSDavid du Colombier }
4117dd7cddfSDavid du Colombier if (unknown & dash_known) {
4127dd7cddfSDavid du Colombier int n = cldev->imager_state.line_params.dash.pattern_size;
4137dd7cddfSDavid du Colombier
4147dd7cddfSDavid du Colombier code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_dash,
4157dd7cddfSDavid du Colombier 2 + (n + 2) * sizeof(float));
4167dd7cddfSDavid du Colombier if (code < 0)
4177dd7cddfSDavid du Colombier return code;
4187dd7cddfSDavid du Colombier dp[1] = n + (cldev->imager_state.line_params.dash.adapt ? 0x80 : 0) +
4197dd7cddfSDavid du Colombier (cldev->imager_state.line_params.dot_length_absolute ? 0x40 : 0);
4207dd7cddfSDavid du Colombier memcpy(dp + 2, &cldev->imager_state.line_params.dot_length,
4217dd7cddfSDavid du Colombier sizeof(float));
4227dd7cddfSDavid du Colombier memcpy(dp + 2 + sizeof(float),
4237dd7cddfSDavid du Colombier &cldev->imager_state.line_params.dash.offset,
4247dd7cddfSDavid du Colombier sizeof(float));
4257dd7cddfSDavid du Colombier if (n != 0)
4267dd7cddfSDavid du Colombier memcpy(dp + 2 + sizeof(float) * 2,
4277dd7cddfSDavid du Colombier cldev->dash_pattern, n * sizeof(float));
4287dd7cddfSDavid du Colombier pcls->known |= dash_known;
4297dd7cddfSDavid du Colombier }
4307dd7cddfSDavid du Colombier if (unknown & clip_path_known) {
4317dd7cddfSDavid du Colombier /*
4327dd7cddfSDavid du Colombier * We can write out the clipping path either as rectangles
4337dd7cddfSDavid du Colombier * or as a real (filled) path.
4347dd7cddfSDavid du Colombier */
4357dd7cddfSDavid du Colombier const gx_clip_path *pcpath = cldev->clip_path;
4367dd7cddfSDavid du Colombier int band_height = cldev->page_band_height;
4377dd7cddfSDavid du Colombier int ymin = (pcls - cldev->states) * band_height;
4387dd7cddfSDavid du Colombier int ymax = min(ymin + band_height, cldev->height);
4397dd7cddfSDavid du Colombier gs_fixed_rect box;
4407dd7cddfSDavid du Colombier bool punt_to_outer_box = false;
4417dd7cddfSDavid du Colombier int code;
4427dd7cddfSDavid du Colombier
4437dd7cddfSDavid du Colombier code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_begin_clip, 1);
4447dd7cddfSDavid du Colombier if (code < 0)
4457dd7cddfSDavid du Colombier return code;
4467dd7cddfSDavid du Colombier if (pcpath->path_valid) {
4477dd7cddfSDavid du Colombier if (gx_path_is_rectangle(&pcpath->path, &box) &&
4487dd7cddfSDavid du Colombier fixed_is_int(box.p.x | box.p.y | box.q.x | box.q.y)
4497dd7cddfSDavid du Colombier ) {
4507dd7cddfSDavid du Colombier /* Write the path as a rectangle. */
4517dd7cddfSDavid du Colombier code = cmd_write_rect_cmd(cldev, pcls, cmd_op_fill_rect,
4527dd7cddfSDavid du Colombier fixed2int_var(box.p.x),
4537dd7cddfSDavid du Colombier fixed2int_var(box.p.y),
4547dd7cddfSDavid du Colombier fixed2int(box.q.x - box.p.x),
4557dd7cddfSDavid du Colombier fixed2int(box.q.y - box.p.y));
4567dd7cddfSDavid du Colombier } else if ( !(cldev->disable_mask & clist_disable_complex_clip) ) {
4577dd7cddfSDavid du Colombier /* Write the path. */
4587dd7cddfSDavid du Colombier code = cmd_put_path(cldev, pcls, &pcpath->path,
4597dd7cddfSDavid du Colombier int2fixed(ymin - 1),
4607dd7cddfSDavid du Colombier int2fixed(ymax + 1),
461*593dc095SDavid du Colombier (byte)(pcpath->rule == gx_rule_even_odd ?
4627dd7cddfSDavid du Colombier cmd_opv_eofill : cmd_opv_fill),
4637dd7cddfSDavid du Colombier true, sn_not_first);
4647dd7cddfSDavid du Colombier } else {
4657dd7cddfSDavid du Colombier /* Complex paths disabled: write outer box as clip */
4667dd7cddfSDavid du Colombier punt_to_outer_box = true;
4677dd7cddfSDavid du Colombier }
4687dd7cddfSDavid du Colombier } else { /* Write out the rectangles. */
4697dd7cddfSDavid du Colombier const gx_clip_list *list = gx_cpath_list(pcpath);
4707dd7cddfSDavid du Colombier const gx_clip_rect *prect = list->head;
4717dd7cddfSDavid du Colombier
4727dd7cddfSDavid du Colombier if (prect == 0)
4737dd7cddfSDavid du Colombier prect = &list->single;
4747dd7cddfSDavid du Colombier else if (cldev->disable_mask & clist_disable_complex_clip)
4757dd7cddfSDavid du Colombier punt_to_outer_box = true;
4767dd7cddfSDavid du Colombier if (!punt_to_outer_box) {
4777dd7cddfSDavid du Colombier for (; prect != 0 && code >= 0; prect = prect->next)
4787dd7cddfSDavid du Colombier if (prect->xmax > prect->xmin &&
4797dd7cddfSDavid du Colombier prect->ymin < ymax && prect->ymax > ymin
4807dd7cddfSDavid du Colombier ) {
4817dd7cddfSDavid du Colombier code =
4827dd7cddfSDavid du Colombier cmd_write_rect_cmd(cldev, pcls, cmd_op_fill_rect,
4837dd7cddfSDavid du Colombier prect->xmin, prect->ymin,
4847dd7cddfSDavid du Colombier prect->xmax - prect->xmin,
4857dd7cddfSDavid du Colombier prect->ymax - prect->ymin);
4867dd7cddfSDavid du Colombier }
4877dd7cddfSDavid du Colombier }
4887dd7cddfSDavid du Colombier }
4897dd7cddfSDavid du Colombier if (punt_to_outer_box) {
4907dd7cddfSDavid du Colombier /* Clip is complex, but disabled. Write out the outer box */
4917dd7cddfSDavid du Colombier gs_fixed_rect box;
4927dd7cddfSDavid du Colombier
4937dd7cddfSDavid du Colombier gx_cpath_outer_box(pcpath, &box);
4947dd7cddfSDavid du Colombier box.p.x = fixed_floor(box.p.x);
4957dd7cddfSDavid du Colombier box.p.y = fixed_floor(box.p.y);
4967dd7cddfSDavid du Colombier code = cmd_write_rect_cmd(cldev, pcls, cmd_op_fill_rect,
4977dd7cddfSDavid du Colombier fixed2int_var(box.p.x),
4987dd7cddfSDavid du Colombier fixed2int_var(box.p.y),
4997dd7cddfSDavid du Colombier fixed2int_ceiling(box.q.x - box.p.x),
5007dd7cddfSDavid du Colombier fixed2int_ceiling(box.q.y - box.p.y));
5017dd7cddfSDavid du Colombier }
5027dd7cddfSDavid du Colombier {
5037dd7cddfSDavid du Colombier int end_code =
5047dd7cddfSDavid du Colombier set_cmd_put_op(dp, cldev, pcls, cmd_opv_end_clip, 1);
5057dd7cddfSDavid du Colombier
5067dd7cddfSDavid du Colombier if (code >= 0)
5077dd7cddfSDavid du Colombier code = end_code; /* take the first failure seen */
5087dd7cddfSDavid du Colombier if (end_code < 0 && cldev->error_is_retryable) {
5097dd7cddfSDavid du Colombier /*
5107dd7cddfSDavid du Colombier * end_clip has to work despite lo-mem to maintain consistency.
5117dd7cddfSDavid du Colombier * This isn't error recovery, but just to prevent dangling
5127dd7cddfSDavid du Colombier * cmd_opv_begin_clip's.
5137dd7cddfSDavid du Colombier */
5147dd7cddfSDavid du Colombier ++cldev->ignore_lo_mem_warnings;
5157dd7cddfSDavid du Colombier end_code =
5167dd7cddfSDavid du Colombier set_cmd_put_op(dp, cldev, pcls, cmd_opv_end_clip, 1);
5177dd7cddfSDavid du Colombier --cldev->ignore_lo_mem_warnings;
5187dd7cddfSDavid du Colombier }
5197dd7cddfSDavid du Colombier }
5207dd7cddfSDavid du Colombier if (code < 0)
5217dd7cddfSDavid du Colombier return code;
5227dd7cddfSDavid du Colombier pcls->clip_enabled = 1;
5237dd7cddfSDavid du Colombier pcls->known |= clip_path_known;
5247dd7cddfSDavid du Colombier }
5257dd7cddfSDavid du Colombier if (unknown & color_space_known) {
5267dd7cddfSDavid du Colombier byte *dp;
5277dd7cddfSDavid du Colombier
5287dd7cddfSDavid du Colombier if (cldev->color_space.byte1 & 8) { /* indexed */
5297dd7cddfSDavid du Colombier const gs_color_space *pcs = cldev->color_space.space;
5307dd7cddfSDavid du Colombier int hival = pcs->params.indexed.hival;
5317dd7cddfSDavid du Colombier uint num_values = (hival + 1) *
5327dd7cddfSDavid du Colombier gs_color_space_num_components(
5337dd7cddfSDavid du Colombier (const gs_color_space *)&pcs->params.indexed.base_space);
5347dd7cddfSDavid du Colombier bool use_proc = cldev->color_space.byte1 & 4;
5357dd7cddfSDavid du Colombier const void *map_data;
5367dd7cddfSDavid du Colombier uint map_size;
5377dd7cddfSDavid du Colombier
5387dd7cddfSDavid du Colombier if (use_proc) {
5397dd7cddfSDavid du Colombier map_data = pcs->params.indexed.lookup.map->values;
5407dd7cddfSDavid du Colombier map_size = num_values *
5417dd7cddfSDavid du Colombier sizeof(pcs->params.indexed.lookup.map->values[0]);
5427dd7cddfSDavid du Colombier } else {
5437dd7cddfSDavid du Colombier map_data = pcs->params.indexed.lookup.table.data;
5447dd7cddfSDavid du Colombier map_size = num_values;
5457dd7cddfSDavid du Colombier }
5467dd7cddfSDavid du Colombier code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_color_space,
5477dd7cddfSDavid du Colombier 2 + cmd_sizew(hival) + map_size);
5487dd7cddfSDavid du Colombier if (code < 0)
5497dd7cddfSDavid du Colombier return code;
5507dd7cddfSDavid du Colombier memcpy(cmd_put_w(hival, dp + 2), map_data, map_size);
5517dd7cddfSDavid du Colombier } else {
5527dd7cddfSDavid du Colombier code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_color_space, 2);
5537dd7cddfSDavid du Colombier if (code < 0)
5547dd7cddfSDavid du Colombier return code;
5557dd7cddfSDavid du Colombier }
5567dd7cddfSDavid du Colombier dp[1] = cldev->color_space.byte1;
5577dd7cddfSDavid du Colombier pcls->known |= color_space_known;
5587dd7cddfSDavid du Colombier }
5593ff48bf5SDavid du Colombier /****** HANDLE masks ******/
5607dd7cddfSDavid du Colombier return 0;
5617dd7cddfSDavid du Colombier }
5627dd7cddfSDavid du Colombier
5637dd7cddfSDavid du Colombier /* ------ Driver procedures ------ */
5647dd7cddfSDavid du Colombier
5657dd7cddfSDavid du Colombier int
clist_fill_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)5667dd7cddfSDavid du Colombier clist_fill_path(gx_device * dev, const gs_imager_state * pis, gx_path * ppath,
5677dd7cddfSDavid du Colombier const gx_fill_params * params, const gx_drawing_color * pdcolor,
5687dd7cddfSDavid du Colombier const gx_clip_path * pcpath)
5697dd7cddfSDavid du Colombier {
5707dd7cddfSDavid du Colombier gx_device_clist_writer * const cdev =
5717dd7cddfSDavid du Colombier &((gx_device_clist *)dev)->writer;
5727dd7cddfSDavid du Colombier uint unknown = 0;
5737dd7cddfSDavid du Colombier int y, height, y0, y1;
5747dd7cddfSDavid du Colombier gs_logical_operation_t lop = pis->log_op;
5757dd7cddfSDavid du Colombier byte op = (byte)
5767dd7cddfSDavid du Colombier (params->rule == gx_rule_even_odd ?
5777dd7cddfSDavid du Colombier cmd_opv_eofill : cmd_opv_fill);
5787dd7cddfSDavid du Colombier gs_fixed_point adjust;
5797dd7cddfSDavid du Colombier bool slow_rop = cmd_slow_rop(dev, lop_know_S_0(lop), pdcolor);
5807dd7cddfSDavid du Colombier
5817dd7cddfSDavid du Colombier if ( (cdev->disable_mask & clist_disable_fill_path) ||
5827dd7cddfSDavid du Colombier gs_debug_c(',')
5837dd7cddfSDavid du Colombier ) {
5847dd7cddfSDavid du Colombier /* Disable path-based banding. */
5857dd7cddfSDavid du Colombier return gx_default_fill_path(dev, pis, ppath, params, pdcolor,
5867dd7cddfSDavid du Colombier pcpath);
5877dd7cddfSDavid du Colombier }
5887dd7cddfSDavid du Colombier adjust = params->adjust;
5897dd7cddfSDavid du Colombier {
5907dd7cddfSDavid du Colombier gs_fixed_rect bbox;
5917dd7cddfSDavid du Colombier
5927dd7cddfSDavid du Colombier gx_path_bbox(ppath, &bbox);
5937dd7cddfSDavid du Colombier y = fixed2int(bbox.p.y) - 1;
5947dd7cddfSDavid du Colombier height = fixed2int_ceiling(bbox.q.y) - y + 1;
5957dd7cddfSDavid du Colombier fit_fill_y(dev, y, height);
5967dd7cddfSDavid du Colombier fit_fill_h(dev, y, height);
5977dd7cddfSDavid du Colombier if (height <= 0)
5987dd7cddfSDavid du Colombier return 0;
5997dd7cddfSDavid du Colombier }
6007dd7cddfSDavid du Colombier y0 = y;
6017dd7cddfSDavid du Colombier y1 = y + height;
6023ff48bf5SDavid du Colombier cmd_check_fill_known(cdev, pis, params->flatness, &adjust, pcpath,
6033ff48bf5SDavid du Colombier &unknown);
6047dd7cddfSDavid du Colombier if (unknown)
6057dd7cddfSDavid du Colombier cmd_clear_known(cdev, unknown);
6067dd7cddfSDavid du Colombier FOR_RECTS_NO_ERROR {
6073ff48bf5SDavid du Colombier int code = cmd_do_write_unknown(cdev, pcls, FILL_KNOWN);
6087dd7cddfSDavid du Colombier
6097dd7cddfSDavid du Colombier if (code < 0)
6107dd7cddfSDavid du Colombier return code;
6117dd7cddfSDavid du Colombier if ((code = cmd_do_enable_clip(cdev, pcls, pcpath != NULL)) < 0 ||
6127dd7cddfSDavid du Colombier (code = cmd_update_lop(cdev, pcls, lop)) < 0
6137dd7cddfSDavid du Colombier )
6147dd7cddfSDavid du Colombier return code;
6157dd7cddfSDavid du Colombier code = cmd_put_drawing_color(cdev, pcls, pdcolor);
6167dd7cddfSDavid du Colombier if (code < 0) {
6177dd7cddfSDavid du Colombier /* Something went wrong, use the default implementation. */
6187dd7cddfSDavid du Colombier return gx_default_fill_path(dev, pis, ppath, params, pdcolor,
6197dd7cddfSDavid du Colombier pcpath);
6207dd7cddfSDavid du Colombier }
6217dd7cddfSDavid du Colombier pcls->colors_used.slow_rop |= slow_rop;
6227dd7cddfSDavid du Colombier code = cmd_put_path(cdev, pcls, ppath,
6237dd7cddfSDavid du Colombier int2fixed(max(y - 1, y0)),
6247dd7cddfSDavid du Colombier int2fixed(min(y + height + 1, y1)),
625*593dc095SDavid du Colombier op,
6267dd7cddfSDavid du Colombier true, sn_none /* fill doesn't need the notes */ );
6277dd7cddfSDavid du Colombier if (code < 0)
6287dd7cddfSDavid du Colombier return code;
6297dd7cddfSDavid du Colombier } END_RECTS_NO_ERROR;
6307dd7cddfSDavid du Colombier return 0;
6317dd7cddfSDavid du Colombier }
6327dd7cddfSDavid du Colombier
6337dd7cddfSDavid du Colombier int
clist_stroke_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_stroke_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)6347dd7cddfSDavid du Colombier clist_stroke_path(gx_device * dev, const gs_imager_state * pis, gx_path * ppath,
6357dd7cddfSDavid du Colombier const gx_stroke_params * params,
6367dd7cddfSDavid du Colombier const gx_drawing_color * pdcolor, const gx_clip_path * pcpath)
6377dd7cddfSDavid du Colombier {
6387dd7cddfSDavid du Colombier gx_device_clist_writer * const cdev =
6397dd7cddfSDavid du Colombier &((gx_device_clist *)dev)->writer;
6407dd7cddfSDavid du Colombier int pattern_size = pis->line_params.dash.pattern_size;
6417dd7cddfSDavid du Colombier uint unknown = 0;
6427dd7cddfSDavid du Colombier gs_fixed_rect bbox;
6437dd7cddfSDavid du Colombier gs_fixed_point expansion;
644*593dc095SDavid du Colombier int adjust_y, expansion_code;
645*593dc095SDavid du Colombier int y, height;
6467dd7cddfSDavid du Colombier gs_logical_operation_t lop = pis->log_op;
6477dd7cddfSDavid du Colombier bool slow_rop = cmd_slow_rop(dev, lop_know_S_0(lop), pdcolor);
6487dd7cddfSDavid du Colombier
6497dd7cddfSDavid du Colombier if ((cdev->disable_mask & clist_disable_stroke_path) ||
6507dd7cddfSDavid du Colombier gs_debug_c(',')
6517dd7cddfSDavid du Colombier ) {
6527dd7cddfSDavid du Colombier /* Disable path-based banding. */
6537dd7cddfSDavid du Colombier return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
6547dd7cddfSDavid du Colombier pcpath);
6557dd7cddfSDavid du Colombier }
6567dd7cddfSDavid du Colombier gx_path_bbox(ppath, &bbox);
6577dd7cddfSDavid du Colombier /* We must use the supplied imager state, not our saved one, */
6587dd7cddfSDavid du Colombier /* for computing the stroke expansion. */
659*593dc095SDavid du Colombier expansion_code = gx_stroke_path_expansion(pis, ppath, &expansion);
660*593dc095SDavid du Colombier if (expansion_code < 0) {
6617dd7cddfSDavid du Colombier /* Expansion is too large: use the entire page. */
6627dd7cddfSDavid du Colombier adjust_y = 0;
6637dd7cddfSDavid du Colombier y = 0;
6647dd7cddfSDavid du Colombier height = dev->height;
6657dd7cddfSDavid du Colombier } else {
6667dd7cddfSDavid du Colombier adjust_y = fixed2int_ceiling(expansion.y) + 1;
6677dd7cddfSDavid du Colombier y = fixed2int(bbox.p.y) - adjust_y;
6687dd7cddfSDavid du Colombier height = fixed2int_ceiling(bbox.q.y) - y + adjust_y;
6697dd7cddfSDavid du Colombier fit_fill_y(dev, y, height);
6707dd7cddfSDavid du Colombier fit_fill_h(dev, y, height);
6717dd7cddfSDavid du Colombier if (height <= 0)
6727dd7cddfSDavid du Colombier return 0;
6737dd7cddfSDavid du Colombier }
6747dd7cddfSDavid du Colombier /* Check the dash pattern, since we bail out if */
6757dd7cddfSDavid du Colombier /* the pattern is too large. */
6767dd7cddfSDavid du Colombier if (cdev->imager_state.line_params.dash.pattern_size != pattern_size ||
6777dd7cddfSDavid du Colombier (pattern_size != 0 &&
6787dd7cddfSDavid du Colombier memcmp(cdev->dash_pattern, pis->line_params.dash.pattern,
6797dd7cddfSDavid du Colombier pattern_size * sizeof(float))) ||
6807dd7cddfSDavid du Colombier cdev->imager_state.line_params.dash.offset !=
6817dd7cddfSDavid du Colombier pis->line_params.dash.offset ||
6827dd7cddfSDavid du Colombier cdev->imager_state.line_params.dash.adapt !=
6837dd7cddfSDavid du Colombier pis->line_params.dash.adapt ||
6847dd7cddfSDavid du Colombier cdev->imager_state.line_params.dot_length !=
6857dd7cddfSDavid du Colombier pis->line_params.dot_length ||
6867dd7cddfSDavid du Colombier cdev->imager_state.line_params.dot_length_absolute !=
6877dd7cddfSDavid du Colombier pis->line_params.dot_length_absolute
6887dd7cddfSDavid du Colombier ) {
6897dd7cddfSDavid du Colombier /* Bail out if the dash pattern is too long. */
6907dd7cddfSDavid du Colombier if (pattern_size > cmd_max_dash)
6917dd7cddfSDavid du Colombier return gx_default_stroke_path(dev, pis, ppath, params,
6927dd7cddfSDavid du Colombier pdcolor, pcpath);
6937dd7cddfSDavid du Colombier unknown |= dash_known;
6947dd7cddfSDavid du Colombier /*
6957dd7cddfSDavid du Colombier * Temporarily reset the dash pattern pointer for gx_set_dash,
6967dd7cddfSDavid du Colombier * but don't leave it set, since that would confuse the GC.
6977dd7cddfSDavid du Colombier */
6987dd7cddfSDavid du Colombier cdev->imager_state.line_params.dash.pattern = cdev->dash_pattern;
6997dd7cddfSDavid du Colombier gx_set_dash(&cdev->imager_state.line_params.dash,
7007dd7cddfSDavid du Colombier pis->line_params.dash.pattern,
7017dd7cddfSDavid du Colombier pis->line_params.dash.pattern_size,
7027dd7cddfSDavid du Colombier pis->line_params.dash.offset, NULL);
7037dd7cddfSDavid du Colombier cdev->imager_state.line_params.dash.pattern = 0;
7047dd7cddfSDavid du Colombier gx_set_dash_adapt(&cdev->imager_state.line_params.dash,
7057dd7cddfSDavid du Colombier pis->line_params.dash.adapt);
7067dd7cddfSDavid du Colombier gx_set_dot_length(&cdev->imager_state.line_params,
7077dd7cddfSDavid du Colombier pis->line_params.dot_length,
7087dd7cddfSDavid du Colombier pis->line_params.dot_length_absolute);
7097dd7cddfSDavid du Colombier }
7103ff48bf5SDavid du Colombier if (state_neq(line_params.cap) || state_neq(line_params.join)) {
7113ff48bf5SDavid du Colombier unknown |= cap_join_known;
7123ff48bf5SDavid du Colombier state_update(line_params.cap);
7133ff48bf5SDavid du Colombier state_update(line_params.join);
7147dd7cddfSDavid du Colombier }
7153ff48bf5SDavid du Colombier cmd_check_fill_known(cdev, pis, params->flatness, &pis->fill_adjust,
7163ff48bf5SDavid du Colombier pcpath, &unknown);
7173ff48bf5SDavid du Colombier if (state_neq(line_params.half_width)) {
7183ff48bf5SDavid du Colombier unknown |= line_width_known;
7193ff48bf5SDavid du Colombier state_update(line_params.half_width);
7203ff48bf5SDavid du Colombier }
7213ff48bf5SDavid du Colombier if (state_neq(line_params.miter_limit)) {
7223ff48bf5SDavid du Colombier unknown |= miter_limit_known;
7233ff48bf5SDavid du Colombier gx_set_miter_limit(&cdev->imager_state.line_params,
7243ff48bf5SDavid du Colombier pis->line_params.miter_limit);
7257dd7cddfSDavid du Colombier }
7267dd7cddfSDavid du Colombier if (state_neq(ctm.xx) || state_neq(ctm.xy) ||
7277dd7cddfSDavid du Colombier state_neq(ctm.yx) || state_neq(ctm.yy) ||
7287dd7cddfSDavid du Colombier /* We don't actually need tx or ty, but we don't want to bother */
7297dd7cddfSDavid du Colombier /* tracking them separately from the other coefficients. */
7307dd7cddfSDavid du Colombier state_neq(ctm.tx) || state_neq(ctm.ty)
7317dd7cddfSDavid du Colombier ) {
7327dd7cddfSDavid du Colombier unknown |= ctm_known;
7337dd7cddfSDavid du Colombier state_update(ctm);
7347dd7cddfSDavid du Colombier }
7357dd7cddfSDavid du Colombier if (unknown)
7367dd7cddfSDavid du Colombier cmd_clear_known(cdev, unknown);
7377dd7cddfSDavid du Colombier FOR_RECTS_NO_ERROR {
7387dd7cddfSDavid du Colombier int code;
7397dd7cddfSDavid du Colombier
7407dd7cddfSDavid du Colombier if ((code = cmd_do_write_unknown(cdev, pcls, stroke_all_known)) < 0 ||
7417dd7cddfSDavid du Colombier (code = cmd_do_enable_clip(cdev, pcls, pcpath != NULL)) < 0 ||
7427dd7cddfSDavid du Colombier (code = cmd_update_lop(cdev, pcls, lop)) < 0
7437dd7cddfSDavid du Colombier )
7447dd7cddfSDavid du Colombier return code;
7457dd7cddfSDavid du Colombier code = cmd_put_drawing_color(cdev, pcls, pdcolor);
7467dd7cddfSDavid du Colombier if (code < 0) {
7477dd7cddfSDavid du Colombier /* Something went wrong, use the default implementation. */
7487dd7cddfSDavid du Colombier return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
7497dd7cddfSDavid du Colombier pcpath);
7507dd7cddfSDavid du Colombier }
7517dd7cddfSDavid du Colombier pcls->colors_used.slow_rop |= slow_rop;
7527dd7cddfSDavid du Colombier {
7537dd7cddfSDavid du Colombier fixed ymin, ymax;
7547dd7cddfSDavid du Colombier
7557dd7cddfSDavid du Colombier /*
7567dd7cddfSDavid du Colombier * If a dash pattern is active, we can't skip segments
7577dd7cddfSDavid du Colombier * outside the clipping region, because that would throw off
7587dd7cddfSDavid du Colombier * the pattern.
759*593dc095SDavid du Colombier * Don't skip segments when expansion is unknown.
7607dd7cddfSDavid du Colombier */
7617dd7cddfSDavid du Colombier
762*593dc095SDavid du Colombier if (pattern_size || expansion_code < 0 ) {
7637dd7cddfSDavid du Colombier ymin = min_fixed;
7647dd7cddfSDavid du Colombier ymax = max_fixed;
765*593dc095SDavid du Colombier } else {
766*593dc095SDavid du Colombier ymin = int2fixed(y - adjust_y);
767*593dc095SDavid du Colombier ymax = int2fixed(y + height + adjust_y);
7687dd7cddfSDavid du Colombier }
7697dd7cddfSDavid du Colombier code = cmd_put_path(cdev, pcls, ppath, ymin, ymax,
770*593dc095SDavid du Colombier cmd_opv_stroke,
7717dd7cddfSDavid du Colombier false, (segment_notes)~0);
7727dd7cddfSDavid du Colombier if (code < 0)
7737dd7cddfSDavid du Colombier return code;
7747dd7cddfSDavid du Colombier }
7757dd7cddfSDavid du Colombier } END_RECTS_NO_ERROR;
7767dd7cddfSDavid du Colombier return 0;
7777dd7cddfSDavid du Colombier }
7787dd7cddfSDavid du Colombier
7797dd7cddfSDavid du Colombier /*
7807dd7cddfSDavid du Colombier * Fill_parallelogram and fill_triangle aren't very efficient. This isn't
7817dd7cddfSDavid du Colombier * important right now, since the non-degenerate case is only used for
7827dd7cddfSDavid du Colombier * smooth shading. However, the rectangular case of fill_parallelogram is
7837dd7cddfSDavid du Colombier * sometimes used for images, so its performance does matter.
7847dd7cddfSDavid du Colombier */
7857dd7cddfSDavid du Colombier
7867dd7cddfSDavid du Colombier private int
clist_put_polyfill(gx_device * dev,fixed px,fixed py,const gs_fixed_point * points,int num_points,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)7877dd7cddfSDavid du Colombier clist_put_polyfill(gx_device *dev, fixed px, fixed py,
7887dd7cddfSDavid du Colombier const gs_fixed_point *points, int num_points,
7897dd7cddfSDavid du Colombier const gx_drawing_color *pdcolor, gs_logical_operation_t lop)
7907dd7cddfSDavid du Colombier {
7917dd7cddfSDavid du Colombier gx_path path;
7927dd7cddfSDavid du Colombier gs_memory_t *mem = dev->memory;
7937dd7cddfSDavid du Colombier int code;
7947dd7cddfSDavid du Colombier gx_device_clist_writer * const cdev =
7957dd7cddfSDavid du Colombier &((gx_device_clist *)dev)->writer;
7967dd7cddfSDavid du Colombier gs_fixed_rect bbox;
7977dd7cddfSDavid du Colombier int y, height, y0, y1;
7987dd7cddfSDavid du Colombier bool slow_rop = cmd_slow_rop(dev, lop_know_S_0(lop), pdcolor);
7997dd7cddfSDavid du Colombier
8007dd7cddfSDavid du Colombier if (gs_debug_c(','))
8017dd7cddfSDavid du Colombier return -1; /* path-based banding is disabled */
8027dd7cddfSDavid du Colombier gx_path_init_local(&path, mem);
8037dd7cddfSDavid du Colombier if ((code = gx_path_add_point(&path, px, py)) < 0 ||
8047dd7cddfSDavid du Colombier (code = gx_path_add_lines(&path, points, num_points)) < 0
8057dd7cddfSDavid du Colombier )
8067dd7cddfSDavid du Colombier goto out;
8077dd7cddfSDavid du Colombier gx_path_bbox(&path, &bbox);
8087dd7cddfSDavid du Colombier y = fixed2int(bbox.p.y) - 1;
8097dd7cddfSDavid du Colombier height = fixed2int_ceiling(bbox.q.y) - y + 1;
8107dd7cddfSDavid du Colombier fit_fill_y(dev, y, height);
8117dd7cddfSDavid du Colombier fit_fill_h(dev, y, height);
8127dd7cddfSDavid du Colombier if (height <= 0)
8137dd7cddfSDavid du Colombier return 0;
8147dd7cddfSDavid du Colombier y0 = y;
8157dd7cddfSDavid du Colombier y1 = y + height;
8167dd7cddfSDavid du Colombier FOR_RECTS_NO_ERROR {
8177dd7cddfSDavid du Colombier if ((code = cmd_update_lop(cdev, pcls, lop)) < 0 ||
8187dd7cddfSDavid du Colombier (code = cmd_put_drawing_color(cdev, pcls, pdcolor)) < 0)
8197dd7cddfSDavid du Colombier goto out;
8207dd7cddfSDavid du Colombier pcls->colors_used.slow_rop |= slow_rop;
8217dd7cddfSDavid du Colombier code = cmd_put_path(cdev, pcls, &path,
8227dd7cddfSDavid du Colombier int2fixed(max(y - 1, y0)),
8237dd7cddfSDavid du Colombier int2fixed(min(y + height + 1, y1)),
824*593dc095SDavid du Colombier cmd_opv_polyfill,
8257dd7cddfSDavid du Colombier true, sn_none /* fill doesn't need the notes */ );
8267dd7cddfSDavid du Colombier if (code < 0)
8277dd7cddfSDavid du Colombier goto out;
8287dd7cddfSDavid du Colombier } END_RECTS_NO_ERROR;
8297dd7cddfSDavid du Colombier out:
8307dd7cddfSDavid du Colombier gx_path_free(&path, "clist_put_polyfill");
8317dd7cddfSDavid du Colombier return code;
8327dd7cddfSDavid du Colombier }
8337dd7cddfSDavid du Colombier
8347dd7cddfSDavid du Colombier int
clist_fill_parallelogram(gx_device * dev,fixed px,fixed py,fixed ax,fixed ay,fixed bx,fixed by,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)8357dd7cddfSDavid du Colombier clist_fill_parallelogram(gx_device *dev, fixed px, fixed py,
8367dd7cddfSDavid du Colombier fixed ax, fixed ay, fixed bx, fixed by,
8377dd7cddfSDavid du Colombier const gx_drawing_color *pdcolor,
8387dd7cddfSDavid du Colombier gs_logical_operation_t lop)
8397dd7cddfSDavid du Colombier {
8407dd7cddfSDavid du Colombier gs_fixed_point pts[3];
8417dd7cddfSDavid du Colombier int code;
8427dd7cddfSDavid du Colombier
8437dd7cddfSDavid du Colombier if (PARALLELOGRAM_IS_RECT(ax, ay, bx, by)) {
8447dd7cddfSDavid du Colombier gs_int_rect r;
8457dd7cddfSDavid du Colombier
8467dd7cddfSDavid du Colombier INT_RECT_FROM_PARALLELOGRAM(&r, px, py, ax, ay, bx, by);
8477dd7cddfSDavid du Colombier return gx_fill_rectangle_device_rop(r.p.x, r.p.y, r.q.x - r.p.x,
8487dd7cddfSDavid du Colombier r.q.y - r.p.y, pdcolor, dev, lop);
8497dd7cddfSDavid du Colombier }
8507dd7cddfSDavid du Colombier pts[0].x = px + ax, pts[0].y = py + ay;
8517dd7cddfSDavid du Colombier pts[1].x = pts[0].x + bx, pts[1].y = pts[0].y + by;
8527dd7cddfSDavid du Colombier pts[2].x = px + bx, pts[2].y = py + by;
8537dd7cddfSDavid du Colombier code = clist_put_polyfill(dev, px, py, pts, 3, pdcolor, lop);
8547dd7cddfSDavid du Colombier return (code >= 0 ? code :
8557dd7cddfSDavid du Colombier gx_default_fill_parallelogram(dev, px, py, ax, ay, bx, by,
8567dd7cddfSDavid du Colombier pdcolor, lop));
8577dd7cddfSDavid du Colombier }
8587dd7cddfSDavid du Colombier
8597dd7cddfSDavid du Colombier int
clist_fill_triangle(gx_device * dev,fixed px,fixed py,fixed ax,fixed ay,fixed bx,fixed by,const gx_drawing_color * pdcolor,gs_logical_operation_t lop)8607dd7cddfSDavid du Colombier clist_fill_triangle(gx_device *dev, fixed px, fixed py,
8617dd7cddfSDavid du Colombier fixed ax, fixed ay, fixed bx, fixed by,
8627dd7cddfSDavid du Colombier const gx_drawing_color *pdcolor,
8637dd7cddfSDavid du Colombier gs_logical_operation_t lop)
8647dd7cddfSDavid du Colombier {
8657dd7cddfSDavid du Colombier gs_fixed_point pts[2];
8667dd7cddfSDavid du Colombier int code;
8677dd7cddfSDavid du Colombier
8687dd7cddfSDavid du Colombier pts[0].x = px + ax, pts[0].y = py + ay;
8697dd7cddfSDavid du Colombier pts[1].x = px + bx, pts[1].y = py + by;
8707dd7cddfSDavid du Colombier code = clist_put_polyfill(dev, px, py, pts, 2, pdcolor, lop);
8717dd7cddfSDavid du Colombier return (code >= 0 ? code :
8727dd7cddfSDavid du Colombier gx_default_fill_triangle(dev, px, py, ax, ay, bx, by,
8737dd7cddfSDavid du Colombier pdcolor, lop));
8747dd7cddfSDavid du Colombier }
8757dd7cddfSDavid du Colombier
8767dd7cddfSDavid du Colombier /* ------ Path utilities ------ */
8777dd7cddfSDavid du Colombier
8787dd7cddfSDavid du Colombier /* Define the state bookkeeping for writing path segments. */
8797dd7cddfSDavid du Colombier typedef struct cmd_segment_writer_s {
8807dd7cddfSDavid du Colombier /* Set at initialization */
8817dd7cddfSDavid du Colombier gx_device_clist_writer *cldev;
8827dd7cddfSDavid du Colombier gx_clist_state *pcls;
8837dd7cddfSDavid du Colombier /* Updated dynamically */
8847dd7cddfSDavid du Colombier segment_notes notes;
8857dd7cddfSDavid du Colombier byte *dp;
8867dd7cddfSDavid du Colombier int len;
8877dd7cddfSDavid du Colombier gs_fixed_point delta_first;
8887dd7cddfSDavid du Colombier byte cmd[6 * (1 + sizeof(fixed))];
8897dd7cddfSDavid du Colombier }
8907dd7cddfSDavid du Colombier cmd_segment_writer;
8917dd7cddfSDavid du Colombier
8927dd7cddfSDavid du Colombier /* Put out a path segment command. */
8937dd7cddfSDavid du Colombier private int
cmd_put_segment(cmd_segment_writer * psw,byte op,const fixed * operands,segment_notes notes)8947dd7cddfSDavid du Colombier cmd_put_segment(cmd_segment_writer * psw, byte op,
8957dd7cddfSDavid du Colombier const fixed * operands, segment_notes notes)
8967dd7cddfSDavid du Colombier {
8977dd7cddfSDavid du Colombier const fixed *optr = operands;
8987dd7cddfSDavid du Colombier /* Fetch num_operands before possible command merging. */
8997dd7cddfSDavid du Colombier static const byte op_num_operands[] = {
9007dd7cddfSDavid du Colombier cmd_segment_op_num_operands_values
9017dd7cddfSDavid du Colombier };
9027dd7cddfSDavid du Colombier int i = op_num_operands[op & 0xf];
9033ff48bf5SDavid du Colombier /* One picky compiler complains if we initialize to psw->cmd - 1. */
9043ff48bf5SDavid du Colombier byte *q = psw->cmd;
9053ff48bf5SDavid du Colombier
9063ff48bf5SDavid du Colombier --q;
9077dd7cddfSDavid du Colombier
9087dd7cddfSDavid du Colombier #ifdef DEBUG
9097dd7cddfSDavid du Colombier if (gs_debug_c('L')) {
9107dd7cddfSDavid du Colombier int j;
9117dd7cddfSDavid du Colombier
9127dd7cddfSDavid du Colombier dlprintf2("[L] %s:%d:", cmd_sub_op_names[op >> 4][op & 0xf],
9137dd7cddfSDavid du Colombier (int)notes);
9147dd7cddfSDavid du Colombier for (j = 0; j < i; ++j)
9157dd7cddfSDavid du Colombier dprintf1(" %g", fixed2float(operands[j]));
9167dd7cddfSDavid du Colombier dputs("\n");
9177dd7cddfSDavid du Colombier }
9187dd7cddfSDavid du Colombier #endif
9197dd7cddfSDavid du Colombier
9207dd7cddfSDavid du Colombier /* Merge or shorten commands if possible. */
9217dd7cddfSDavid du Colombier if (op == cmd_opv_rlineto) {
9227dd7cddfSDavid du Colombier if (operands[0] == 0)
9237dd7cddfSDavid du Colombier op = cmd_opv_vlineto, optr = ++operands, i = 1;
9247dd7cddfSDavid du Colombier else if (operands[1] == 0)
9257dd7cddfSDavid du Colombier op = cmd_opv_hlineto, i = 1;
9267dd7cddfSDavid du Colombier else
9277dd7cddfSDavid du Colombier switch (*psw->dp) {
9287dd7cddfSDavid du Colombier case cmd_opv_rmoveto:
9297dd7cddfSDavid du Colombier psw->delta_first.x = operands[0];
9307dd7cddfSDavid du Colombier psw->delta_first.y = operands[1];
9317dd7cddfSDavid du Colombier op = cmd_opv_rmlineto;
9327dd7cddfSDavid du Colombier merge:cmd_uncount_op(*psw->dp, psw->len);
9337dd7cddfSDavid du Colombier cmd_shorten_op(psw->cldev, psw->pcls, psw->len); /* delete it */
9347dd7cddfSDavid du Colombier q += psw->len - 1;
9357dd7cddfSDavid du Colombier break;
9367dd7cddfSDavid du Colombier case cmd_opv_rmlineto:
9377dd7cddfSDavid du Colombier if (notes != psw->notes)
9387dd7cddfSDavid du Colombier break;
9397dd7cddfSDavid du Colombier op = cmd_opv_rm2lineto;
9407dd7cddfSDavid du Colombier goto merge;
9417dd7cddfSDavid du Colombier case cmd_opv_rm2lineto:
9427dd7cddfSDavid du Colombier if (notes != psw->notes)
9437dd7cddfSDavid du Colombier break;
9447dd7cddfSDavid du Colombier if (operands[0] == -psw->delta_first.x &&
9457dd7cddfSDavid du Colombier operands[1] == -psw->delta_first.y
9467dd7cddfSDavid du Colombier ) {
9477dd7cddfSDavid du Colombier cmd_uncount_op(cmd_opv_rm2lineto, psw->len);
9487dd7cddfSDavid du Colombier *psw->dp = cmd_count_op(cmd_opv_rm3lineto, psw->len);
9497dd7cddfSDavid du Colombier return 0;
9507dd7cddfSDavid du Colombier }
9517dd7cddfSDavid du Colombier break;
9527dd7cddfSDavid du Colombier default:
9537dd7cddfSDavid du Colombier ;
9547dd7cddfSDavid du Colombier }
9557dd7cddfSDavid du Colombier }
9567dd7cddfSDavid du Colombier for (; --i >= 0; ++optr) {
9577dd7cddfSDavid du Colombier fixed d = *optr, d2;
9587dd7cddfSDavid du Colombier
9597dd7cddfSDavid du Colombier if (is_bits(d, _fixed_shift + 11) &&
9607dd7cddfSDavid du Colombier !(d & (float2fixed(0.25) - 1))
9617dd7cddfSDavid du Colombier ) {
9627dd7cddfSDavid du Colombier cmd_count_add1(stats_cmd_diffs[3]);
9637dd7cddfSDavid du Colombier d = ((d >> (_fixed_shift - 2)) & 0x1fff) + 0xc000;
9647dd7cddfSDavid du Colombier q += 2;
9657dd7cddfSDavid du Colombier } else if (is_bits(d, 19) && i > 0 && is_bits(d2 = optr[1], 19)) {
9667dd7cddfSDavid du Colombier cmd_count_add1(stats_cmd_diffs[0]);
9677dd7cddfSDavid du Colombier q[1] = (byte) ((d >> 13) & 0x3f);
9687dd7cddfSDavid du Colombier q[2] = (byte) (d >> 5);
9697dd7cddfSDavid du Colombier q[3] = (byte) ((d << 3) + ((d2 >> 16) & 7));
9707dd7cddfSDavid du Colombier q[4] = (byte) (d2 >> 8);
9717dd7cddfSDavid du Colombier q[5] = (byte) d2;
9727dd7cddfSDavid du Colombier q += 5;
9737dd7cddfSDavid du Colombier --i, ++optr;
9747dd7cddfSDavid du Colombier continue;
9757dd7cddfSDavid du Colombier } else if (is_bits(d, 22)) {
9767dd7cddfSDavid du Colombier cmd_count_add1(stats_cmd_diffs[1]);
9777dd7cddfSDavid du Colombier q[1] = (byte) (((d >> 16) & 0x3f) + 0x40);
9787dd7cddfSDavid du Colombier q += 3;
9797dd7cddfSDavid du Colombier } else if (is_bits(d, 30)) {
9807dd7cddfSDavid du Colombier cmd_count_add1(stats_cmd_diffs[2]);
9817dd7cddfSDavid du Colombier q[1] = (byte) (((d >> 24) & 0x3f) + 0x80);
9827dd7cddfSDavid du Colombier q[2] = (byte) (d >> 16);
9837dd7cddfSDavid du Colombier q += 4;
9847dd7cddfSDavid du Colombier } else {
9857dd7cddfSDavid du Colombier int b;
9867dd7cddfSDavid du Colombier
9877dd7cddfSDavid du Colombier cmd_count_add1(stats_cmd_diffs[4]);
9887dd7cddfSDavid du Colombier *++q = 0xe0;
9897dd7cddfSDavid du Colombier for (b = sizeof(fixed) - 1; b > 1; --b)
9907dd7cddfSDavid du Colombier *++q = (byte) (d >> (b * 8));
9917dd7cddfSDavid du Colombier q += 2;
9927dd7cddfSDavid du Colombier }
9937dd7cddfSDavid du Colombier q[-1] = (byte) (d >> 8);
9947dd7cddfSDavid du Colombier *q = (byte) d;
9957dd7cddfSDavid du Colombier }
9967dd7cddfSDavid du Colombier if (notes != psw->notes) {
9977dd7cddfSDavid du Colombier byte *dp;
9987dd7cddfSDavid du Colombier int code =
9993ff48bf5SDavid du Colombier set_cmd_put_op(dp, psw->cldev, psw->pcls, cmd_opv_set_misc2, 3);
10007dd7cddfSDavid du Colombier
10017dd7cddfSDavid du Colombier if (code < 0)
10027dd7cddfSDavid du Colombier return code;
10033ff48bf5SDavid du Colombier dp[1] = segment_notes_known;
10043ff48bf5SDavid du Colombier dp[2] = notes;
10057dd7cddfSDavid du Colombier psw->notes = notes;
10067dd7cddfSDavid du Colombier } {
10077dd7cddfSDavid du Colombier int len = q + 2 - psw->cmd;
10087dd7cddfSDavid du Colombier byte *dp;
10097dd7cddfSDavid du Colombier int code = set_cmd_put_op(dp, psw->cldev, psw->pcls, op, len);
10107dd7cddfSDavid du Colombier
10117dd7cddfSDavid du Colombier if (code < 0)
10127dd7cddfSDavid du Colombier return code;
10137dd7cddfSDavid du Colombier memcpy(dp + 1, psw->cmd, len - 1);
10147dd7cddfSDavid du Colombier psw->len = len;
10157dd7cddfSDavid du Colombier psw->dp = dp;
10167dd7cddfSDavid du Colombier }
10177dd7cddfSDavid du Colombier return 0;
10187dd7cddfSDavid du Colombier }
10197dd7cddfSDavid du Colombier /* Put out a line segment command. */
10207dd7cddfSDavid du Colombier #define cmd_put_rmoveto(psw, operands)\
10217dd7cddfSDavid du Colombier cmd_put_segment(psw, cmd_opv_rmoveto, operands, sn_none)
10227dd7cddfSDavid du Colombier #define cmd_put_rlineto(psw, operands, notes)\
10237dd7cddfSDavid du Colombier cmd_put_segment(psw, cmd_opv_rlineto, operands, notes)
10247dd7cddfSDavid du Colombier
10257dd7cddfSDavid du Colombier /*
10267dd7cddfSDavid du Colombier * Write a path. We go to a lot of trouble to omit segments that are
10277dd7cddfSDavid du Colombier * entirely outside the band.
10287dd7cddfSDavid du Colombier */
10297dd7cddfSDavid du Colombier private int
cmd_put_path(gx_device_clist_writer * cldev,gx_clist_state * pcls,const gx_path * ppath,fixed ymin,fixed ymax,byte path_op,bool implicit_close,segment_notes keep_notes)10307dd7cddfSDavid du Colombier cmd_put_path(gx_device_clist_writer * cldev, gx_clist_state * pcls,
10317dd7cddfSDavid du Colombier const gx_path * ppath, fixed ymin, fixed ymax, byte path_op,
10327dd7cddfSDavid du Colombier bool implicit_close, segment_notes keep_notes)
10337dd7cddfSDavid du Colombier {
10347dd7cddfSDavid du Colombier gs_path_enum cenum;
10357dd7cddfSDavid du Colombier cmd_segment_writer writer;
10367dd7cddfSDavid du Colombier
10377dd7cddfSDavid du Colombier /*
10387dd7cddfSDavid du Colombier * initial_op is logically const. We would like to declare it as
10397dd7cddfSDavid du Colombier * static const, since some systems really dislike non-const statics,
10407dd7cddfSDavid du Colombier * but this would entail a cast in set_first_point() that provokes a
10417dd7cddfSDavid du Colombier * warning message from gcc. Instead, we pay the (tiny) cost of an
10427dd7cddfSDavid du Colombier * unnecessary dynamic initialization.
10437dd7cddfSDavid du Colombier */
10447dd7cddfSDavid du Colombier byte initial_op = cmd_opv_end_run;
10457dd7cddfSDavid du Colombier
10467dd7cddfSDavid du Colombier /*
10477dd7cddfSDavid du Colombier * We define the 'side' of a point according to its Y value as
10487dd7cddfSDavid du Colombier * follows:
10497dd7cddfSDavid du Colombier */
10507dd7cddfSDavid du Colombier #define which_side(y) ((y) < ymin ? -1 : (y) >= ymax ? 1 : 0)
10517dd7cddfSDavid du Colombier
10527dd7cddfSDavid du Colombier /*
10537dd7cddfSDavid du Colombier * While writing a subpath, we need to keep track of any segments
10547dd7cddfSDavid du Colombier * skipped at the beginning of the subpath and any segments skipped
10557dd7cddfSDavid du Colombier * just before the current segment. We do this with two sets of
10567dd7cddfSDavid du Colombier * state variables, one that tracks the actual path segments and one
10577dd7cddfSDavid du Colombier * that tracks the emitted segments.
10587dd7cddfSDavid du Colombier *
10597dd7cddfSDavid du Colombier * The following track the actual segments:
10607dd7cddfSDavid du Colombier */
10617dd7cddfSDavid du Colombier
10627dd7cddfSDavid du Colombier /*
10637dd7cddfSDavid du Colombier * The point and side of the last moveto (skipped if
10647dd7cddfSDavid du Colombier * start_side != 0):
10657dd7cddfSDavid du Colombier */
10667dd7cddfSDavid du Colombier gs_fixed_point start;
1067*593dc095SDavid du Colombier int start_side = 0x7badf00d; /* Initialize against indeterminizm. */
10687dd7cddfSDavid du Colombier
10697dd7cddfSDavid du Colombier /*
10707dd7cddfSDavid du Colombier * Whether any lines or curves were skipped immediately
10717dd7cddfSDavid du Colombier * following the moveto:
10727dd7cddfSDavid du Colombier */
1073*593dc095SDavid du Colombier bool start_skip = 0x7badf00d; /* Initialize against indeterminizm. */
10747dd7cddfSDavid du Colombier
10757dd7cddfSDavid du Colombier /* The side of the last point: */
1076*593dc095SDavid du Colombier int side = 0x7badf00d; /* Initialize against indeterminizm. */
10777dd7cddfSDavid du Colombier
10787dd7cddfSDavid du Colombier /* The last point with side != 0: */
10797dd7cddfSDavid du Colombier gs_fixed_point out;
10807dd7cddfSDavid du Colombier
10817dd7cddfSDavid du Colombier /* If the last out-going segment was a lineto, */
10827dd7cddfSDavid du Colombier /* its notes: */
1083*593dc095SDavid du Colombier segment_notes out_notes = 0x7badf00d; /* Initialize against indeterminizm. */
10847dd7cddfSDavid du Colombier
10857dd7cddfSDavid du Colombier /*
10867dd7cddfSDavid du Colombier * The following track the emitted segments:
10877dd7cddfSDavid du Colombier */
10887dd7cddfSDavid du Colombier
10897dd7cddfSDavid du Colombier /* The last point emitted: */
10907dd7cddfSDavid du Colombier fixed px = int2fixed(pcls->rect.x);
10917dd7cddfSDavid du Colombier fixed py = int2fixed(pcls->rect.y);
10927dd7cddfSDavid du Colombier
10937dd7cddfSDavid du Colombier /* The point of the last emitted moveto: */
10947dd7cddfSDavid du Colombier gs_fixed_point first;
10957dd7cddfSDavid du Colombier
10967dd7cddfSDavid du Colombier /* Information about the last emitted operation: */
10977dd7cddfSDavid du Colombier int open = 0; /* -1 if last was moveto, 1 if line/curveto, */
10987dd7cddfSDavid du Colombier
10997dd7cddfSDavid du Colombier /* 0 if newpath/closepath */
11007dd7cddfSDavid du Colombier
11017dd7cddfSDavid du Colombier
11027dd7cddfSDavid du Colombier if_debug4('p', "[p]initial (%g,%g), clip [%g..%g)\n",
11037dd7cddfSDavid du Colombier fixed2float(px), fixed2float(py),
11047dd7cddfSDavid du Colombier fixed2float(ymin), fixed2float(ymax));
11057dd7cddfSDavid du Colombier gx_path_enum_init(&cenum, ppath);
11067dd7cddfSDavid du Colombier writer.cldev = cldev;
11077dd7cddfSDavid du Colombier writer.pcls = pcls;
11087dd7cddfSDavid du Colombier writer.notes = sn_none;
11097dd7cddfSDavid du Colombier #define set_first_point() (writer.dp = &initial_op)
11107dd7cddfSDavid du Colombier #define first_point() (writer.dp == &initial_op)
11117dd7cddfSDavid du Colombier set_first_point();
11127dd7cddfSDavid du Colombier for (;;) {
11137dd7cddfSDavid du Colombier fixed vs[6];
11147dd7cddfSDavid du Colombier struct { fixed vs[6]; } prev;
11157dd7cddfSDavid du Colombier
11167dd7cddfSDavid du Colombier #define A vs[0]
11177dd7cddfSDavid du Colombier #define B vs[1]
11187dd7cddfSDavid du Colombier #define C vs[2]
11197dd7cddfSDavid du Colombier #define D vs[3]
11207dd7cddfSDavid du Colombier #define E vs[4]
11217dd7cddfSDavid du Colombier #define F vs[5]
11227dd7cddfSDavid du Colombier int pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *) vs);
11237dd7cddfSDavid du Colombier byte *dp;
11247dd7cddfSDavid du Colombier int code;
11257dd7cddfSDavid du Colombier
11267dd7cddfSDavid du Colombier switch (pe_op) {
11277dd7cddfSDavid du Colombier case 0:
11287dd7cddfSDavid du Colombier /* If the path is open and needs an implicit close, */
11297dd7cddfSDavid du Colombier /* do the close and then come here again. */
11307dd7cddfSDavid du Colombier if (open > 0 && implicit_close)
11317dd7cddfSDavid du Colombier goto close;
11327dd7cddfSDavid du Colombier /* All done. */
11337dd7cddfSDavid du Colombier pcls->rect.x = fixed2int_var(px);
11347dd7cddfSDavid du Colombier pcls->rect.y = fixed2int_var(py);
11357dd7cddfSDavid du Colombier if_debug2('p', "[p]final (%d,%d)\n",
11367dd7cddfSDavid du Colombier pcls->rect.x, pcls->rect.y);
11377dd7cddfSDavid du Colombier return set_cmd_put_op(dp, cldev, pcls, path_op, 1);
11387dd7cddfSDavid du Colombier case gs_pe_moveto:
11397dd7cddfSDavid du Colombier /* If the path is open and needs an implicit close, */
11407dd7cddfSDavid du Colombier /* do a closepath and then redo the moveto. */
11417dd7cddfSDavid du Colombier if (open > 0 && implicit_close) {
11427dd7cddfSDavid du Colombier gx_path_enum_backup(&cenum);
11437dd7cddfSDavid du Colombier goto close;
11447dd7cddfSDavid du Colombier }
11457dd7cddfSDavid du Colombier open = -1;
11467dd7cddfSDavid du Colombier start.x = A, start.y = B;
11477dd7cddfSDavid du Colombier start_skip = false;
11487dd7cddfSDavid du Colombier if ((start_side = side = which_side(B)) != 0) {
11497dd7cddfSDavid du Colombier out.x = A, out.y = B;
11507dd7cddfSDavid du Colombier if_debug3('p', "[p]skip moveto (%g,%g) side %d\n",
11517dd7cddfSDavid du Colombier fixed2float(out.x), fixed2float(out.y),
11527dd7cddfSDavid du Colombier side);
11537dd7cddfSDavid du Colombier continue;
11547dd7cddfSDavid du Colombier }
11557dd7cddfSDavid du Colombier C = A - px, D = B - py;
11567dd7cddfSDavid du Colombier first.x = px = A, first.y = py = B;
11577dd7cddfSDavid du Colombier code = cmd_put_rmoveto(&writer, &C);
11587dd7cddfSDavid du Colombier if_debug2('p', "[p]moveto (%g,%g)\n",
11597dd7cddfSDavid du Colombier fixed2float(px), fixed2float(py));
11607dd7cddfSDavid du Colombier break;
11617dd7cddfSDavid du Colombier case gs_pe_lineto:
11627dd7cddfSDavid du Colombier {
11637dd7cddfSDavid du Colombier int next_side = which_side(B);
11647dd7cddfSDavid du Colombier segment_notes notes =
11657dd7cddfSDavid du Colombier gx_path_enum_notes(&cenum) & keep_notes;
11667dd7cddfSDavid du Colombier
11677dd7cddfSDavid du Colombier if (next_side == side && side != 0) { /* Skip a line completely outside the clip region. */
11687dd7cddfSDavid du Colombier if (open < 0)
11697dd7cddfSDavid du Colombier start_skip = true;
11707dd7cddfSDavid du Colombier out.x = A, out.y = B;
11717dd7cddfSDavid du Colombier out_notes = notes;
11727dd7cddfSDavid du Colombier if_debug3('p', "[p]skip lineto (%g,%g) side %d\n",
11737dd7cddfSDavid du Colombier fixed2float(out.x), fixed2float(out.y),
11747dd7cddfSDavid du Colombier side);
11757dd7cddfSDavid du Colombier continue;
11767dd7cddfSDavid du Colombier }
11777dd7cddfSDavid du Colombier /* If we skipped any segments, put out a moveto/lineto. */
11787dd7cddfSDavid du Colombier if (side && (px != out.x || py != out.y || first_point())) {
11797dd7cddfSDavid du Colombier C = out.x - px, D = out.y - py;
11807dd7cddfSDavid du Colombier if (open < 0) {
11817dd7cddfSDavid du Colombier first = out;
11827dd7cddfSDavid du Colombier code = cmd_put_rmoveto(&writer, &C);
11837dd7cddfSDavid du Colombier } else
11847dd7cddfSDavid du Colombier code = cmd_put_rlineto(&writer, &C, out_notes);
11857dd7cddfSDavid du Colombier if (code < 0)
11867dd7cddfSDavid du Colombier return code;
11877dd7cddfSDavid du Colombier px = out.x, py = out.y;
11887dd7cddfSDavid du Colombier if_debug3('p', "[p]catchup %s (%g,%g) for line\n",
11897dd7cddfSDavid du Colombier (open < 0 ? "moveto" : "lineto"),
11907dd7cddfSDavid du Colombier fixed2float(px), fixed2float(py));
11917dd7cddfSDavid du Colombier }
11927dd7cddfSDavid du Colombier if ((side = next_side) != 0) { /* Note a vertex going outside the clip region. */
11937dd7cddfSDavid du Colombier out.x = A, out.y = B;
11947dd7cddfSDavid du Colombier }
11957dd7cddfSDavid du Colombier C = A - px, D = B - py;
11967dd7cddfSDavid du Colombier px = A, py = B;
11977dd7cddfSDavid du Colombier open = 1;
11987dd7cddfSDavid du Colombier code = cmd_put_rlineto(&writer, &C, notes);
11997dd7cddfSDavid du Colombier }
12007dd7cddfSDavid du Colombier if_debug3('p', "[p]lineto (%g,%g) side %d\n",
12017dd7cddfSDavid du Colombier fixed2float(px), fixed2float(py), side);
12027dd7cddfSDavid du Colombier break;
12037dd7cddfSDavid du Colombier case gs_pe_closepath:
12047dd7cddfSDavid du Colombier #ifdef DEBUG
12057dd7cddfSDavid du Colombier {
12067dd7cddfSDavid du Colombier gs_path_enum cpenum;
12077dd7cddfSDavid du Colombier gs_fixed_point cvs[3];
12087dd7cddfSDavid du Colombier int op;
12097dd7cddfSDavid du Colombier
12107dd7cddfSDavid du Colombier cpenum = cenum;
12117dd7cddfSDavid du Colombier switch (op = gx_path_enum_next(&cpenum, cvs)) {
12127dd7cddfSDavid du Colombier case 0:
12137dd7cddfSDavid du Colombier case gs_pe_moveto:
12147dd7cddfSDavid du Colombier break;
12157dd7cddfSDavid du Colombier default:
12167dd7cddfSDavid du Colombier lprintf1("closepath followed by %d, not end/moveto!\n",
12177dd7cddfSDavid du Colombier op);
12187dd7cddfSDavid du Colombier }
12197dd7cddfSDavid du Colombier }
12207dd7cddfSDavid du Colombier #endif
12217dd7cddfSDavid du Colombier /* A closepath may require drawing an explicit line if */
12227dd7cddfSDavid du Colombier /* we skipped any segments at the beginning of the path. */
12237dd7cddfSDavid du Colombier close:if (side != start_side) { /* If we skipped any segments, put out a moveto/lineto. */
12247dd7cddfSDavid du Colombier if (side && (px != out.x || py != out.y || first_point())) {
12257dd7cddfSDavid du Colombier C = out.x - px, D = out.y - py;
12267dd7cddfSDavid du Colombier code = cmd_put_rlineto(&writer, &C, out_notes);
12277dd7cddfSDavid du Colombier if (code < 0)
12287dd7cddfSDavid du Colombier return code;
12297dd7cddfSDavid du Colombier px = out.x, py = out.y;
12307dd7cddfSDavid du Colombier if_debug2('p', "[p]catchup line (%g,%g) for close\n",
12317dd7cddfSDavid du Colombier fixed2float(px), fixed2float(py));
12327dd7cddfSDavid du Colombier }
12337dd7cddfSDavid du Colombier if (open > 0 && start_skip) { /* Draw the closing line back to the start. */
12347dd7cddfSDavid du Colombier C = start.x - px, D = start.y - py;
12357dd7cddfSDavid du Colombier code = cmd_put_rlineto(&writer, &C, sn_none);
12367dd7cddfSDavid du Colombier if (code < 0)
12377dd7cddfSDavid du Colombier return code;
12387dd7cddfSDavid du Colombier px = start.x, py = start.y;
12397dd7cddfSDavid du Colombier if_debug2('p', "[p]draw close to (%g,%g)\n",
12407dd7cddfSDavid du Colombier fixed2float(px), fixed2float(py));
12417dd7cddfSDavid du Colombier }
12427dd7cddfSDavid du Colombier }
12437dd7cddfSDavid du Colombier /*
12447dd7cddfSDavid du Colombier * We don't bother to update side because we know that the
12457dd7cddfSDavid du Colombier * next element after a closepath, if any, must be a moveto.
12467dd7cddfSDavid du Colombier * We must handle explicitly the possibility that the entire
12477dd7cddfSDavid du Colombier * subpath was skipped.
12487dd7cddfSDavid du Colombier */
12497dd7cddfSDavid du Colombier if (implicit_close || open <= 0) {
12507dd7cddfSDavid du Colombier /*
12517dd7cddfSDavid du Colombier * Force writing an explicit moveto if the next subpath
12527dd7cddfSDavid du Colombier * starts with a moveto to the same point where this one
12537dd7cddfSDavid du Colombier * ends.
12547dd7cddfSDavid du Colombier */
12557dd7cddfSDavid du Colombier set_first_point();
1256*593dc095SDavid du Colombier if (side != 0) {
1257*593dc095SDavid du Colombier open = 0;
12587dd7cddfSDavid du Colombier continue;
12597dd7cddfSDavid du Colombier }
1260*593dc095SDavid du Colombier }
12617dd7cddfSDavid du Colombier open = 0;
12627dd7cddfSDavid du Colombier px = first.x, py = first.y;
12637dd7cddfSDavid du Colombier code = cmd_put_segment(&writer, cmd_opv_closepath, &A, sn_none);
12647dd7cddfSDavid du Colombier if_debug0('p', "[p]close\n");
12657dd7cddfSDavid du Colombier break;
12667dd7cddfSDavid du Colombier case gs_pe_curveto:
12677dd7cddfSDavid du Colombier {
12687dd7cddfSDavid du Colombier segment_notes notes =
12697dd7cddfSDavid du Colombier gx_path_enum_notes(&cenum) & keep_notes;
12707dd7cddfSDavid du Colombier
12717dd7cddfSDavid du Colombier {
12727dd7cddfSDavid du Colombier fixed bpy, bqy;
12737dd7cddfSDavid du Colombier int all_side, out_side;
12747dd7cddfSDavid du Colombier
12757dd7cddfSDavid du Colombier /* Compute the Y bounds for the clipping check. */
12767dd7cddfSDavid du Colombier if (B < D)
12777dd7cddfSDavid du Colombier bpy = B, bqy = D;
12787dd7cddfSDavid du Colombier else
12797dd7cddfSDavid du Colombier bpy = D, bqy = B;
12807dd7cddfSDavid du Colombier if (F < bpy)
12817dd7cddfSDavid du Colombier bpy = F;
12827dd7cddfSDavid du Colombier else if (F > bqy)
12837dd7cddfSDavid du Colombier bqy = F;
12847dd7cddfSDavid du Colombier all_side = (bqy < ymin ? -1 : bpy > ymax ? 1 : 0);
12857dd7cddfSDavid du Colombier if (all_side != 0) {
12867dd7cddfSDavid du Colombier if (all_side == side) { /* Skip a curve entirely outside the clip region. */
12877dd7cddfSDavid du Colombier if (open < 0)
12887dd7cddfSDavid du Colombier start_skip = true;
12897dd7cddfSDavid du Colombier out.x = E, out.y = F;
12907dd7cddfSDavid du Colombier out_notes = notes;
12917dd7cddfSDavid du Colombier if_debug3('p', "[p]skip curveto (%g,%g) side %d\n",
12927dd7cddfSDavid du Colombier fixed2float(out.x), fixed2float(out.y),
12937dd7cddfSDavid du Colombier side);
12947dd7cddfSDavid du Colombier continue;
12957dd7cddfSDavid du Colombier }
12967dd7cddfSDavid du Colombier out_side = all_side;
12977dd7cddfSDavid du Colombier } else
12987dd7cddfSDavid du Colombier out_side = which_side(F);
12997dd7cddfSDavid du Colombier /* If we skipped any segments, put out a moveto/lineto. */
13007dd7cddfSDavid du Colombier if (side && (px != out.x || py != out.y || first_point())) {
13017dd7cddfSDavid du Colombier fixed diff[2];
13027dd7cddfSDavid du Colombier
13037dd7cddfSDavid du Colombier diff[0] = out.x - px, diff[1] = out.y - py;
13047dd7cddfSDavid du Colombier if (open < 0) {
13057dd7cddfSDavid du Colombier first = out;
13067dd7cddfSDavid du Colombier code = cmd_put_rmoveto(&writer, diff);
13077dd7cddfSDavid du Colombier } else
13087dd7cddfSDavid du Colombier code = cmd_put_rlineto(&writer, diff, out_notes);
13097dd7cddfSDavid du Colombier if (code < 0)
13107dd7cddfSDavid du Colombier return code;
13117dd7cddfSDavid du Colombier px = out.x, py = out.y;
13127dd7cddfSDavid du Colombier if_debug3('p', "[p]catchup %s (%g,%g) for curve\n",
13137dd7cddfSDavid du Colombier (open < 0 ? "moveto" : "lineto"),
13147dd7cddfSDavid du Colombier fixed2float(px), fixed2float(py));
13157dd7cddfSDavid du Colombier }
13167dd7cddfSDavid du Colombier if ((side = out_side) != 0) { /* Note a vertex going outside the clip region. */
13177dd7cddfSDavid du Colombier out.x = E, out.y = F;
13187dd7cddfSDavid du Colombier }
13197dd7cddfSDavid du Colombier }
13207dd7cddfSDavid du Colombier {
13217dd7cddfSDavid du Colombier fixed nx = E, ny = F;
13227dd7cddfSDavid du Colombier const fixed *optr = vs;
13237dd7cddfSDavid du Colombier byte op;
13247dd7cddfSDavid du Colombier
13257dd7cddfSDavid du Colombier if_debug7('p', "[p]curveto (%g,%g; %g,%g; %g,%g) side %d\n",
13267dd7cddfSDavid du Colombier fixed2float(A), fixed2float(B),
13277dd7cddfSDavid du Colombier fixed2float(C), fixed2float(D),
13287dd7cddfSDavid du Colombier fixed2float(E), fixed2float(F), side);
13297dd7cddfSDavid du Colombier E -= C, F -= D;
13307dd7cddfSDavid du Colombier C -= A, D -= B;
13317dd7cddfSDavid du Colombier A -= px, B -= py;
13327dd7cddfSDavid du Colombier if (*writer.dp >= cmd_opv_min_curveto &&
13337dd7cddfSDavid du Colombier *writer.dp <= cmd_opv_max_curveto &&
13347dd7cddfSDavid du Colombier ((prev.A == 0 &&
13357dd7cddfSDavid du Colombier A == prev.E && C == prev.C && E == prev.A &&
13367dd7cddfSDavid du Colombier B == -prev.F && D == -prev.D && F == -prev.B) ||
13377dd7cddfSDavid du Colombier (prev.A != 0 &&
13387dd7cddfSDavid du Colombier A == -prev.E && C == -prev.C && E == -prev.A &&
13397dd7cddfSDavid du Colombier B == prev.F && D == prev.D && F == prev.B))
13407dd7cddfSDavid du Colombier )
13417dd7cddfSDavid du Colombier op = cmd_opv_scurveto;
13427dd7cddfSDavid du Colombier else if (B == 0 && E == 0) {
13437dd7cddfSDavid du Colombier B = A, E = F, optr++, op = cmd_opv_hvcurveto;
13447dd7cddfSDavid du Colombier if ((B ^ D) >= 0) {
13457dd7cddfSDavid du Colombier if (C == D && E == B)
13467dd7cddfSDavid du Colombier op = cmd_opv_hqcurveto;
13477dd7cddfSDavid du Colombier } else if (C == -D && E == -B)
13487dd7cddfSDavid du Colombier C = D, op = cmd_opv_hqcurveto;
13497dd7cddfSDavid du Colombier } else if (A == 0 && F == 0) {
13507dd7cddfSDavid du Colombier optr++, op = cmd_opv_vhcurveto;
13517dd7cddfSDavid du Colombier if ((B ^ C) >= 0) {
13527dd7cddfSDavid du Colombier if (D == C && E == B)
13537dd7cddfSDavid du Colombier op = cmd_opv_vqcurveto;
13547dd7cddfSDavid du Colombier } else if (D == -C && E == -B)
13557dd7cddfSDavid du Colombier op = cmd_opv_vqcurveto;
13567dd7cddfSDavid du Colombier } else if (A == 0 && B == 0)
13577dd7cddfSDavid du Colombier optr += 2, op = cmd_opv_nrcurveto;
13587dd7cddfSDavid du Colombier else if (E == 0 && F == 0)
13597dd7cddfSDavid du Colombier op = cmd_opv_rncurveto;
13607dd7cddfSDavid du Colombier else
13617dd7cddfSDavid du Colombier op = cmd_opv_rrcurveto;
13627dd7cddfSDavid du Colombier memcpy(prev.vs, vs, sizeof(prev.vs));
13637dd7cddfSDavid du Colombier px = nx, py = ny;
13647dd7cddfSDavid du Colombier open = 1;
13657dd7cddfSDavid du Colombier code = cmd_put_segment(&writer, op, optr, notes);
13667dd7cddfSDavid du Colombier }
13677dd7cddfSDavid du Colombier }
13687dd7cddfSDavid du Colombier break;
13697dd7cddfSDavid du Colombier default:
13707dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
13717dd7cddfSDavid du Colombier }
13727dd7cddfSDavid du Colombier if (code < 0)
13737dd7cddfSDavid du Colombier return code;
13747dd7cddfSDavid du Colombier #undef A
13757dd7cddfSDavid du Colombier #undef B
13767dd7cddfSDavid du Colombier #undef C
13777dd7cddfSDavid du Colombier #undef D
13787dd7cddfSDavid du Colombier #undef E
13797dd7cddfSDavid du Colombier #undef F
13807dd7cddfSDavid du Colombier }
13817dd7cddfSDavid du Colombier }
1382