summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-02-27 03:11:02 +0000
committerChris Liddell <chris.liddell@artifex.com>2012-03-15 11:54:24 +0000
commit23401e532f394b0fedf41ef97e2673d8a6f35b39 (patch)
tree15d9008d2e66206e34d16c6d2473a2a52731221f
parent835bbe29fb0b995e377c010966a80713272d78ba (diff)
Support HPGL style path handling. (Work in progress)
HPGL handles paths slightly differently to the postscript imaging model. When a path is filled, successive moveto's are treated as linetos. (i.e. the 'place we close the path to' is left at the first moveto, and the area remains fillable). Stroking is unaffected however. To model this in Ghostscript we add a new path segment type 's_gap'. The filling code treats this as a lineto. The stroking code is updated to not stroke such edges (and not to break the subpath at this point). We add a new parameter to the imager state (hpgl_fill_mode), new accessor functions (gs_sethpglfillmode, gs_currenthpglfillmode), and new postscript operators (.sethpglfillmode and .currenthpglfillmode). If hpgl fill mode is set to a non-zero value, then path construction treats movetos in an open subpath as gaptos. Still to do: * Double check the output from this code matches HPGL. * Update the clist code to send hpgl fill mode changes. * Update PDF write to spot such paths and to convert them as appropriate when writing out.
-rw-r--r--gs/base/gdevpdfd.c1
-rw-r--r--gs/base/gdevtrac.c4
-rw-r--r--gs/base/gdevvec.c3
-rw-r--r--gs/base/gspath.c19
-rw-r--r--gs/base/gspath1.c1
-rw-r--r--gs/base/gspenum.h1
-rw-r--r--gs/base/gsstate.c14
-rw-r--r--gs/base/gsstate.h2
-rw-r--r--gs/base/gxclpath.c1
-rw-r--r--gs/base/gxcpath.c4
-rw-r--r--gs/base/gxistate.h3
-rw-r--r--gs/base/gxline.h2
-rw-r--r--gs/base/gxpath.c37
-rw-r--r--gs/base/gxpath.h1
-rw-r--r--gs/base/gxpath2.c15
-rw-r--r--gs/base/gxpcopy.c46
-rw-r--r--gs/base/gxpdash.c13
-rw-r--r--gs/base/gxstroke.c18
-rw-r--r--gs/base/gxttfb.c1
-rw-r--r--gs/base/gzpath.h4
-rw-r--r--gs/psi/zgstate.c16
21 files changed, 183 insertions, 23 deletions
diff --git a/gs/base/gdevpdfd.c b/gs/base/gdevpdfd.c
index b5ad3199a..0f058515d 100644
--- a/gs/base/gdevpdfd.c
+++ b/gs/base/gdevpdfd.c
@@ -260,6 +260,7 @@ pdf_is_same_clip_path(gx_device_pdf * pdev, const gx_clip_path * pcpath)
return 0;
case gs_pe_moveto:
case gs_pe_lineto:
+ case gs_pe_gapto:
if (vs0[0].x != vs1[0].x || vs0[0].y != vs1[0].y)
return 0;
}
diff --git a/gs/base/gdevtrac.c b/gs/base/gdevtrac.c
index 535cebc01..be1492f01 100644
--- a/gs/base/gdevtrac.c
+++ b/gs/base/gdevtrac.c
@@ -100,6 +100,10 @@ trace_path(const gx_path *path)
dprintf2(" %g %g lineto\n", fixed2float(pts[0].x),
fixed2float(pts[0].y));
continue;
+ case gs_pe_gapto:
+ dprintf2(" %g %g gapto\n", fixed2float(pts[0].x),
+ fixed2float(pts[0].y));
+ continue;
case gs_pe_curveto:
dprintf6(" %g %g %g %g %g %g curveto\n", fixed2float(pts[0].x),
fixed2float(pts[0].y), fixed2float(pts[1].x),
diff --git a/gs/base/gdevvec.c b/gs/base/gdevvec.c
index b4a6ef4b3..ecff2d230 100644
--- a/gs/base/gdevvec.c
+++ b/gs/base/gdevvec.c
@@ -101,6 +101,7 @@ gdev_vector_dopath(gx_device_vector *vdev, const gx_path * ppath,
sw:
if (type & gx_path_type_optimize) {
opt:
+ /* RJW: We fail to optimize gaptos */
if (pe_op == gs_pe_lineto) {
if (!incomplete_line) {
line_end = vs[0];
@@ -173,6 +174,7 @@ gdev_vector_dopath(gx_device_vector *vdev, const gx_path * ppath,
}
goto draw;
case gs_pe_lineto:
+ case gs_pe_gapto:
if (need_moveto) { /* see gs_pe_moveto case */
code = gdev_vector_dopath_segment(&state, gs_pe_moveto,
&line_start);
@@ -642,6 +644,7 @@ gdev_vector_dopath_segment(gdev_vector_dopath_state_t *state, int pe_op,
state->prev = vp[0];
break;
case gs_pe_lineto:
+ case gs_pe_gapto: /* FIXME */
code = gs_point_transform_inverse(fixed2float(vs[0].x),
fixed2float(vs[0].y), pmat, &vp[0]);
if (code < 0)
diff --git a/gs/base/gspath.c b/gs/base/gspath.c
index 4964b2a08..dbdd7be53 100644
--- a/gs/base/gspath.c
+++ b/gs/base/gspath.c
@@ -154,12 +154,21 @@ gs_moveto_aux(gs_imager_state *pis, gx_path *ppath, floatp x, floatp y)
code = clamp_point_aux(pis->clamp_coordinates, &pt, x, y);
if (code < 0)
return code;
- code = gx_path_add_point(ppath, pt.x, pt.y);
- if (code < 0)
- return code;
- ppath->start_flags = ppath->state_flags;
+ if (path_subpath_open(ppath) && pis->hpgl_fill_mode)
+ {
+ code = gx_path_add_gap_notes(ppath, pt.x, pt.y, 0);
+ if (code < 0)
+ return code;
+ }
+ else
+ {
+ code = gx_path_add_point(ppath, pt.x, pt.y);
+ if (code < 0)
+ return code;
+ ppath->start_flags = ppath->state_flags;
+ pis->subpath_start = pis->current_point;
+ }
gx_setcurrentpoint(pis, x, y);
- pis->subpath_start = pis->current_point;
pis->current_point_valid = true;
return 0;
}
diff --git a/gs/base/gspath1.c b/gs/base/gspath1.c
index 4f4d760ae..f886460f8 100644
--- a/gs/base/gspath1.c
+++ b/gs/base/gspath1.c
@@ -641,6 +641,7 @@ gs_path_enum_next(gs_path_enum * penum, gs_point ppts[3])
/* falls through */
case gs_pe_moveto:
case gs_pe_lineto:
+ case gs_pe_gapto:
if ((code = gs_point_transform_inverse(
fixed2float(fpts[0].x),
fixed2float(fpts[0].y),
diff --git a/gs/base/gspenum.h b/gs/base/gspenum.h
index 920a72d92..5cda5033d 100644
--- a/gs/base/gspenum.h
+++ b/gs/base/gspenum.h
@@ -22,6 +22,7 @@
#define gs_pe_lineto 2
#define gs_pe_curveto 3
#define gs_pe_closepath 4
+#define gs_pe_gapto 5
/* Define an abstract type for the path enumerator. */
typedef struct gs_path_enum_s gs_path_enum;
diff --git a/gs/base/gsstate.c b/gs/base/gsstate.c
index 470ca8eea..d279acecd 100644
--- a/gs/base/gsstate.c
+++ b/gs/base/gsstate.c
@@ -839,6 +839,20 @@ gs_currenttextrenderingmode(const gs_state * pgs)
return pgs->text_rendering_mode;
}
+/* sethpglfillmode */
+void
+gs_sethpglfillmode(gs_state * pgs, int fill)
+{
+ pgs->hpgl_fill_mode = fill;
+}
+
+/* currenthpglfillmode */
+int
+gs_currenthpglfillmode(const gs_state * pgs)
+{
+ return pgs->hpgl_fill_mode;
+}
+
/* ------ Internal routines ------ */
/* Free the privately allocated parts of a gstate. */
diff --git a/gs/base/gsstate.h b/gs/base/gsstate.h
index 5b6bea5a0..7fa8ceea6 100644
--- a/gs/base/gsstate.h
+++ b/gs/base/gsstate.h
@@ -90,5 +90,7 @@ void gs_settextrenderingmode(gs_state * pgs, uint trm);
uint gs_currenttextrenderingmode(const gs_state * pgs);
#include "gscpm.h"
gs_in_cache_device_t gs_incachedevice(const gs_state *);
+void gs_sethpglfillmode(gs_state *, int);
+int gs_currenthpglfillmode(const gs_state *);
#endif /* gsstate_INCLUDED */
diff --git a/gs/base/gxclpath.c b/gs/base/gxclpath.c
index 01fa187ef..df250cd94 100644
--- a/gs/base/gxclpath.c
+++ b/gs/base/gxclpath.c
@@ -1340,6 +1340,7 @@ cmd_put_path(gx_device_clist_writer * cldev, gx_clist_state * pcls,
fixed2float(px), fixed2float(py));
break;
case gs_pe_lineto:
+ case gs_pe_gapto:
{
int next_side = which_side(B);
segment_notes notes =
diff --git a/gs/base/gxcpath.c b/gs/base/gxcpath.c
index d0ada3762..05bbcb004 100644
--- a/gs/base/gxcpath.c
+++ b/gs/base/gxcpath.c
@@ -421,6 +421,10 @@ gx_cpath_to_path_synthesize(const gx_clip_path * pcpath, gx_path * ppath)
code = gx_path_add_line_notes(ppath, pts[0].x, pts[0].y,
gx_cpath_enum_notes(&cenum));
break;
+ case gs_pe_gapto:
+ code = gx_path_add_gap_notes(ppath, pts[0].x, pts[0].y,
+ gx_cpath_enum_notes(&cenum));
+ break;
case gs_pe_curveto:
code = gx_path_add_curve_notes(ppath, pts[0].x, pts[0].y,
pts[1].x, pts[1].y,
diff --git a/gs/base/gxistate.h b/gs/base/gxistate.h
index e1ac8a1e2..9923ae83b 100644
--- a/gs/base/gxistate.h
+++ b/gs/base/gxistate.h
@@ -235,6 +235,7 @@ typedef struct gs_xstate_trans_flags {
gs_memory_t *memory;\
void *client_data;\
gx_line_params line_params;\
+ bool hpgl_fill_mode;\
gs_matrix_fixed ctm;\
bool current_point_valid;\
gs_point current_point;\
@@ -294,7 +295,7 @@ struct gs_imager_state_s {
/* Initialization for gs_imager_state */
#define gs_imager_state_initial(scale, is_gstate)\
- is_gstate, 0, 0, { gx_line_params_initial },\
+ is_gstate, 0, 0, { gx_line_params_initial }, 0,\
{ (float)(scale), 0.0, 0.0, (float)(-(scale)), 0.0, 0.0 },\
false, {0, 0}, {0, 0}, false, \
lop_default, gx_max_color_value, BLEND_MODE_Compatible,\
diff --git a/gs/base/gxline.h b/gs/base/gxline.h
index 36072b4ef..851878f29 100644
--- a/gs/base/gxline.h
+++ b/gs/base/gxline.h
@@ -72,6 +72,6 @@ int gx_set_dot_length(gx_line_params *, floatp, bool);
#define gx_line_params_initial\
0.0, gs_cap_butt, gs_cap_butt, gs_cap_butt, gs_join_miter, -1,\
10.0, (float)0.20305866, 0.0, 0/*false*/,\
- { identity_matrix_body }, { gx_dash_params_initial }
+ { identity_matrix_body }, { gx_dash_params_initial }
#endif /* gxline_INCLUDED */
diff --git a/gs/base/gxpath.c b/gs/base/gxpath.c
index b4ef51468..f7c5a853a 100644
--- a/gs/base/gxpath.c
+++ b/gs/base/gxpath.c
@@ -66,6 +66,7 @@ static rc_free_proc(rc_free_path_segments_local);
static int
gz_path_add_point(gx_path *, fixed, fixed),
gz_path_add_line_notes(gx_path *, fixed, fixed, segment_notes),
+ gz_path_add_gap_notes(gx_path *, fixed, fixed, segment_notes),
gz_path_add_curve_notes(gx_path *, fixed, fixed, fixed, fixed, fixed, fixed, segment_notes),
gz_path_close_subpath_notes(gx_path *, segment_notes);
static byte gz_path_state_flags(gx_path *ppath, byte flags);
@@ -73,6 +74,7 @@ static byte gz_path_state_flags(gx_path *ppath, byte flags);
static gx_path_procs default_path_procs = {
gz_path_add_point,
gz_path_add_line_notes,
+ gz_path_add_gap_notes,
gz_path_add_curve_notes,
gz_path_close_subpath_notes,
gz_path_state_flags
@@ -84,12 +86,14 @@ static gx_path_procs default_path_procs = {
static int
gz_path_bbox_add_point(gx_path *, fixed, fixed),
gz_path_bbox_add_line_notes(gx_path *, fixed, fixed, segment_notes),
+ gz_path_bbox_add_gap_notes(gx_path *, fixed, fixed, segment_notes),
gz_path_bbox_add_curve_notes(gx_path *, fixed, fixed, fixed, fixed, fixed, fixed, segment_notes),
gz_path_bbox_close_subpath_notes(gx_path *, segment_notes);
static gx_path_procs path_bbox_procs = {
gz_path_bbox_add_point,
gz_path_bbox_add_line_notes,
+ gz_path_bbox_add_gap_notes,
gz_path_bbox_add_curve_notes,
gz_path_bbox_close_subpath_notes,
gz_path_state_flags
@@ -588,6 +592,36 @@ gz_path_bbox_add_line_notes(gx_path * ppath, fixed x, fixed y, segment_notes not
gz_path_bbox_move(ppath, x, y);
return 0;
}
+/* Add a gap to the current path (lineto). */
+int
+gx_path_add_gap_notes(gx_path * ppath, fixed x, fixed y, segment_notes notes)
+{
+ return ppath->procs->add_gap(ppath, x, y, notes);
+}
+static int
+gz_path_add_gap_notes(gx_path * ppath, fixed x, fixed y, segment_notes notes)
+{
+ subpath *psub;
+ line_segment *lp;
+
+ if (ppath->bbox_set)
+ check_in_bbox(ppath, x, y);
+ path_open();
+ path_alloc_segment(lp, line_segment, &st_line, s_gap, notes,
+ "gx_path_add_gap");
+ path_alloc_link(lp);
+ path_set_point(lp, x, y);
+ path_update_draw(ppath);
+ trace_segment("[P]", (segment *) lp);
+ return 0;
+}
+static int
+gz_path_bbox_add_gap_notes(gx_path * ppath, fixed x, fixed y, segment_notes notes)
+{
+ gz_path_bbox_add(ppath, x, y);
+ gz_path_bbox_move(ppath, x, y);
+ return 0;
+}
/* Add multiple lines to the current path. */
/* Note that all lines have the same notes. */
@@ -1019,6 +1053,9 @@ gx_print_segment(const segment * pseg)
case s_line:
dprintf3(" %1.4f %1.4f lineto\t%% %s\n", px, py, out);
break;
+ case s_gap:
+ dprintf3(" %1.4f %1.4f gapto\t%% %s\n", px, py, out);
+ break;
case s_dash:{
const dash_segment *const pd = (const dash_segment *)pseg;
diff --git a/gs/base/gxpath.h b/gs/base/gxpath.h
index b8dedafd7..48b6328d8 100644
--- a/gs/base/gxpath.h
+++ b/gs/base/gxpath.h
@@ -141,6 +141,7 @@ int gx_path_new(gx_path *),
gx_path_add_point(gx_path *, fixed, fixed),
gx_path_add_relative_point(gx_path *, fixed, fixed),
gx_path_add_line_notes(gx_path *, fixed, fixed, segment_notes),
+ gx_path_add_gap_notes(gx_path *, fixed, fixed, segment_notes),
gx_path_add_dash_notes(gx_path * ppath, fixed x, fixed y, fixed dx, fixed dy, segment_notes notes),
gx_path_add_lines_notes(gx_path *, const gs_fixed_point *, int, segment_notes),
gx_path_add_rectangle(gx_path *, fixed, fixed, fixed, fixed),
diff --git a/gs/base/gxpath2.c b/gs/base/gxpath2.c
index 01caed385..653cc03cf 100644
--- a/gs/base/gxpath2.c
+++ b/gs/base/gxpath2.c
@@ -186,7 +186,7 @@ gx_subpath_is_rectangular(const subpath * pseg0, gs_fixed_rect * pbox,
) {
if ((pseg4 = pseg3->next) == 0 || pseg4->type == s_start)
type = prt_open; /* M, L, L, L */
- else if (pseg4->type != s_line) /* must be s_line_close */
+ else if (pseg4->type != s_line && pseg4->type != s_gap) /* must be s_line_close */
type = prt_closed; /* M, L, L, L, C */
else if (pseg4->pt.x != pseg0->pt.x ||
pseg4->pt.y != pseg0->pt.y
@@ -194,7 +194,7 @@ gx_subpath_is_rectangular(const subpath * pseg0, gs_fixed_rect * pbox,
return prt_none;
else if (pseg4->next == 0 || pseg4->next->type == s_start)
type = prt_fake_closed; /* Mo, L, L, L, Lo */
- else if (pseg4->next->type != s_line) /* must be s_line_close */
+ else if (pseg4->next->type != s_line && pseg4->next->type != s_gap) /* must be s_line_close */
type = prt_closed; /* Mo, L, L, L, Lo, C */
else
return prt_none;
@@ -405,6 +405,10 @@ gx_path_copy_reversed(const gx_path * ppath_old, gx_path * ppath)
code = gx_path_add_line_notes(ppath,
prev->pt.x, prev->pt.y, prev_notes);
break;
+ case s_gap:
+ code = gx_path_add_gap_notes(ppath,
+ prev->pt.x, prev->pt.y, prev_notes);
+ break;
case s_line_close:
/* Skip the closing line. */
code = gx_path_add_point(ppath, prev->pt.x,
@@ -504,6 +508,10 @@ gx_path_append_reversed(const gx_path * ppath_old, gx_path * ppath)
code = gx_path_add_line_notes(ppath,
prev->pt.x, prev->pt.y, prev_notes);
break;
+ case s_gap:
+ code = gx_path_add_gap_notes(ppath,
+ prev->pt.x, prev->pt.y, prev_notes);
+ break;
case s_line_close:
/* Skip the closing line. */
code = gx_path_add_point(ppath, prev->pt.x,
@@ -588,6 +596,9 @@ gx_path_enum_next(gs_path_enum * penum, gs_fixed_point ppts[3])
case s_line:
ppts[0] = pseg->pt;
return gs_pe_lineto;
+ case s_gap:
+ ppts[0] = pseg->pt;
+ return gs_pe_gapto;
case s_line_close:
ppts[0] = pseg->pt;
return gs_pe_closepath;
diff --git a/gs/base/gxpcopy.c b/gs/base/gxpcopy.c
index fa8dc7a79..06b46eed2 100644
--- a/gs/base/gxpcopy.c
+++ b/gs/base/gxpcopy.c
@@ -52,6 +52,32 @@ break_line_if_long(gx_path *ppath, const segment *pseg)
}
return 0;
}
+static inline int
+break_gap_if_long(gx_path *ppath, const segment *pseg)
+{
+ fixed x0 = ppath->position.x;
+ fixed y0 = ppath->position.y;
+
+ if (gx_check_fixed_diff_overflow(pseg->pt.x, x0) ||
+ gx_check_fixed_diff_overflow(pseg->pt.y, y0)) {
+ fixed x, y;
+
+ if (gx_check_fixed_sum_overflow(pseg->pt.x, x0))
+ x = (pseg->pt.x >> 1) + (x0 >> 1);
+ else
+ x = (pseg->pt.x + x0) >> 1;
+ if (gx_check_fixed_sum_overflow(pseg->pt.y, y0))
+ y = (pseg->pt.y >> 1) + (y0 >> 1);
+ else
+ y = (pseg->pt.y + y0) >> 1;
+ return gx_path_add_gap_notes(ppath, x, y, pseg->notes);
+ /* WARNING: Stringly speaking, the next half segment must get
+ the sn_not_first flag. We don't bother, because that flag
+ has no important meaning with colinear segments.
+ */
+ }
+ return 0;
+}
/* Copy a path, optionally flattening or monotonizing it. */
/* If the copy fails, free the new path. */
@@ -221,6 +247,14 @@ gx_path_copy_reducing(const gx_path *ppath_old, gx_path *ppath,
pseg->pt.x, pseg->pt.y, pseg->notes);
vd_lineto(pseg->pt.x, pseg->pt.y);
break;
+ case s_gap:
+ code = break_gap_if_long(ppath, pseg);
+ if (code < 0)
+ break;
+ code = gx_path_add_gap_notes(ppath,
+ pseg->pt.x, pseg->pt.y, pseg->notes);
+ vd_lineto(pseg->pt.x, pseg->pt.y);
+ break;
case s_dash:
{
const dash_segment *pd = (const dash_segment *)pseg;
@@ -348,6 +382,7 @@ gx_path__check_curves(const gx_path * ppath, gx_path_copy_options options, fixed
}
break;
case s_line:
+ case s_gap:
if (gx_check_fixed_diff_overflow(pseg->pt.x, pt0.x) ||
gx_check_fixed_diff_overflow(pseg->pt.y, pt0.y))
return false;
@@ -697,12 +732,15 @@ find_contacting_segments(const subpath *sp0, segment *sp0last,
Instead it either quickly finds something, or maybe not. */
for (s0 = sp0last, count0 = 0; count0 < search_limit && s0 != (segment *)sp0; s0 = s0->prev, count0++) {
s0s = s0->prev;
- if (s0->type == s_line && (s0s->pt.x == s0->pt.x ||
- (any_abs(s0s->pt.x - s0->pt.x) == 1 && any_abs(s0s->pt.y - s0->pt.y) > min_length))) {
+ if ((s0->type == s_line || s0->type == s_gap) &&
+ (s0s->pt.x == s0->pt.x ||
+ (any_abs(s0s->pt.x - s0->pt.x) == 1 &&
+ any_abs(s0s->pt.y - s0->pt.y) > min_length))) {
for (s1 = sp1last, count1 = 0; count1 < search_limit && s1 != (segment *)sp1; s1 = s1->prev, count1++) {
s1s = s1->prev;
- if (s1->type == s_line && (s1s->pt.x == s1->pt.x ||
- (any_abs(s1s->pt.x - s1->pt.x) == 1 && any_abs(s1s->pt.y - s1->pt.y) > min_length))) {
+ if ((s1->type == s_line || s1->type == s_gap) &&
+ (s1s->pt.x == s1->pt.x ||
+ (any_abs(s1s->pt.x - s1->pt.x) == 1 && any_abs(s1s->pt.y - s1->pt.y) > min_length))) {
if (s0s->pt.x == s1s->pt.x || s0->pt.x == s1->pt.x || s0->pt.x == s1s->pt.x || s0s->pt.x == s1->pt.x) {
if (s0s->pt.y < s0->pt.y && s1s->pt.y > s1->pt.y) {
fixed y0 = max(s0s->pt.y, s1->pt.y);
diff --git a/gs/base/gxpdash.c b/gs/base/gxpdash.c
index 9732990bb..6284f30c2 100644
--- a/gs/base/gxpdash.c
+++ b/gs/base/gxpdash.c
@@ -90,7 +90,7 @@ subpath_expand_dashes(const subpath * psub, gx_path * ppath,
elt_length = dash->init_dist_left;
x = x0, y = y0;
pseg = (const segment *)psub;
- while ((pseg = pseg->next) != 0 && pseg->type != s_start) {
+ while ((pseg = pseg->next) != 0 && pseg->type != s_start && pseg->type != s_gap) {
fixed sx = pseg->pt.x, sy = pseg->pt.y;
fixed udx = sx - x, udy = sy - y;
double length, dx, dy;
@@ -179,7 +179,7 @@ subpath_expand_dashes(const subpath * psub, gx_path * ppath,
const segment *pseg2 = pseg->next;
end_notes = 0;
- while (pseg2 != 0 && pseg2->type != s_start)
+ while (pseg2 != 0 && pseg2->type != s_start && pseg2->type != s_gap)
{
if ((pseg2->pt.x != sx) || (pseg2->pt.x != sy)) {
/* Non degenerate. We aren't the last one */
@@ -216,7 +216,10 @@ subpath_expand_dashes(const subpath * psub, gx_path * ppath,
code = gx_path_add_point(ppath, sx, sy);
notes &= ~sn_not_first;
if (elt_length < fixed2float(fixed_epsilon) &&
- (pseg->next == 0 || pseg->next->type == s_start || elt_length == 0)) {
+ (pseg->next == 0 ||
+ pseg->next->type == s_start ||
+ pseg->next->type == s_gap ||
+ elt_length == 0)) {
/*
* Ink is off, but we're within epsilon of the end
* of the dash element.
@@ -231,7 +234,9 @@ subpath_expand_dashes(const subpath * psub, gx_path * ppath,
if (++index == count)
index = 0;
elt_length1 = pattern[index] * scale;
- if (pseg->next == 0 || pseg->next->type == s_start) {
+ if (pseg->next == 0 ||
+ pseg->next->type == s_start ||
+ pseg->next->type == s_gap) {
elt_length = elt_length1;
left = 0;
ink_on = true;
diff --git a/gs/base/gxstroke.c b/gs/base/gxstroke.c
index 86d550227..b9d3eba0d 100644
--- a/gs/base/gxstroke.c
+++ b/gs/base/gxstroke.c
@@ -146,6 +146,7 @@ gx_stroke_path_expansion(const gs_imager_state * pis, const gx_path * ppath,
if (!(pseg->pt.x == prev.x || pseg->pt.y == prev.y))
goto not_exact;
break;
+ case s_gap:
default: /* other/unknown segment type */
goto not_exact;
}
@@ -706,6 +707,7 @@ gx_stroke_path_only_aux(gx_path * ppath, gx_path * to_path, gx_device * pdev,
/* We work with unscaled values, for speed. */
fixed sx, udx, sy, udy;
bool is_dash_segment = false;
+ bool is_gap_segment = pseg->type == s_gap;
d1:if (pseg->type != s_dash) {
sx = pseg->pt.x;
@@ -739,7 +741,8 @@ gx_stroke_path_only_aux(gx_path * ppath, gx_path * to_path, gx_device * pdev,
continue;
/* Check for a degenerate subpath. */
while ((pseg = pseg->next) != 0 &&
- pseg->type != s_start
+ pseg->type != s_start &&
+ pseg->type != s_gap
) {
if (is_dash_segment)
break;
@@ -793,7 +796,7 @@ gx_stroke_path_only_aux(gx_path * ppath, gx_path * to_path, gx_device * pdev,
udy = fixed_1;
}
}
- if (sx == x && sy == y && (pseg == NULL || pseg->type == s_start)) {
+ if (sx == x && sy == y && (pseg == NULL || pseg->type == s_start || pseg->type == s_gap)) {
double scale = device_dot_length /
hypot((double)udx, (double)udy);
fixed udx1, udy1;
@@ -892,14 +895,14 @@ gx_stroke_path_only_aux(gx_path * ppath, gx_path * to_path, gx_device * pdev,
if (index)
dev->sgr.stroke_stored = false;
adjust_stroke(dev, &pl, pis, false,
- (pseg->prev == 0 || pseg->prev->type == s_start) &&
- (pseg->next == 0 || pseg->next->type == s_start) &&
+ (pseg->prev == 0 || pseg->prev->type == s_start || pseg->prev->type == s_gap) &&
+ (pseg->next == 0 || pseg->next->type == s_start || pseg->next->type == s_gap) &&
(zero_length || !is_closed),
COMBINE_FLAGS(flags));
compute_caps(&pl);
}
}
- if (index++) {
+ if ((pseg->prev && pseg->prev->type != s_gap) && index++) {
gs_line_join join =
(pseg->notes & not_first ? curve_join : pgs_lp->join);
int first;
@@ -920,6 +923,8 @@ gx_stroke_path_only_aux(gx_path * ppath, gx_path * to_path, gx_device * pdev,
if (is_dash_segment) /* Never join to a dash segment */
lptr = NULL;
#endif
+ if (lptr && pseg->type == s_gap)
+ lptr = NULL;
ensure_closed = ((to_path == &stroke_path_body &&
lop_is_idempotent(pis->log_op)) ||
(lptr == NULL ? true : lptr->thin));
@@ -955,6 +960,9 @@ gx_stroke_path_only_aux(gx_path * ppath, gx_path * to_path, gx_device * pdev,
if (lptr && psub->type == s_dash)
lptr = NULL;
#endif
+ if (psub && psub->next && psub->next->type == s_gap)
+ lptr = NULL;
+
flags = (((notes & sn_not_first) ?
((flags & nf_all_from_arc) | nf_some_from_arc) : 0) |
((notes & sn_dash_head) ? nf_dash_head : 0) |
diff --git a/gs/base/gxttfb.c b/gs/base/gxttfb.c
index 418d20ca8..83d68d20f 100644
--- a/gs/base/gxttfb.c
+++ b/gs/base/gxttfb.c
@@ -562,6 +562,7 @@ path_to_hinter(t1_hinter *h, gx_path *path)
code = t1_hinter__rmoveto(h, pts[0].x - p.x, pts[0].y - p.y);
break;
case gs_pe_lineto:
+ case gs_pe_gapto:
code = t1_hinter__rlineto(h, pts[0].x - p.x, pts[0].y - p.y);
break;
case gs_pe_curveto:
diff --git a/gs/base/gzpath.h b/gs/base/gzpath.h
index 4d48f8bbd..181154b63 100644
--- a/gs/base/gzpath.h
+++ b/gs/base/gzpath.h
@@ -37,7 +37,8 @@ typedef enum {
s_line,
s_line_close,
s_curve,
- s_dash /* only for internal use of the stroking algorithm */
+ s_dash, /* only for internal use of the stroking algorithm */
+ s_gap
} segment_type;
/* Define the common structure for all segments. */
@@ -282,6 +283,7 @@ typedef enum {
typedef struct gx_path_procs_s {
int (*add_point)(gx_path *, fixed, fixed);
int (*add_line)(gx_path *, fixed, fixed, segment_notes);
+ int (*add_gap)(gx_path *, fixed, fixed, segment_notes);
int (*add_curve)(gx_path *, fixed, fixed, fixed, fixed, fixed, fixed, segment_notes);
int (*close_subpath)(gx_path *, segment_notes);
byte (*state_flags)(gx_path *, byte);
diff --git a/gs/psi/zgstate.c b/gs/psi/zgstate.c
index 1c06bfd24..f91301853 100644
--- a/gs/psi/zgstate.c
+++ b/gs/psi/zgstate.c
@@ -513,6 +513,20 @@ zcurrenttextrenderingmode(i_ctx_t *i_ctx_p)
return zcurrent_uint(i_ctx_p, gs_currenttextrenderingmode);
}
+/* <int> .sethpglfill - */
+static int
+zsethpglfillmode(i_ctx_t *i_ctx_p)
+{
+ return zset_uint(i_ctx_p, gs_sethpglfillmode);
+}
+
+/* - .currenttextrenderingmode <int> */
+static int
+zcurrenthpglfillmode(i_ctx_t *i_ctx_p)
+{
+ return zcurrent_uint(i_ctx_p, gs_currenthpglfillmode);
+}
+
/* ------ Initialization procedure ------ */
/* We need to split the table because of the 16-element limit. */
@@ -555,6 +569,8 @@ const op_def zgstate2_op_defs[] = {
const op_def zgstate3_op_defs[] = {
{"0.settextrenderingmode", zsettextrenderingmode},
{"0.currenttextrenderingmode", zcurrenttextrenderingmode},
+ {"0.sethpglfillmode", zsethpglfillmode},
+ {"0.currenthpglfillmode", zcurrenthpglfillmode},
op_def_end(0)
};