diff options
Diffstat (limited to 'base/gxclpath.c')
-rw-r--r-- | base/gxclpath.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/base/gxclpath.c b/base/gxclpath.c index c202178c..83cb44e0 100644 --- a/base/gxclpath.c +++ b/base/gxclpath.c @@ -927,6 +927,28 @@ clist_fill_path(gx_device * dev, const gs_gstate * pgs, gx_path * ppath, return 0; } +int clist_lock_pattern(gx_device * pdev, gs_gstate * pgs, gs_id pattern, int lock) +{ + gx_device_clist_writer * const cdev = + &((gx_device_clist *)pdev)->writer; + byte *dp; + int code; + + /* We need to both lock now, and ensure that we lock on reading this back. */ + code = gx_pattern_cache_entry_set_lock(pgs, pattern, lock); + if (code < 0) + return code; + + code = set_cmd_put_all_op(&dp, cdev, cmd_opv_lock_pattern, + 1 + 1 + sizeof(pattern)); + + if (code < 0) + return code; + dp[1] = lock; + memcpy(dp+2, &pattern, sizeof(pattern)); + return 0; +} + int clist_fill_stroke_path(gx_device * pdev, const gs_gstate * pgs, gx_path * ppath, @@ -1563,6 +1585,47 @@ cmd_put_segment(cmd_segment_writer * psw, byte op, #define cmd_put_rlineto(psw, operands, notes)\ cmd_put_segment(psw, cmd_opv_rlineto, operands, notes) + +/* Bug 693235 shows a problem with a 'large' stroke, that + * extends from almost the minimum extent permissible + * to almost the positive extent permissible. When we band + * that, and play it back, we subtract the y offset of the band + * from it, and that causes a very negative number to tip over + * to being a very positive number. + * + * To avoid this, we spot 'far out' entries in the path, and + * reduce them to being 'less far out'. + * + * We pick 'far out' as being outside the central 1/4 of our + * 2d plane. This is far larger than is ever going to be used + * by a real device (famous last words!). + * + * We reduce the lines by moving to 1/4 of the way along them. + * + * If we only ever actually want to render the central 1/16 of + * the plane (which is still far more generous than we'd expect), + * the reduced lines should be suitably small not to overflow, + * and yet not be reduced so much that the reduction is ever visible. + * + * In practice this gives us a 4 million x 4 million maximum + * resolution. + */ + +static int +far_out(gs_fixed_point out) +{ + return (out.y >= max_fixed/2 || out.y <= -(max_fixed/2) || out.x >= max_fixed/2 || out.x <= -(max_fixed/2)); +} + +static void +reduce_line(fixed *m0, fixed *m1, fixed x0, fixed y0, fixed x1, fixed y1) +{ + /* We want to find m0, m1, 1/4 of the way from x0, y0 to x1, y1. */ + /* Sacrifice 2 bits of accuracy to avoid overflow. */ + *m0 = (x0/4) + 3*(x1/4); + *m1 = (y0/4) + 3*(y1/4); +} + /* * Write a path. We go to a lot of trouble to omit segments that are * entirely outside the band. @@ -1716,6 +1779,20 @@ cmd_put_path(gx_device_clist_writer * cldev, gx_clist_state * pcls, } /* If we skipped any segments, put out a moveto/lineto. */ if (side && ((open < 0) || (px != out.x || py != out.y || first_point()))) { + if (far_out(out)) { + /* out is far enough out that we have to worry about wrapping on playback. Reduce the extent. */ + if (open >= 0) { + fixed mid[2]; + fixed m0, m1; + reduce_line(&m0, &m1, out.x, out.y, px, py); + mid[0] = m0 - px, mid[1] = m1 - py; + code = cmd_put_rlineto(&writer, mid, out_notes); + if (code < 0) + return code; + px = m0, py = m1; + } + reduce_line(&out.x, &out.y, out.x, out.y, A, B); + } C = out.x - px, D = out.y - py; if (open < 0) { first = out; @@ -1758,6 +1835,20 @@ cmd_put_path(gx_device_clist_writer * cldev, gx_clist_state * pcls, } /* If we skipped any segments, put out a moveto/lineto. */ if (side && ((open < 0) || (px != out.x || py != out.y || first_point()))) { + if (far_out(out)) { + /* out is far enough out that we have to worry about wrapping on playback. Reduce the extent. */ + if (open >= 0) { + fixed mid[2]; + fixed m0, m1; + reduce_line(&m0, &m1, out.x, out.y, px, py); + mid[0] = m0 - px, mid[1] = m1 - py; + code = cmd_put_rlineto(&writer, mid, out_notes); + if (code < 0) + return code; + px = m0, py = m1; + } + reduce_line(&out.x, &out.y, out.x, out.y, A, B); + } C = out.x - px, D = out.y - py; if (open < 0) { first = out; @@ -1805,6 +1896,20 @@ cmd_put_path(gx_device_clist_writer * cldev, gx_clist_state * pcls, /* we skipped any segments at the beginning of the path. */ close:if (side != start_side) { /* If we skipped any segments, put out a moveto/lineto. */ if (side && (px != out.x || py != out.y || first_point())) { + if (far_out(out)) { + /* out is far enough out that we have to worry about wrapping on playback. Reduce the extent. */ + if (open >= 0) { + fixed mid[2]; + fixed m0, m1; + reduce_line(&m0, &m1, out.x, out.y, px, py); + mid[0] = m0 - px, mid[1] = m1 - py; + code = cmd_put_rlineto(&writer, mid, out_notes); + if (code < 0) + return code; + px = m0, py = m1; + } + reduce_line(&out.x, &out.y, out.x, out.y, A, B); + } C = out.x - px, D = out.y - py; code = cmd_put_rlineto(&writer, &C, out_notes); if (code < 0) |