/* but no client currently relies on this. */ bool gx_path_enum_backup(gs_path_enum * penum) { const segment *pseg = penum->pseg; if (pseg != 0) { if ((pseg = pseg->prev) == 0) return false; penum->pseg = pseg; return true; } /* We're at the end of the path. Check to see whether */ /* we need to back up over a trailing moveto. */ { const gx_path *ppath = penum->path; if (path_last_is_moveto(ppath) && penum->moveto_done) { /* Back up over the trailing moveto. */ penum->moveto_done = false; return true; } { const subpath *psub = ppath->current_subpath; if (psub == 0) /* empty path */ return false; /* Back up to the last segment of the last subpath. */ penum->pseg = psub->last; return true; } } }
static int gz_path_close_subpath_notes(gx_path * ppath, segment_notes notes) { subpath *psub; line_close_segment *lp; int code; if (!path_subpath_open(ppath)) return 0; if (path_last_is_moveto(ppath)) { /* The last operation was a moveto: create a subpath. */ code = gx_path_new_subpath(ppath); if (code < 0) return code; } path_alloc_segment(lp, line_close_segment, &st_line_close, s_line_close, notes, "gx_path_close_subpath"); path_alloc_link(lp); path_set_point(lp, psub->pt.x, psub->pt.y); lp->sub = psub; psub->is_closed = 1; path_update_closepath(ppath); trace_segment("[P]", (segment *) lp); return 0; }
int gs_upathbbox(gs_state * pgs, gs_rect * pbox, bool include_moveto) { gs_fixed_rect fbox; /* box in device coordinates */ gs_rect dbox; int code = gx_path_bbox_set(pgs->path, &fbox); if (code < 0) return code; /* If the path ends with a moveto and include_moveto is true, */ /* include the moveto in the bounding box. */ if (path_last_is_moveto(pgs->path) && include_moveto) { gs_fixed_point pt; code = gx_path_current_point_inline(pgs->path, &pt); if (code < 0) return code; if (pt.x < fbox.p.x) fbox.p.x = pt.x; if (pt.y < fbox.p.y) fbox.p.y = pt.y; if (pt.x > fbox.q.x) fbox.q.x = pt.x; if (pt.y > fbox.q.y) fbox.q.y = pt.y; } /* Transform the result back to user coordinates. */ dbox.p.x = fixed2float(fbox.p.x); dbox.p.y = fixed2float(fbox.p.y); dbox.q.x = fixed2float(fbox.q.x); dbox.q.y = fixed2float(fbox.q.y); return gs_bbox_transform_inverse(&dbox, &ctm_only(pgs), pbox); }
/* otherwise, return the element type. */ int gx_path_enum_next(gs_path_enum * penum, gs_fixed_point ppts[3]) { const segment *pseg = penum->pseg; if (pseg == 0) { /* We've enumerated all the segments, but there might be */ /* a trailing moveto. */ const gx_path *ppath = penum->path; if (path_last_is_moveto(ppath) && !penum->moveto_done) { /* Handle a trailing moveto */ penum->moveto_done = true; penum->notes = sn_none; ppts[0] = ppath->position; return gs_pe_moveto; } return 0; } penum->pseg = pseg->next; penum->notes = pseg->notes; switch (pseg->type) { case s_start: ppts[0] = pseg->pt; return gs_pe_moveto; case s_line: ppts[0] = pseg->pt; return gs_pe_lineto; case s_line_close: ppts[0] = pseg->pt; return gs_pe_closepath; case s_curve: #define pcseg ((const curve_segment *)pseg) ppts[0] = pcseg->p1; ppts[1] = pcseg->p2; ppts[2] = pseg->pt; return gs_pe_curveto; #undef pcseg default: lprintf1("bad type %x in gx_path_enum_next!\n", pseg->type); return_error(gs_error_Fatal); } }
/* * Reverse a path. We know ppath != ppath_old. * NOTE: in releases 5.01 and earlier, the implicit line added by closepath * became the first segment of the reversed path. Starting in release * 5.02, the code follows the Adobe implementation (and LanguageLevel 3 * specification), in which this line becomes the *last* segment of the * reversed path. This can produce some quite unintuitive results. * * The order of the subpaths is unspecified in the PLRM, but the CPSI * reverses the subpaths, and the CET (11-05 p6, test 3) tests for it. */ int gx_path_copy_reversed(const gx_path * ppath_old, gx_path * ppath) { const subpath *psub = ppath_old->current_subpath; #ifdef DEBUG if (gs_debug_c('P')) gx_dump_path(ppath_old, "before reversepath"); #endif nsp: if (psub) { const segment *prev = psub->last; const segment *pseg; segment_notes notes = (prev == (const segment *)psub ? sn_none : psub->next->notes); segment_notes prev_notes; int code; if (!psub->is_closed) { code = gx_path_add_point(ppath, prev->pt.x, prev->pt.y); if (code < 0) return code; } /* * The do ... while structure of this loop is artificial, * designed solely to keep compilers from complaining about * 'statement not reached' or 'end-of-loop code not reached'. * The normal exit from this loop is the goto statement in * the s_start arm of the switch. */ do { pseg = prev; prev_notes = notes; prev = pseg->prev; notes = pseg->notes; prev_notes = (prev_notes & sn_not_first) | (notes & ~sn_not_first); switch (pseg->type) { case s_start: /* Finished subpath */ if (psub->is_closed) { code = gx_path_close_subpath_notes(ppath, prev_notes); if (code < 0) return code; } do { psub = (const subpath *)psub->prev; } while (psub && psub->type != s_start); goto nsp; case s_curve: { const curve_segment *pc = (const curve_segment *)pseg; code = gx_path_add_curve_notes(ppath, pc->p2.x, pc->p2.y, pc->p1.x, pc->p1.y, prev->pt.x, prev->pt.y, prev_notes); break; } case s_line: code = gx_path_add_line_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, prev->pt.y); break; default: /* not possible */ return_error(gs_error_Fatal); } } while (code >= 0); return code; /* only reached if code < 0 */ } #undef sn_not_end /* * In the Adobe implementations, reversepath discards a trailing * moveto unless the path consists only of a moveto. We reproduce * this behavior here, even though we consider it a bug. */ if (ppath_old->first_subpath == 0 && path_last_is_moveto(ppath_old) ) { int code = gx_path_add_point(ppath, ppath_old->position.x, ppath_old->position.y); if (code < 0) return code; } #ifdef DEBUG if (gs_debug_c('P')) gx_dump_path(ppath, "after reversepath"); #endif return 0; }