static void fz_dash_moveto(struct sctx *s, fz_point a, fz_linecap start_cap, fz_linecap end_cap) { s->toggle = 1; s->offset = 0; s->phase = s->dash_phase; while (s->phase >= s->dash_list[s->offset]) { s->toggle = !s->toggle; s->phase -= s->dash_list[s->offset]; s->offset ++; if (s->offset == s->dash_len) s->offset = 0; } s->cur = a; if (s->toggle) { fz_stroke_flush(s, s->cap, end_cap); s->cap = start_cap; fz_stroke_moveto(s, a); } }
static void fz_stroke_closepath(struct sctx *s) { if (s->sn == 2) { /* SumatraPDF: prevent rendering artifacts from line joins */ float dx = s->beg[0].x - s->seg[1].x, dy = s->beg[0].y - s->seg[1].y; fz_stroke_lineto(s, s->beg[0], 0); if (s->seg[1].x == s->beg[0].x && s->seg[1].y == s->beg[0].y) fz_add_line_join(s, s->seg[0], s->beg[0], s->beg[1], 0); else if (dx * dx + dy * dy < FLT_EPSILON) fz_stroke_flush(s, FZ_LINECAP_BUTT, FZ_LINECAP_BUTT); else fz_add_line_join(s, s->seg[1], s->beg[0], s->beg[1], 0); } else if (s->dot) { fz_add_line_dot(s, s->beg[0]); } s->seg[0] = s->beg[0]; s->bn = 1; s->sn = 1; s->dot = 0; s->from_bezier = 0; }
static void fz_dash_lineto(struct sctx *s, fz_point b, int dash_cap, int from_bezier) { float dx, dy; float total, used, ratio; fz_point a; fz_point m; a = s->cur; dx = b.x - a.x; dy = b.y - a.y; total = sqrtf(dx * dx + dy * dy); used = 0; while (total - used > s->dash_list[s->offset] - s->phase) { used += s->dash_list[s->offset] - s->phase; ratio = used / total; m.x = a.x + ratio * dx; m.y = a.y + ratio * dy; if (s->toggle) { fz_stroke_lineto(s, m, from_bezier); } else { fz_stroke_flush(s, s->cap, dash_cap); s->cap = dash_cap; fz_stroke_moveto(s, m); } s->toggle = !s->toggle; s->phase = 0; s->offset ++; if (s->offset == s->dash_len) s->offset = 0; } s->phase += total - used; s->cur = b; if (s->toggle) { fz_stroke_lineto(s, b, from_bezier); } }
void fz_flatten_dash_path(fz_gel *gel, fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm, float flatness, float linewidth) { struct sctx s; fz_point p0, p1, p2, p3, beg; float phase_len, max_expand; int i; s.gel = gel; s.ctm = ctm; s.flatness = flatness; s.linejoin = stroke->linejoin; s.linewidth = linewidth * 0.5f; s.miterlimit = stroke->miterlimit; s.sn = 0; s.bn = 0; s.dot = 0; s.dash_list = stroke->dash_list; s.dash_phase = stroke->dash_phase; s.dash_len = stroke->dash_len; s.toggle = 0; s.offset = 0; s.phase = 0; s.cap = stroke->start_cap; if (path->len > 0 && path->items[0].k != FZ_MOVETO) return; phase_len = 0; for (i = 0; i < stroke->dash_len; i++) phase_len += stroke->dash_list[i]; max_expand = fz_matrix_max_expansion(ctm); if (phase_len < 1.0f && phase_len * max_expand < 0.5f) { fz_flatten_stroke_path(gel, path, stroke, ctm, flatness, linewidth); return; } p0.x = p0.y = 0; i = 0; while (i < path->len) { switch (path->items[i++].k) { case FZ_MOVETO: p1.x = path->items[i++].v; p1.y = path->items[i++].v; fz_dash_moveto(&s, p1, stroke->start_cap, stroke->end_cap); beg = p0 = p1; break; case FZ_LINETO: p1.x = path->items[i++].v; p1.y = path->items[i++].v; fz_dash_lineto(&s, p1, stroke->dash_cap, 0); p0 = p1; break; case FZ_CURVETO: p1.x = path->items[i++].v; p1.y = path->items[i++].v; p2.x = path->items[i++].v; p2.y = path->items[i++].v; p3.x = path->items[i++].v; p3.y = path->items[i++].v; fz_dash_bezier(&s, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 0, stroke->dash_cap); p0 = p3; break; case FZ_CLOSE_PATH: fz_dash_lineto(&s, beg, stroke->dash_cap, 0); p0 = p1 = beg; break; } } fz_stroke_flush(&s, s.cap, stroke->end_cap); }
void fz_flatten_stroke_path(fz_gel *gel, fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm, float flatness, float linewidth) { struct sctx s; fz_point p0, p1, p2, p3; int i; s.gel = gel; s.ctm = ctm; s.flatness = flatness; s.linejoin = stroke->linejoin; s.linewidth = linewidth * 0.5f; /* hairlines use a different value from the path value */ s.miterlimit = stroke->miterlimit; s.sn = 0; s.bn = 0; s.dot = 0; s.dash_list = NULL; s.dash_phase = 0; s.dash_len = 0; s.toggle = 0; s.offset = 0; s.phase = 0; s.cap = stroke->start_cap; i = 0; if (path->len > 0 && path->items[0].k != FZ_MOVETO) return; p0.x = p0.y = 0; while (i < path->len) { switch (path->items[i++].k) { case FZ_MOVETO: p1.x = path->items[i++].v; p1.y = path->items[i++].v; fz_stroke_flush(&s, stroke->start_cap, stroke->end_cap); fz_stroke_moveto(&s, p1); p0 = p1; break; case FZ_LINETO: p1.x = path->items[i++].v; p1.y = path->items[i++].v; fz_stroke_lineto(&s, p1, 0); p0 = p1; break; case FZ_CURVETO: p1.x = path->items[i++].v; p1.y = path->items[i++].v; p2.x = path->items[i++].v; p2.y = path->items[i++].v; p3.x = path->items[i++].v; p3.y = path->items[i++].v; fz_stroke_bezier(&s, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 0); p0 = p3; break; case FZ_CLOSE_PATH: fz_stroke_closepath(&s); break; } } fz_stroke_flush(&s, stroke->start_cap, stroke->end_cap); }
void fz_flatten_dash_path(fz_gel *gel, fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm, float flatness, float linewidth) { struct sctx s; fz_point p0, p1, p2, p3, beg; float phase_len, max_expand; int i, k; fz_matrix inv; s.gel = gel; s.ctm = ctm; s.flatness = flatness; s.linejoin = stroke->linejoin; s.linewidth = linewidth * 0.5f; s.miterlimit = stroke->miterlimit; s.sn = 0; s.dot = 0; s.dash_list = stroke->dash_list; s.dash_phase = stroke->dash_phase; s.dash_len = stroke->dash_len; s.toggle = 0; s.offset = 0; s.phase = 0; s.cap = stroke->start_cap; if (path->cmd_len > 0 && path->cmds[0] != FZ_MOVETO) return; phase_len = 0; for (i = 0; i < stroke->dash_len; i++) phase_len += stroke->dash_list[i]; if (stroke->dash_len > 0 && phase_len == 0) return; fz_gel_scissor(gel, &s.rect); if (fz_try_invert_matrix(&inv, ctm)) return; fz_transform_rect(&s.rect, &inv); s.rect.x0 -= linewidth; s.rect.x1 += linewidth; s.rect.y0 -= linewidth; s.rect.y1 += linewidth; max_expand = fz_matrix_max_expansion(ctm); if (phase_len < 1.0f && phase_len * max_expand < 0.5f) { fz_flatten_stroke_path(gel, path, stroke, ctm, flatness, linewidth); return; } s.dash_total = phase_len; /* cf. http://git.ghostscript.com/?p=mupdf.git;a=commitdiff;h=fd54bf89f2adfd5545202a6df87076fb7269f62c */ s.dash_phase = fmodf(s.dash_phase, s.dash_total); p0.x = p0.y = 0; i = k = 0; while (i < path->cmd_len) { switch (path->cmds[i++]) { case FZ_MOVETO: p1.x = path->coords[k++]; p1.y = path->coords[k++]; fz_dash_moveto(&s, p1, stroke->start_cap, stroke->end_cap); beg = p0 = p1; break; case FZ_LINETO: p1.x = path->coords[k++]; p1.y = path->coords[k++]; fz_dash_lineto(&s, p1, stroke->dash_cap, 0); p0 = p1; break; case FZ_CURVETO: p1.x = path->coords[k++]; p1.y = path->coords[k++]; p2.x = path->coords[k++]; p2.y = path->coords[k++]; p3.x = path->coords[k++]; p3.y = path->coords[k++]; fz_dash_bezier(&s, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 0, stroke->dash_cap); p0 = p3; break; case FZ_CLOSE_PATH: fz_dash_lineto(&s, beg, stroke->dash_cap, 0); p0 = p1 = beg; break; } } fz_stroke_flush(&s, s.cap, stroke->end_cap); }
static void fz_dash_lineto(struct sctx *s, fz_point b, int dash_cap, int from_bezier) { float dx, dy, d; float total, used, ratio, tail; fz_point a; fz_point m; fz_point old_b; int n; a = s->cur; dx = b.x - a.x; dy = b.y - a.y; used = 0; tail = 0; total = sqrtf(dx * dx + dy * dy); /* If a is off screen, bring it onto the screen. First * horizontally... */ if ((d = s->rect.x0 - a.x) > 0) { if (b.x < s->rect.x0) { /* Entirely off screen */ tail = total; old_b = b; goto adjust_for_tail; } a.x = s->rect.x0; /* d > 0, dx > 0 */ goto a_moved_horizontally; } else if (d < 0 && (d = (s->rect.x1 - a.x)) < 0) { if (b.x > s->rect.x1) { /* Entirely off screen */ tail = total; old_b = b; goto adjust_for_tail; } a.x = s->rect.x1; /* d < 0, dx < 0 */ a_moved_horizontally: /* d and dx have the same sign */ a.y += dy * d/dx; used = total * d/dx; total -= used; dx = b.x - a.x; dy = b.y - a.y; } /* Then vertically... */ if ((d = s->rect.y0 - a.y) > 0) { if (b.y < s->rect.y0) { /* Entirely off screen */ tail = total; old_b = b; goto adjust_for_tail; } a.y = s->rect.y0; /* d > 0, dy > 0 */ goto a_moved_vertically; } else if (d < 0 && (d = (s->rect.y1 - a.y)) < 0) { if (b.y > s->rect.y1) { /* Entirely off screen */ tail = total; old_b = b; goto adjust_for_tail; } a.y = s->rect.y1; /* d < 0, dy < 0 */ a_moved_vertically: /* d and dy have the same sign */ a.x += dx * d/dy; d = total * d/dy; total -= d; used += d; dx = b.x - a.x; dy = b.y - a.y; } if (used != 0.0f) { /* Update the position in the dash array */ if (s->toggle) { fz_stroke_lineto(s, a, from_bezier); } else { fz_stroke_flush(s, s->cap, dash_cap); s->cap = dash_cap; fz_stroke_moveto(s, a); } used += s->phase; n = used/s->dash_total; used -= n*s->dash_total; if (n & s->dash_len & 1) s->toggle = !s->toggle; while (used >= s->dash_list[s->offset]) { used -= s->dash_list[s->offset]; s->offset++; if (s->offset == s->dash_len) s->offset = 0; s->toggle = !s->toggle; } if (s->toggle) { fz_stroke_lineto(s, a, from_bezier); } else { fz_stroke_flush(s, s->cap, dash_cap); s->cap = dash_cap; fz_stroke_moveto(s, a); } s->phase = used; used = 0; } /* Now if b.x is off screen, bring it back */ if ((d = b.x - s->rect.x0) < 0) { old_b = b; b.x = s->rect.x0; /* d < 0, dx < 0 */ goto b_moved_horizontally; } else if (d > 0 && (d = (b.x - s->rect.x1)) > 0) { old_b = b; b.x = s->rect.x1; /* d > 0, dx > 0 */ b_moved_horizontally: /* d and dx have the same sign */ b.y -= dy * d/dx; tail = total * d/dx; total -= tail; dx = b.x - a.x; dy = b.y - a.y; } /* Then vertically... */ if ((d = b.y - s->rect.y0) < 0) { old_b = b; b.y = s->rect.y0; /* d < 0, dy < 0 */ goto b_moved_vertically; } else if (d > 0 && (d = (b.y - s->rect.y1)) > 0) { float t; old_b = b; b.y = s->rect.y1; /* d > 0, dy > 0 */ b_moved_vertically: /* d and dy have the same sign */ b.x -= dx * d/dy; t = total * d/dy; tail += t; total -= t; dx = b.x - a.x; dy = b.y - a.y; } while (total - used > s->dash_list[s->offset] - s->phase) { used += s->dash_list[s->offset] - s->phase; ratio = used / total; m.x = a.x + ratio * dx; m.y = a.y + ratio * dy; if (s->toggle) { fz_stroke_lineto(s, m, from_bezier); } else { fz_stroke_flush(s, s->cap, dash_cap); s->cap = dash_cap; fz_stroke_moveto(s, m); } s->toggle = !s->toggle; s->phase = 0; s->offset ++; if (s->offset == s->dash_len) s->offset = 0; } s->phase += total - used; if (tail == 0.0f) { s->cur = b; if (s->toggle) { fz_stroke_lineto(s, b, from_bezier); } } else { adjust_for_tail: s->cur = old_b; /* Update the position in the dash array */ if (s->toggle) { fz_stroke_lineto(s, old_b, from_bezier); } else { fz_stroke_flush(s, s->cap, dash_cap); s->cap = dash_cap; fz_stroke_moveto(s, old_b); } tail += s->phase; n = tail/s->dash_total; tail -= n*s->dash_total; if (n & s->dash_len & 1) s->toggle = !s->toggle; while (tail > s->dash_list[s->offset]) { tail -= s->dash_list[s->offset]; s->offset++; if (s->offset == s->dash_len) s->offset = 0; s->toggle = !s->toggle; } if (s->toggle) { fz_stroke_lineto(s, old_b, from_bezier); } else { fz_stroke_flush(s, s->cap, dash_cap); s->cap = dash_cap; fz_stroke_moveto(s, old_b); } s->phase = tail; } }