/* * Put a segment of an enumerated path on the output file. * pe_op is assumed to be valid and non-zero. */ int gdev_vector_dopath_segment(gdev_vector_dopath_state_t *state, int pe_op, gs_fixed_point vs[3]) { gx_device_vector *vdev = state->vdev; const gs_matrix *const pmat = &state->scale_mat; gs_point vp[3]; int code; switch (pe_op) { case gs_pe_moveto: code = gs_point_transform_inverse(fixed2float(vs[0].x), fixed2float(vs[0].y), pmat, &vp[0]); if (code < 0) return code; if (state->first) state->start = vp[0], state->first = false; code = vdev_proc(vdev, moveto) (vdev, 0/*unused*/, 0/*unused*/, vp[0].x, vp[0].y, state->type); 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) return code; code = vdev_proc(vdev, lineto) (vdev, state->prev.x, state->prev.y, vp[0].x, vp[0].y, state->type); state->prev = vp[0]; break; case gs_pe_curveto: code = gs_point_transform_inverse(fixed2float(vs[0].x), fixed2float(vs[0].y), pmat, &vp[0]); if (code < 0) return code; code = gs_point_transform_inverse(fixed2float(vs[1].x), fixed2float(vs[1].y), pmat, &vp[1]); if (code < 0) return code; gs_point_transform_inverse(fixed2float(vs[2].x), fixed2float(vs[2].y), pmat, &vp[2]); code = vdev_proc(vdev, curveto) (vdev, state->prev.x, state->prev.y, vp[0].x, vp[0].y, vp[1].x, vp[1].y, vp[2].x, vp[2].y, state->type); state->prev = vp[2]; break; case gs_pe_closepath: code = vdev_proc(vdev, closepath) (vdev, state->prev.x, state->prev.y, state->start.x, state->start.y, state->type); state->prev = state->start; break; default: /* can't happen */ return -1; } return code; }
/* otherwise, return the element type. */ int gs_path_enum_next(gs_path_enum * penum, gs_point ppts[3]) { gs_fixed_point fpts[3]; int pe_op = gx_path_enum_next(penum, fpts); int code; switch (pe_op) { case 0: /* all done */ case gs_pe_closepath: break; case gs_pe_curveto: if ((code = gs_point_transform_inverse( fixed2float(fpts[1].x), fixed2float(fpts[1].y), &penum->mat, &ppts[1])) < 0 || (code = gs_point_transform_inverse( fixed2float(fpts[2].x), fixed2float(fpts[2].y), &penum->mat, &ppts[2])) < 0) return code; /* falls through */ case gs_pe_moveto: case gs_pe_lineto: if ((code = gs_point_transform_inverse( fixed2float(fpts[0].x), fixed2float(fpts[0].y), &penum->mat, &ppts[0])) < 0) return code; default: /* error */ break; } return pe_op; }
int gs_itransform(gs_state * pgs, floatp x, floatp y, gs_point * pt) { /* If the matrix isn't skewed, we get more accurate results */ /* by using transform_inverse than by using the inverse matrix. */ if (!is_skewed(&pgs->ctm)) { return gs_point_transform_inverse(x, y, &ctm_only(pgs), pt); } else { ensure_inverse_valid(pgs); return gs_point_transform(x, y, &pgs->ctm_inverse, pt); } }
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 */ } }