static void gx_ttfExport__LineTo(ttfExport *self, FloatPoint *p) { gx_ttfExport *e = (gx_ttfExport *)self; if (!e->error) e->error = gx_path_add_line_notes(e->path, float2fixed(p->x), float2fixed(p->y), sn_none); }
/* * 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; }
static int subpath_expand_dashes(const subpath * psub, gx_path * ppath, const gs_imager_state * pis, const gx_dash_params * dash) { const float *pattern = dash->pattern; int count, index; bool ink_on; double elt_length; fixed x0 = psub->pt.x, y0 = psub->pt.y; fixed x, y; const segment *pseg; int wrap = (dash->init_ink_on && psub->is_closed ? -1 : 0); int drawing = wrap; segment_notes notes = ~sn_not_first; const gx_line_params *pgs_lp = gs_currentlineparams_inline(pis); bool zero_length = true; int code; if ((code = gx_path_add_point(ppath, x0, y0)) < 0) return code; /* * To do the right thing at the beginning of a closed path, we have * to skip any initial line, and then redo it at the end of the * path. Drawing = -1 while skipping, 0 while drawing normally, and * 1 on the second round. Note that drawing != 0 implies ink_on. */ top:count = dash->pattern_size; ink_on = dash->init_ink_on; index = dash->init_index; elt_length = dash->init_dist_left; x = x0, y = y0; pseg = (const segment *)psub; while ((pseg = pseg->next) != 0 && pseg->type != s_start) { fixed sx = pseg->pt.x, sy = pseg->pt.y; fixed udx = sx - x, udy = sy - y; double length, dx, dy; double scale = 1; double left; if (!(udx | udy)) { /* degenerate */ if (pgs_lp->dot_length == 0 && pgs_lp->cap != gs_cap_round) { /* From PLRM, stroke operator : If a subpath is degenerate (consists of a single-point closed path or of two or more points at the same coordinates), stroke paints it only if round line caps have been specified */ if (zero_length || pseg->type != s_line_close) continue; } dx = 0, dy = 0, length = 0; } else { gs_point d; zero_length = false; dx = udx, dy = udy; /* scaled as fixed */ gs_imager_idtransform(pis, dx, dy, &d); length = hypot(d.x, d.y) * (1.0 / fixed_1); if (gs_imager_currentdashadapt(pis)) { double reps = length / dash->pattern_length; scale = reps / ceil(reps); /* Ensure we're starting at the start of a */ /* repetition. (This shouldn't be necessary, */ /* but it is.) */ count = dash->pattern_size; ink_on = dash->init_ink_on; index = dash->init_index; elt_length = dash->init_dist_left * scale; } } left = length; while (left > elt_length) { /* We are using up the line segment. */ double fraction = elt_length / length; fixed fx = (fixed) (dx * fraction); fixed fy = (fixed) (dy * fraction); fixed nx = x + fx; fixed ny = y + fy; if (ink_on) { if (drawing >= 0) { if (left >= elt_length && any_abs(fx) + any_abs(fy) < fixed_half) code = gx_path_add_dash_notes(ppath, nx, ny, udx, udy, notes & pseg->notes); else code = gx_path_add_line_notes(ppath, nx, ny, notes & pseg->notes); } notes |= sn_not_first; } else { if (drawing > 0) /* done */ return 0; code = gx_path_add_point(ppath, nx, ny); notes &= ~sn_not_first; drawing = 0; } if (code < 0) return code; left -= elt_length; ink_on = !ink_on; if (++index == count) index = 0; elt_length = pattern[index] * scale; x = nx, y = ny; } elt_length -= left; /* Handle the last dash of a segment. */ on:if (ink_on) { if (drawing >= 0) { if (pseg->type == s_line_close && drawing > 0) code = gx_path_close_subpath_notes(ppath, notes & pseg->notes); else if (any_abs(sx - x) + any_abs(sy - y) < fixed_half) code = gx_path_add_dash_notes(ppath, sx, sy, udx, udy, notes & pseg->notes); else code = gx_path_add_line_notes(ppath, sx, sy, notes & pseg->notes); notes |= sn_not_first; } } else { 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)) { /* * Ink is off, but we're within epsilon of the end * of the dash element. * "Stretch" a little so we get a dot. * Also if the next dash pattern is zero length, * use the last segment orientation. */ double elt_length1; if (code < 0) return code; if (++index == count) index = 0; elt_length1 = pattern[index] * scale; if (pseg->next == 0 || pseg->next->type == s_start) { elt_length = elt_length1; left = 0; ink_on = true; goto on; } /* Looking ahead one dash pattern element. If it is zero length, apply to the current segment (at its end). */ if (elt_length1 == 0) { left = 0; code = gx_path_add_dash_notes(ppath, sx, sy, udx, udy, notes & pseg->notes); if (++index == count) index = 0; elt_length = pattern[index] * scale; ink_on = false; } else if (--index == 0) { /* Revert lookahead. */ index = count - 1; } } if (drawing > 0) /* done */ return code; drawing = 0; } if (code < 0) return code; x = sx, y = sy; } /* Check for wraparound. */ if (wrap && drawing <= 0) { /* We skipped some initial lines. */ /* Go back and do them now. */ drawing = 1; goto top; } return 0; }