static void fz_add_line_stroke(struct sctx *s, fz_point a, fz_point b) { float dx = b.x - a.x; float dy = b.y - a.y; float scale = s->linewidth / sqrtf(dx * dx + dy * dy); float dlx = dy * scale; float dly = -dx * scale; fz_add_line(s, a.x - dlx, a.y - dly, b.x - dlx, b.y - dly); fz_add_line(s, b.x + dlx, b.y + dly, a.x + dlx, a.y + dly); }
static void fz_add_line_cap(struct sctx *s, fz_point a, fz_point b, fz_linecap linecap) { float flatness = s->flatness; float linewidth = s->linewidth; float dx = b.x - a.x; float dy = b.y - a.y; float scale = linewidth / sqrtf(dx * dx + dy * dy); float dlx = dy * scale; float dly = -dx * scale; if (linecap == FZ_LINECAP_BUTT) fz_add_line(s, b.x - dlx, b.y - dly, b.x + dlx, b.y + dly); if (linecap == FZ_LINECAP_ROUND) { int i; int n = ceilf((float)M_PI / (2.0f * (float)M_SQRT2 * sqrtf(flatness / linewidth))); float ox = b.x - dlx; float oy = b.y - dly; for (i = 1; i < n; i++) { float theta = (float)M_PI * i / n; float cth = cosf(theta); float sth = sinf(theta); float nx = b.x - dlx * cth - dly * sth; float ny = b.y - dly * cth + dlx * sth; fz_add_line(s, ox, oy, nx, ny); ox = nx; oy = ny; } fz_add_line(s, ox, oy, b.x + dlx, b.y + dly); } if (linecap == FZ_LINECAP_SQUARE) { fz_add_line(s, b.x - dlx, b.y - dly, b.x - dlx - dly, b.y - dly + dlx); fz_add_line(s, b.x - dlx - dly, b.y - dly + dlx, b.x + dlx - dly, b.y + dly + dlx); fz_add_line(s, b.x + dlx - dly, b.y + dly + dlx, b.x + dlx, b.y + dly); } if (linecap == FZ_LINECAP_TRIANGLE) { float mx = -dly; float my = dlx; fz_add_line(s, b.x - dlx, b.y - dly, b.x + mx, b.y + my); fz_add_line(s, b.x + mx, b.y + my, b.x + dlx, b.y + dly); } }
static void fz_add_arc(struct sctx *s, float xc, float yc, float x0, float y0, float x1, float y1) { float th0, th1, r; float theta; float ox, oy, nx, ny; int n, i; r = fabsf(s->linewidth); theta = 2 * (float)M_SQRT2 * sqrtf(s->flatness / r); th0 = atan2f(y0, x0); th1 = atan2f(y1, x1); if (r > 0) { if (th0 < th1) th0 += (float)M_PI * 2; n = ceilf((th0 - th1) / theta); } else { if (th1 < th0) th1 += (float)M_PI * 2; n = ceilf((th1 - th0) / theta); } ox = x0; oy = y0; for (i = 1; i < n; i++) { theta = th0 + (th1 - th0) * i / n; nx = cosf(theta) * r; ny = sinf(theta) * r; fz_add_line(s, xc + ox, yc + oy, xc + nx, yc + ny); ox = nx; oy = ny; } fz_add_line(s, xc + ox, yc + oy, xc + x1, yc + y1); }
static void fz_add_line_dot(struct sctx *s, fz_point a) { float flatness = s->flatness; float linewidth = s->linewidth; int n = ceilf((float)M_PI / ((float)M_SQRT2 * sqrtf(flatness / linewidth))); float ox = a.x - linewidth; float oy = a.y; int i; for (i = 1; i < n; i++) { float theta = (float)M_PI * 2 * i / n; float cth = cosf(theta); float sth = sinf(theta); float nx = a.x - cth * linewidth; float ny = a.y + sth * linewidth; fz_add_line(s, ox, oy, nx, ny); ox = nx; oy = ny; } fz_add_line(s, ox, oy, a.x - linewidth, a.y); }
static void fz_add_line_join(struct sctx *s, fz_point a, fz_point b, fz_point c, int join_under) { float miterlimit = s->miterlimit; float linewidth = s->linewidth; fz_linejoin linejoin = s->linejoin; float dx0, dy0; float dx1, dy1; float dlx0, dly0; float dlx1, dly1; float dmx, dmy; float dmr2; float scale; float cross; float len0, len1; dx0 = b.x - a.x; dy0 = b.y - a.y; dx1 = c.x - b.x; dy1 = c.y - b.y; cross = dx1 * dy0 - dx0 * dy1; /* Ensure that cross >= 0 */ if (cross < 0) { float tmp; tmp = dx1; dx1 = -dx0; dx0 = -tmp; tmp = dy1; dy1 = -dy0; dy0 = -tmp; cross = -cross; } len0 = dx0 * dx0 + dy0 * dy0; if (len0 < FLT_EPSILON) linejoin = FZ_LINEJOIN_BEVEL; len1 = dx1 * dx1 + dy1 * dy1; if (len1 < FLT_EPSILON) linejoin = FZ_LINEJOIN_BEVEL; scale = linewidth / sqrtf(len0); dlx0 = dy0 * scale; dly0 = -dx0 * scale; scale = linewidth / sqrtf(len1); dlx1 = dy1 * scale; dly1 = -dx1 * scale; dmx = (dlx0 + dlx1) * 0.5f; dmy = (dly0 + dly1) * 0.5f; dmr2 = dmx * dmx + dmy * dmy; if (cross * cross < FLT_EPSILON && dx0 * dx1 + dy0 * dy1 >= 0) linejoin = FZ_LINEJOIN_BEVEL; if (join_under) { fz_add_line(s, b.x + dlx1, b.y + dly1, b.x + dlx0, b.y + dly0); } else { fz_add_line(s, b.x + dlx1, b.y + dly1, b.x, b.y); fz_add_line(s, b.x, b.y, b.x + dlx0, b.y + dly0); } /* XPS miter joins are clipped at miterlength, rather than simply * being converted to bevelled joins. */ if (linejoin == FZ_LINEJOIN_MITER_XPS) { if (cross == 0) linejoin = FZ_LINEJOIN_BEVEL; else if (dmr2 * miterlimit * miterlimit >= linewidth * linewidth) linejoin = FZ_LINEJOIN_MITER; else { float k, t0x, t0y, t1x, t1y; scale = linewidth * linewidth / dmr2; dmx *= scale; dmy *= scale; k = (scale - linewidth * miterlimit / sqrtf(dmr2)) / (scale - 1); t0x = b.x - dmx + k * (dmx - dlx0); t0y = b.y - dmy + k * (dmy - dly0); t1x = b.x - dmx + k * (dmx - dlx1); t1y = b.y - dmy + k * (dmy - dly1); fz_add_line(s, b.x - dlx0, b.y - dly0, t0x, t0y); fz_add_line(s, t0x, t0y, t1x, t1y); fz_add_line(s, t1x, t1y, b.x - dlx1, b.y - dly1); } } else if (linejoin == FZ_LINEJOIN_MITER) if (dmr2 * miterlimit * miterlimit < linewidth * linewidth) linejoin = FZ_LINEJOIN_BEVEL; if (linejoin == FZ_LINEJOIN_MITER) { scale = linewidth * linewidth / dmr2; dmx *= scale; dmy *= scale; fz_add_line(s, b.x - dlx0, b.y - dly0, b.x - dmx, b.y - dmy); fz_add_line(s, b.x - dmx, b.y - dmy, b.x - dlx1, b.y - dly1); } if (linejoin == FZ_LINEJOIN_BEVEL) { fz_add_line(s, b.x - dlx0, b.y - dly0, b.x - dlx1, b.y - dly1); } if (linejoin == FZ_LINEJOIN_ROUND) { fz_add_arc(s, b.x, b.y, -dlx0, -dly0, -dlx1, -dly1); } }
static void fz_add_line_join(struct sctx *s, fz_point a, fz_point b, fz_point c) { float miterlimit = s->miterlimit; float linewidth = s->linewidth; int linejoin = s->linejoin; float dx0, dy0; float dx1, dy1; float dlx0, dly0; float dlx1, dly1; float dmx, dmy; float dmr2; float scale; float cross; dx0 = b.x - a.x; dy0 = b.y - a.y; dx1 = c.x - b.x; dy1 = c.y - b.y; if (dx0 * dx0 + dy0 * dy0 < FLT_EPSILON) linejoin = BEVEL; if (dx1 * dx1 + dy1 * dy1 < FLT_EPSILON) linejoin = BEVEL; scale = linewidth / sqrtf(dx0 * dx0 + dy0 * dy0); dlx0 = dy0 * scale; dly0 = -dx0 * scale; scale = linewidth / sqrtf(dx1 * dx1 + dy1 * dy1); dlx1 = dy1 * scale; dly1 = -dx1 * scale; cross = dx1 * dy0 - dx0 * dy1; dmx = (dlx0 + dlx1) * 0.5f; dmy = (dly0 + dly1) * 0.5f; dmr2 = dmx * dmx + dmy * dmy; if (cross * cross < FLT_EPSILON && dx0 * dx1 + dy0 * dy1 >= 0) linejoin = BEVEL; if (linejoin == MITER) if (dmr2 * miterlimit * miterlimit < linewidth * linewidth) linejoin = BEVEL; if (linejoin == BEVEL) { fz_add_line(s, b.x - dlx0, b.y - dly0, b.x - dlx1, b.y - dly1); fz_add_line(s, b.x + dlx1, b.y + dly1, b.x + dlx0, b.y + dly0); } if (linejoin == MITER) { scale = linewidth * linewidth / dmr2; dmx *= scale; dmy *= scale; if (cross < 0) { fz_add_line(s, b.x - dlx0, b.y - dly0, b.x - dlx1, b.y - dly1); fz_add_line(s, b.x + dlx1, b.y + dly1, b.x + dmx, b.y + dmy); fz_add_line(s, b.x + dmx, b.y + dmy, b.x + dlx0, b.y + dly0); } else { fz_add_line(s, b.x + dlx1, b.y + dly1, b.x + dlx0, b.y + dly0); fz_add_line(s, b.x - dlx0, b.y - dly0, b.x - dmx, b.y - dmy); fz_add_line(s, b.x - dmx, b.y - dmy, b.x - dlx1, b.y - dly1); } } if (linejoin == ROUND) { if (cross < 0) { fz_add_line(s, b.x - dlx0, b.y - dly0, b.x - dlx1, b.y - dly1); fz_add_arc(s, b.x, b.y, dlx1, dly1, dlx0, dly0); } else { fz_add_line(s, b.x + dlx1, b.y + dly1, b.x + dlx0, b.y + dly0); fz_add_arc(s, b.x, b.y, -dlx0, -dly0, -dlx1, -dly1); } } }