/* Start enumerating a path */ int gs_path_enum_copy_init(gs_path_enum * penum, const gs_state * pgs, bool copy) { gs_memory_t *mem = pgs->memory; if (copy) { gx_path *copied_path = gx_path_alloc(mem, "gs_path_enum_init"); int code; if (copied_path == 0) return_error(gs_error_VMerror); code = gx_path_copy(pgs->path, copied_path); if (code < 0) { gx_path_free(copied_path, "gs_path_enum_init"); return code; } gx_path_enum_init(penum, copied_path); penum->copied_path = copied_path; } else { gx_path_enum_init(penum, pgs->path); } penum->memory = mem; gs_currentmatrix(pgs, &penum->mat); return 0; }
/* Compute the path length for user path purposes. */ static int path_length_for_upath(const gx_path *ppath) { gs_path_enum penum; int op, size = 0; gs_fixed_point pts[3]; gx_path_enum_init(&penum, ppath); while ((op = gx_path_enum_next(&penum, pts)) != 0) { switch (op) { case gs_pe_moveto: case gs_pe_lineto: size += 3; continue; case gs_pe_curveto: size += 7; continue; case gs_pe_closepath: size += 1; continue; default: return_error(e_unregistered); } } return size; }
static int path_to_hinter(t1_hinter *h, gx_path *path) { int code; gs_path_enum penum; gs_fixed_point pts[3]; gs_fixed_point p = {0, 0}; /* initialize to avoid a warning */ bool first = true; int op; code = gx_path_enum_init(&penum, path); if (code < 0) return code; while ((op = gx_path_enum_next(&penum, pts)) != 0) { switch (op) { case gs_pe_moveto: if (first) { first = false; p = pts[0]; code = t1_hinter__rmoveto(h, p.x, p.y); } else code = t1_hinter__rmoveto(h, pts[0].x - p.x, pts[0].y - p.y); break; case gs_pe_lineto: code = t1_hinter__rlineto(h, pts[0].x - p.x, pts[0].y - p.y); break; case gs_pe_curveto: code = t1_hinter__rcurveto(h, pts[0].x - p.x, pts[0].y - p.y, pts[1].x - pts[0].x, pts[1].y - pts[0].y, pts[2].x - pts[1].x, pts[2].y - pts[1].y); pts[0] = pts[2]; break; case gs_pe_closepath: code = t1_hinter__closepath(h); break; default: return_error(gs_error_unregistered); } if (code < 0) return code; p = pts[0]; } return 0; }
int gdev_vector_dopath(gx_device_vector *vdev, const gx_path * ppath, gx_path_type_t type, const gs_matrix *pmat) { bool do_close = (type & (gx_path_type_stroke | gx_path_type_always_close)) != 0; gs_fixed_rect rbox; gx_path_rectangular_type rtype = gx_path_is_rectangular(ppath, &rbox); gs_path_enum cenum; gdev_vector_dopath_state_t state; gs_fixed_point line_start, line_end; bool incomplete_line = false; bool need_moveto = false; int code; gdev_vector_dopath_init(&state, vdev, type, pmat); /* * if the path type is stroke, we only recognize closed * rectangles; otherwise, we recognize all rectangles. * Note that for stroking with a transformation, we can't use dorect, * which requires (untransformed) device coordinates. */ if (rtype != prt_none && (!(type & gx_path_type_stroke) || rtype == prt_closed) && (pmat == 0 || is_xxyy(pmat) || is_xyyx(pmat)) && (state.scale_mat.xx == 1.0 && state.scale_mat.yy == 1.0 && is_xxyy(&state.scale_mat) && is_fzero2(state.scale_mat.tx, state.scale_mat.ty)) ) { gs_point p, q; gs_point_transform_inverse((double)rbox.p.x, (double)rbox.p.y, &state.scale_mat, &p); gs_point_transform_inverse((double)rbox.q.x, (double)rbox.q.y, &state.scale_mat, &q); code = vdev_proc(vdev, dorect)(vdev, (fixed)p.x, (fixed)p.y, (fixed)q.x, (fixed)q.y, type); if (code >= 0) return code; /* If the dorect proc failed, use a general path. */ } code = vdev_proc(vdev, beginpath)(vdev, type); if (code < 0) return code; gx_path_enum_init(&cenum, ppath); for (;;) { gs_fixed_point vs[3]; int pe_op = gx_path_enum_next(&cenum, vs); 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]; incomplete_line = true; continue; } /* * Merge collinear horizontal or vertical line segments * going in the same direction. */ if (vs[0].x == line_end.x) { if (vs[0].x == line_start.x && coord_between(line_start.y, line_end.y, vs[0].y) ) { line_end.y = vs[0].y; continue; } } else if (vs[0].y == line_end.y) { if (vs[0].y == line_start.y && coord_between(line_start.x, line_end.x, vs[0].x) ) { line_end.x = vs[0].x; continue; } } } if (incomplete_line) { if (need_moveto) { /* see gs_pe_moveto case */ code = gdev_vector_dopath_segment(&state, gs_pe_moveto, &line_start); if (code < 0) return code; need_moveto = false; } code = gdev_vector_dopath_segment(&state, gs_pe_lineto, &line_end); if (code < 0) return code; line_start = line_end; incomplete_line = false; goto opt; } } switch (pe_op) { case 0: /* done */ done: code = vdev_proc(vdev, endpath)(vdev, type); return (code < 0 ? code : 0); case gs_pe_curveto: if (need_moveto) { /* see gs_pe_moveto case */ code = gdev_vector_dopath_segment(&state, gs_pe_moveto, &line_start); if (code < 0) return code; need_moveto = false; } line_start = vs[2]; goto draw; case gs_pe_moveto: /* * A bug in Acrobat Reader 4 causes it to draw a single pixel * for a fill with an isolated moveto. If we're doing a fill * without a stroke, defer emitting a moveto until we know that * the subpath has more elements. */ line_start = vs[0]; if (!(type & gx_path_type_stroke) && (type & gx_path_type_fill)) { need_moveto = true; continue; } 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); if (code < 0) return code; need_moveto = false; } line_start = vs[0]; goto draw; case gs_pe_closepath: if (need_moveto) { /* see gs_pe_moveto case */ need_moveto = false; continue; } if (!do_close) { pe_op = gx_path_enum_next(&cenum, vs); if (pe_op == 0) goto done; code = gdev_vector_dopath_segment(&state, gs_pe_closepath, vs); if (code < 0) return code; goto sw; } /* falls through */ draw: code = gdev_vector_dopath_segment(&state, pe_op, vs); if (code < 0) return code; } incomplete_line = false; /* only needed if optimizing */ } }