summaryrefslogtreecommitdiff
path: root/source/fitz/draw-path.c
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2017-04-26 12:03:07 +0100
committerRobin Watts <Robin.Watts@artifex.com>2017-06-13 16:03:59 +0100
commitf1386c6778baded82a3b98215264c2613efc7fe7 (patch)
tree63c093d906d2a69f3d978577930484968eff7f3e /source/fitz/draw-path.c
parent1bcfc08545f4bed3d1197af1756f7465af11cf96 (diff)
downloadmupdf-f1386c6778baded82a3b98215264c2613efc7fe7.tar.xz
Introduce fz_rasterizer encapsulation
This is intended to be a way to allow us to implement compiletime/runtime selection of different scan converter implementations.
Diffstat (limited to 'source/fitz/draw-path.c')
-rw-r--r--source/fitz/draw-path.c491
1 files changed, 315 insertions, 176 deletions
diff --git a/source/fitz/draw-path.c b/source/fitz/draw-path.c
index fe140a56..2c3d8e37 100644
--- a/source/fitz/draw-path.c
+++ b/source/fitz/draw-path.c
@@ -7,18 +7,58 @@
#define MAX_DEPTH 8
+/*
+ When stroking/filling, we now label the edges as we emit them.
+
+ For filling, we walk the outline of the shape in order, so everything
+ is labelled as '0'.
+
+ For stroking, we walk up both sides of the stroke at once; the forward
+ side (0), and the reverse side (1). When we get to the top, either
+ both sides join back to where they started, or we cap them.
+
+ The start cap is labelled 2, the end cap is labelled 0.
+
+ These labels are ignored for edge based rasterization, but are required
+ for edgebuffer based rasterization.
+
+ Consider the following simplified ascii art diagram of a stroke from
+ left to right with 3 sections.
+
+ | 0 0 0
+ | +----->-----+----->-----+----->-----+
+ | | |
+ | ^ 2 A B C v 0
+ | | |
+ | +-----<-----+-----<-----+-----<-----+
+ | 1 1 1
+
+ Edge 0 is sent in order (the top edge of A then B then C, left to right
+ in the above diagram). Edge 1 is sent in reverse order (the bottom edge
+ of A then B then C, still left to right in the above diagram, even though
+ the sense of the line is right to left).
+
+ Finally any caps required are sent, 0 and 2.
+
+ It would be nicer if we could roll edge 2 into edge 1, but to do that
+ we'd need to know in advance if a stroke was closed or not, so we have
+ special case code in the edgebuffer based rasterizer to cope with this.
+*/
+
+
+
static void
-line(fz_context *ctx, fz_gel *gel, const fz_matrix *ctm, float x0, float y0, float x1, float y1)
+line(fz_context *ctx, fz_rasterizer *rast, const fz_matrix *ctm, float x0, float y0, float x1, float y1)
{
float tx0 = ctm->a * x0 + ctm->c * y0 + ctm->e;
float ty0 = ctm->b * x0 + ctm->d * y0 + ctm->f;
float tx1 = ctm->a * x1 + ctm->c * y1 + ctm->e;
float ty1 = ctm->b * x1 + ctm->d * y1 + ctm->f;
- fz_insert_gel(ctx, gel, tx0, ty0, tx1, ty1);
+ fz_insert_rasterizer(ctx, rast, tx0, ty0, tx1, ty1, 0);
}
static void
-bezier(fz_context *ctx, fz_gel *gel, const fz_matrix *ctm, float flatness,
+bezier(fz_context *ctx, fz_rasterizer *rast, const fz_matrix *ctm, float flatness,
float xa, float ya,
float xb, float yb,
float xc, float yc,
@@ -39,7 +79,7 @@ bezier(fz_context *ctx, fz_gel *gel, const fz_matrix *ctm, float flatness,
dmax = fz_max(dmax, fz_abs(yd - yc));
if (dmax < flatness || depth >= MAX_DEPTH)
{
- line(ctx, gel, ctm, xa, ya, xd, yd);
+ line(ctx, rast, ctm, xa, ya, xd, yd);
return;
}
@@ -67,12 +107,12 @@ bezier(fz_context *ctx, fz_gel *gel, const fz_matrix *ctm, float flatness,
xabcd *= 0.125f; yabcd *= 0.125f;
- bezier(ctx, gel, ctm, flatness, xa, ya, xab, yab, xabc, yabc, xabcd, yabcd, depth + 1);
- bezier(ctx, gel, ctm, flatness, xabcd, yabcd, xbcd, ybcd, xcd, ycd, xd, yd, depth + 1);
+ bezier(ctx, rast, ctm, flatness, xa, ya, xab, yab, xabc, yabc, xabcd, yabcd, depth + 1);
+ bezier(ctx, rast, ctm, flatness, xabcd, yabcd, xbcd, ybcd, xcd, ycd, xd, yd, depth + 1);
}
static void
-quad(fz_context *ctx, fz_gel *gel, const fz_matrix *ctm, float flatness,
+quad(fz_context *ctx, fz_rasterizer *rast, const fz_matrix *ctm, float flatness,
float xa, float ya,
float xb, float yb,
float xc, float yc, int depth)
@@ -89,7 +129,7 @@ quad(fz_context *ctx, fz_gel *gel, const fz_matrix *ctm, float flatness,
dmax = fz_max(dmax, fz_abs(yc - yb));
if (dmax < flatness || depth >= MAX_DEPTH)
{
- line(ctx, gel, ctm, xa, ya, xc, yc);
+ line(ctx, rast, ctm, xa, ya, xc, yc);
return;
}
@@ -106,13 +146,13 @@ quad(fz_context *ctx, fz_gel *gel, const fz_matrix *ctm, float flatness,
xabc *= 0.25f; yabc *= 0.25f;
- quad(ctx, gel, ctm, flatness, xa, ya, xab, yab, xabc, yabc, depth + 1);
- quad(ctx, gel, ctm, flatness, xabc, yabc, xbc, ybc, xc, yc, depth + 1);
+ quad(ctx, rast, ctm, flatness, xa, ya, xab, yab, xabc, yabc, depth + 1);
+ quad(ctx, rast, ctm, flatness, xabc, yabc, xbc, ybc, xc, yc, depth + 1);
}
typedef struct
{
- fz_gel *gel;
+ fz_rasterizer *rast;
const fz_matrix *ctm;
float flatness;
fz_point b;
@@ -127,9 +167,11 @@ flatten_moveto(fz_context *ctx, void *arg_, float x, float y)
/* implicit closepath before moveto */
if (arg->c.x != arg->b.x || arg->c.y != arg->b.y)
- line(ctx, arg->gel, arg->ctm, arg->c.x, arg->c.y, arg->b.x, arg->b.y);
+ line(ctx, arg->rast, arg->ctm, arg->c.x, arg->c.y, arg->b.x, arg->b.y);
arg->c.x = arg->b.x = x;
arg->c.y = arg->b.y = y;
+
+ fz_gap_rasterizer(ctx, arg->rast);
}
static void
@@ -137,7 +179,7 @@ flatten_lineto(fz_context *ctx, void *arg_, float x, float y)
{
flatten_arg *arg = (flatten_arg *)arg_;
- line(ctx, arg->gel, arg->ctm, arg->c.x, arg->c.y, x, y);
+ line(ctx, arg->rast, arg->ctm, arg->c.x, arg->c.y, x, y);
arg->c.x = x;
arg->c.y = y;
}
@@ -147,7 +189,7 @@ flatten_curveto(fz_context *ctx, void *arg_, float x1, float y1, float x2, float
{
flatten_arg *arg = (flatten_arg *)arg_;
- bezier(ctx, arg->gel, arg->ctm, arg->flatness, arg->c.x, arg->c.y, x1, y1, x2, y2, x3, y3, 0);
+ bezier(ctx, arg->rast, arg->ctm, arg->flatness, arg->c.x, arg->c.y, x1, y1, x2, y2, x3, y3, 0);
arg->c.x = x3;
arg->c.y = y3;
}
@@ -157,7 +199,7 @@ flatten_quadto(fz_context *ctx, void *arg_, float x1, float y1, float x2, float
{
flatten_arg *arg = (flatten_arg *)arg_;
- quad(ctx, arg->gel, arg->ctm, arg->flatness, arg->c.x, arg->c.y, x1, y1, x2, y2, 0);
+ quad(ctx, arg->rast, arg->ctm, arg->flatness, arg->c.x, arg->c.y, x1, y1, x2, y2, 0);
arg->c.x = x2;
arg->c.y = y2;
}
@@ -167,7 +209,7 @@ flatten_close(fz_context *ctx, void *arg_)
{
flatten_arg *arg = (flatten_arg *)arg_;
- line(ctx, arg->gel, arg->ctm, arg->c.x, arg->c.y, arg->b.x, arg->b.y);
+ line(ctx, arg->rast, arg->ctm, arg->c.x, arg->c.y, arg->b.x, arg->b.y);
arg->c.x = arg->b.x;
arg->c.y = arg->b.y;
}
@@ -179,31 +221,35 @@ flatten_rectto(fz_context *ctx, void *arg_, float x0, float y0, float x1, float
const fz_matrix *ctm = arg->ctm;
flatten_moveto(ctx, arg_, x0, y0);
- /* In the case where we have an axis aligned rectangle, do some
- * horrid antidropout stuff. */
- if (ctm->b == 0 && ctm->c == 0)
- {
- float tx0 = ctm->a * x0 + ctm->e;
- float ty0 = ctm->d * y0 + ctm->f;
- float tx1 = ctm->a * x1 + ctm->e;
- float ty1 = ctm->d * y1 + ctm->f;
- fz_insert_gel_rect(ctx, arg->gel, tx0, ty0, tx1, ty1);
- }
- else if (ctm->a == 0 && ctm->d == 0)
- {
- float tx0 = ctm->c * y0 + ctm->e;
- float ty0 = ctm->b * x0 + ctm->f;
- float tx1 = ctm->c * y1 + ctm->e;
- float ty1 = ctm->b * x1 + ctm->f;
- fz_insert_gel_rect(ctx, arg->gel, tx0, ty1, tx1, ty0);
- }
- else
+
+ if (fz_antidropout_rasterizer(ctx, arg->rast))
{
- flatten_lineto(ctx, arg_, x1, y0);
- flatten_lineto(ctx, arg_, x1, y1);
- flatten_lineto(ctx, arg_, x0, y1);
- flatten_close(ctx, arg_);
+ /* In the case where we have an axis aligned rectangle, do some
+ * horrid antidropout stuff. */
+ if (ctm->b == 0 && ctm->c == 0)
+ {
+ float tx0 = ctm->a * x0 + ctm->e;
+ float ty0 = ctm->d * y0 + ctm->f;
+ float tx1 = ctm->a * x1 + ctm->e;
+ float ty1 = ctm->d * y1 + ctm->f;
+ fz_insert_rasterizer_rect(ctx, arg->rast, tx0, ty0, tx1, ty1);
+ return;
+ }
+ else if (ctm->a == 0 && ctm->d == 0)
+ {
+ float tx0 = ctm->c * y0 + ctm->e;
+ float ty0 = ctm->b * x0 + ctm->f;
+ float tx1 = ctm->c * y1 + ctm->e;
+ float ty1 = ctm->b * x1 + ctm->f;
+ fz_insert_rasterizer_rect(ctx, arg->rast, tx0, ty1, tx1, ty0);
+ return;
+ }
}
+
+ flatten_lineto(ctx, arg_, x1, y0);
+ flatten_lineto(ctx, arg_, x1, y1);
+ flatten_lineto(ctx, arg_, x0, y1);
+ flatten_close(ctx, arg_);
}
static const fz_path_walker flatten_proc =
@@ -218,26 +264,50 @@ static const fz_path_walker flatten_proc =
flatten_rectto
};
-void
-fz_flatten_fill_path(fz_context *ctx, fz_gel *gel, const fz_path *path, const fz_matrix *ctm, float flatness, const fz_irect *scissor)
+int
+fz_flatten_fill_path(fz_context *ctx, fz_rasterizer *rast, const fz_path *path, const fz_matrix *ctm, float flatness, const fz_irect *scissor, fz_irect *bbox)
{
flatten_arg arg;
+ fz_irect local_bbox;
+
+ if (fz_reset_rasterizer(ctx, rast, scissor))
+ {
+ arg.rast = rast;
+ arg.ctm = ctm;
+ arg.flatness = flatness;
+ arg.b.x = arg.b.y = arg.c.x = arg.c.y = 0;
- fz_reset_gel(ctx, gel, scissor);
+ fz_walk_path(ctx, path, &flatten_proc, &arg);
+ if (arg.c.x != arg.b.x || arg.c.y != arg.b.y)
+ line(ctx, rast, ctm, arg.c.x, arg.c.y, arg.b.x, arg.b.y);
- arg.gel = gel;
+ fz_gap_rasterizer(ctx, rast);
+
+ fz_postindex_rasterizer(ctx, rast);
+ }
+
+ arg.rast = rast;
arg.ctm = ctm;
arg.flatness = flatness;
arg.b.x = arg.b.y = arg.c.x = arg.c.y = 0;
fz_walk_path(ctx, path, &flatten_proc, &arg);
if (arg.c.x != arg.b.x || arg.c.y != arg.b.y)
- line(ctx, gel, ctm, arg.c.x, arg.c.y, arg.b.x, arg.b.y);
+ line(ctx, rast, ctm, arg.c.x, arg.c.y, arg.b.x, arg.b.y);
+
+ fz_gap_rasterizer(ctx, rast);
+
+ if (!bbox)
+ return 0;
+
+ local_bbox = *scissor;
+ fz_bound_rasterizer(ctx, rast, bbox);
+ return fz_is_empty_irect(fz_intersect_irect(bbox, &local_bbox));
}
typedef struct sctx
{
- fz_gel *gel;
+ fz_rasterizer *rast;
const fz_matrix *ctm;
float flatness;
const fz_stroke_state *stroke;
@@ -265,72 +335,79 @@ typedef struct sctx
} sctx;
static void
-fz_add_line(fz_context *ctx, sctx *s, float x0, float y0, float x1, float y1)
+fz_add_line(fz_context *ctx, sctx *s, float x0, float y0, float x1, float y1, int rev)
{
float tx0 = s->ctm->a * x0 + s->ctm->c * y0 + s->ctm->e;
float ty0 = s->ctm->b * x0 + s->ctm->d * y0 + s->ctm->f;
float tx1 = s->ctm->a * x1 + s->ctm->c * y1 + s->ctm->e;
float ty1 = s->ctm->b * x1 + s->ctm->d * y1 + s->ctm->f;
- fz_insert_gel(ctx, s->gel, tx0, ty0, tx1, ty1);
+
+ fz_insert_rasterizer(ctx, s->rast, tx0, ty0, tx1, ty1, rev);
}
static void
fz_add_horiz_rect(fz_context *ctx, sctx *s, float x0, float y0, float x1, float y1)
{
- if (s->ctm->b == 0 && s->ctm->c == 0)
- {
- float tx0 = s->ctm->a * x0 + s->ctm->e;
- float ty0 = s->ctm->d * y0 + s->ctm->f;
- float tx1 = s->ctm->a * x1 + s->ctm->e;
- float ty1 = s->ctm->d * y1 + s->ctm->f;
- fz_insert_gel_rect(ctx, s->gel, tx1, ty1, tx0, ty0);
- }
- else if (s->ctm->a == 0 && s->ctm->d == 0)
- {
- float tx0 = s->ctm->c * y0 + s->ctm->e;
- float ty0 = s->ctm->b * x0 + s->ctm->f;
- float tx1 = s->ctm->c * y1 + s->ctm->e;
- float ty1 = s->ctm->b * x1 + s->ctm->f;
- fz_insert_gel_rect(ctx, s->gel, tx1, ty0, tx0, ty1);
- }
- else
- {
- fz_add_line(ctx, s, x0, y0, x1, y0);
- fz_add_line(ctx, s, x1, y1, x0, y1);
+ if (fz_antidropout_rasterizer(ctx, s->rast)) {
+ if (s->ctm->b == 0 && s->ctm->c == 0)
+ {
+ float tx0 = s->ctm->a * x0 + s->ctm->e;
+ float ty0 = s->ctm->d * y0 + s->ctm->f;
+ float tx1 = s->ctm->a * x1 + s->ctm->e;
+ float ty1 = s->ctm->d * y1 + s->ctm->f;
+ fz_insert_rasterizer_rect(ctx, s->rast, tx1, ty1, tx0, ty0);
+ return;
+ }
+ else if (s->ctm->a == 0 && s->ctm->d == 0)
+ {
+ float tx0 = s->ctm->c * y0 + s->ctm->e;
+ float ty0 = s->ctm->b * x0 + s->ctm->f;
+ float tx1 = s->ctm->c * y1 + s->ctm->e;
+ float ty1 = s->ctm->b * x1 + s->ctm->f;
+ fz_insert_rasterizer_rect(ctx, s->rast, tx1, ty0, tx0, ty1);
+ return;
+ }
}
+
+ fz_add_line(ctx, s, x0, y0, x1, y0, 0);
+ fz_add_line(ctx, s, x1, y1, x0, y1, 1);
}
static void
fz_add_vert_rect(fz_context *ctx, sctx *s, float x0, float y0, float x1, float y1)
{
- if (s->ctm->b == 0 && s->ctm->c == 0)
+ if (fz_antidropout_rasterizer(ctx, s->rast))
{
- float tx0 = s->ctm->a * x0 + s->ctm->e;
- float ty0 = s->ctm->d * y0 + s->ctm->f;
- float tx1 = s->ctm->a * x1 + s->ctm->e;
- float ty1 = s->ctm->d * y1 + s->ctm->f;
- fz_insert_gel_rect(ctx, s->gel, tx0, ty1, tx1, ty0);
- }
- else if (s->ctm->a == 0 && s->ctm->d == 0)
- {
- float tx0 = s->ctm->c * y0 + s->ctm->e;
- float ty0 = s->ctm->b * x0 + s->ctm->f;
- float tx1 = s->ctm->c * y1 + s->ctm->e;
- float ty1 = s->ctm->b * x1 + s->ctm->f;
- fz_insert_gel_rect(ctx, s->gel, tx0, ty0, tx1, ty1);
- }
- else
- {
- fz_add_line(ctx, s, x1, y0, x0, y0);
- fz_add_line(ctx, s, x0, y1, x1, y1);
+ if (s->ctm->b == 0 && s->ctm->c == 0)
+ {
+ float tx0 = s->ctm->a * x0 + s->ctm->e;
+ float ty0 = s->ctm->d * y0 + s->ctm->f;
+ float tx1 = s->ctm->a * x1 + s->ctm->e;
+ float ty1 = s->ctm->d * y1 + s->ctm->f;
+ fz_insert_rasterizer_rect(ctx, s->rast, tx0, ty1, tx1, ty0);
+ return;
+ }
+ else if (s->ctm->a == 0 && s->ctm->d == 0)
+ {
+ float tx0 = s->ctm->c * y0 + s->ctm->e;
+ float ty0 = s->ctm->b * x0 + s->ctm->f;
+ float tx1 = s->ctm->c * y1 + s->ctm->e;
+ float ty1 = s->ctm->b * x1 + s->ctm->f;
+ fz_insert_rasterizer_rect(ctx, s->rast, tx0, ty0, tx1, ty1);
+ return;
+ }
}
+
+ fz_add_line(ctx, s, x1, y0, x0, y0, 0);
+ fz_add_line(ctx, s, x0, y1, x1, y1, 1);
}
static void
fz_add_arc(fz_context *ctx, sctx *s,
float xc, float yc,
float x0, float y0,
- float x1, float y1)
+ float x1, float y1,
+ int rev)
{
float th0, th1, r;
float theta;
@@ -355,42 +432,37 @@ fz_add_arc(fz_context *ctx, sctx *s,
n = ceilf((th1 - th0) / theta);
}
- ox = x0;
- oy = y0;
- for (i = 1; i < n; i++)
+ if (rev)
{
- theta = th0 + (th1 - th0) * i / n;
- nx = cosf(theta) * r;
- ny = sinf(theta) * r;
- fz_add_line(ctx, s, xc + ox, yc + oy, xc + nx, yc + ny);
- ox = nx;
- oy = ny;
- }
-
- fz_add_line(ctx, s, xc + ox, yc + oy, xc + x1, yc + y1);
-}
-
-static void
-fz_add_line_stroke(fz_context *ctx, sctx *s, float ax, float ay, float bx, float by)
-{
- float dx = bx - ax;
- float dy = by - ay;
- float scale = s->linewidth / sqrtf(dx * dx + dy * dy);
- float dlx = dy * scale;
- float dly = -dx * scale;
+ ox = x1;
+ oy = y1;
+ for (i = n-1; i > 0; i--)
+ {
+ theta = th0 + (th1 - th0) * i / n;
+ nx = cosf(theta) * r;
+ ny = sinf(theta) * r;
+ fz_add_line(ctx, s, xc + nx, yc + ny, xc + ox, yc + oy, rev);
+ ox = nx;
+ oy = ny;
+ }
- if (0 && dx == 0)
- {
- fz_add_vert_rect(ctx, s, ax - dlx, ay, bx + dlx, by);
- }
- else if (dy == 0)
- {
- fz_add_horiz_rect(ctx, s, ax, ay - dly, bx, by + dly);
+ fz_add_line(ctx, s, xc + x0, yc + y0, xc + ox, yc + oy, rev);
}
else
{
- fz_add_line(ctx, s, ax - dlx, ay - dly, bx - dlx, by - dly);
- fz_add_line(ctx, s, bx + dlx, by + dly, ax + dlx, ay + dly);
+ 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(ctx, s, xc + ox, yc + oy, xc + nx, yc + ny, rev);
+ ox = nx;
+ oy = ny;
+ }
+
+ fz_add_line(ctx, s, xc + ox, yc + oy, xc + x1, yc + y1, rev);
}
}
@@ -409,6 +481,7 @@ fz_add_line_join(fz_context *ctx, sctx *s, float ax, float ay, float bx, float b
float scale;
float cross;
float len0, len1;
+ int rev = 0;
dx0 = bx - ax;
dy0 = by - ay;
@@ -424,6 +497,7 @@ fz_add_line_join(fz_context *ctx, sctx *s, float ax, float ay, float bx, float b
tmp = dx1; dx1 = -dx0; dx0 = -tmp;
tmp = dy1; dy1 = -dy0; dy0 = -tmp;
cross = -cross;
+ rev = !rev;
}
len0 = dx0 * dx0 + dy0 * dy0;
@@ -461,16 +535,6 @@ fz_add_line_join(fz_context *ctx, sctx *s, float ax, float ay, float bx, float b
if (cross * cross < FLT_EPSILON && dx0 * dx1 + dy0 * dy1 >= 0)
linejoin = FZ_LINEJOIN_BEVEL;
- if (join_under)
- {
- fz_add_line(ctx, s, bx + dlx1, by + dly1, bx + dlx0, by + dly0);
- }
- else
- {
- fz_add_line(ctx, s, bx + dlx1, by + dly1, bx, by);
- fz_add_line(ctx, s, bx, by, bx + dlx0, by + dly0);
- }
-
/* XPS miter joins are clipped at miterlength, rather than simply
* being converted to bevelled joins. */
if (linejoin == FZ_LINEJOIN_MITER_XPS)
@@ -479,47 +543,78 @@ fz_add_line_join(fz_context *ctx, sctx *s, float ax, float ay, float bx, float b
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 = bx - dmx + k * (dmx - dlx0);
- t0y = by - dmy + k * (dmy - dly0);
- t1x = bx - dmx + k * (dmx - dlx1);
- t1y = by - dmy + k * (dmy - dly1);
-
- fz_add_line(ctx, s, bx - dlx0, by - dly0, t0x, t0y);
- fz_add_line(ctx, s, t0x, t0y, t1x, t1y);
- fz_add_line(ctx, s, t1x, t1y, bx - dlx1, by - dly1);
- }
}
else if (linejoin == FZ_LINEJOIN_MITER)
if (dmr2 * miterlimit * miterlimit < linewidth * linewidth)
linejoin = FZ_LINEJOIN_BEVEL;
+ if (join_under)
+ {
+ fz_add_line(ctx, s, bx + dlx1, by + dly1, bx + dlx0, by + dly0, !rev);
+ }
+ else if (rev)
+ {
+ fz_add_line(ctx, s, bx + dlx1, by + dly1, bx, by, 0);
+ fz_add_line(ctx, s, bx, by, bx + dlx0, by + dly0, 0);
+ }
+ else
+ {
+ fz_add_line(ctx, s, bx, by, bx + dlx0, by + dly0, 1);
+ fz_add_line(ctx, s, bx + dlx1, by + dly1, bx, by, 1);
+ }
+
switch (linejoin)
{
case FZ_LINEJOIN_MITER_XPS:
- break;
+ {
+ float k, t0x, t0y, t1x, t1y;
+ scale = linewidth * linewidth / dmr2;
+ dmx *= scale;
+ dmy *= scale;
+ k = (scale - linewidth * miterlimit / sqrtf(dmr2)) / (scale - 1);
+ t0x = bx - dmx + k * (dmx - dlx0);
+ t0y = by - dmy + k * (dmy - dly0);
+ t1x = bx - dmx + k * (dmx - dlx1);
+ t1y = by - dmy + k * (dmy - dly1);
+
+ if (rev)
+ {
+ fz_add_line(ctx, s, t1x, t1y, bx - dlx1, by - dly1, 1);
+ fz_add_line(ctx, s, t0x, t0y, t1x, t1y, 1);
+ fz_add_line(ctx, s, bx - dlx0, by - dly0, t0x, t0y, 1);
+ }
+ else
+ {
+ fz_add_line(ctx, s, bx - dlx0, by - dly0, t0x, t0y, 0);
+ fz_add_line(ctx, s, t0x, t0y, t1x, t1y, 0);
+ fz_add_line(ctx, s, t1x, t1y, bx - dlx1, by - dly1, 0);
+ }
+ break;
+ }
case FZ_LINEJOIN_MITER:
scale = linewidth * linewidth / dmr2;
dmx *= scale;
dmy *= scale;
- fz_add_line(ctx, s, bx - dlx0, by - dly0, bx - dmx, by - dmy);
- fz_add_line(ctx, s, bx - dmx, by - dmy, bx - dlx1, by - dly1);
+ if (rev)
+ {
+ fz_add_line(ctx, s, bx - dmx, by - dmy, bx - dlx1, by - dly1, 1);
+ fz_add_line(ctx, s, bx - dlx0, by - dly0, bx - dmx, by - dmy, 1);
+ }
+ else
+ {
+ fz_add_line(ctx, s, bx - dlx0, by - dly0, bx - dmx, by - dmy, 0);
+ fz_add_line(ctx, s, bx - dmx, by - dmy, bx - dlx1, by - dly1, 0);
+ }
break;
case FZ_LINEJOIN_BEVEL:
- fz_add_line(ctx, s, bx - dlx0, by - dly0, bx - dlx1, by - dly1);
+ fz_add_line(ctx, s, bx - dlx0, by - dly0, bx - dlx1, by - dly1, rev);
break;
case FZ_LINEJOIN_ROUND:
- fz_add_arc(ctx, s, bx, by, -dlx0, -dly0, -dlx1, -dly1);
+ fz_add_arc(ctx, s, bx, by, -dlx0, -dly0, -dlx1, -dly1, rev);
break;
default:
@@ -528,7 +623,7 @@ fz_add_line_join(fz_context *ctx, sctx *s, float ax, float ay, float bx, float b
}
static void
-fz_add_line_cap(fz_context *ctx, sctx *s, float ax, float ay, float bx, float by, fz_linecap linecap)
+fz_add_line_cap(fz_context *ctx, sctx *s, float ax, float ay, float bx, float by, fz_linecap linecap, int rev)
{
float flatness = s->flatness;
float linewidth = s->linewidth;
@@ -543,7 +638,7 @@ fz_add_line_cap(fz_context *ctx, sctx *s, float ax, float ay, float bx, float by
switch (linecap)
{
case FZ_LINECAP_BUTT:
- fz_add_line(ctx, s, bx - dlx, by - dly, bx + dlx, by + dly);
+ fz_add_line(ctx, s, bx - dlx, by - dly, bx + dlx, by + dly, rev);
break;
case FZ_LINECAP_ROUND:
@@ -559,29 +654,29 @@ fz_add_line_cap(fz_context *ctx, sctx *s, float ax, float ay, float bx, float by
float sth = sinf(theta);
float nx = bx - dlx * cth - dly * sth;
float ny = by - dly * cth + dlx * sth;
- fz_add_line(ctx, s, ox, oy, nx, ny);
+ fz_add_line(ctx, s, ox, oy, nx, ny, rev);
ox = nx;
oy = ny;
}
- fz_add_line(ctx, s, ox, oy, bx + dlx, by + dly);
+ fz_add_line(ctx, s, ox, oy, bx + dlx, by + dly, rev);
break;
}
case FZ_LINECAP_SQUARE:
fz_add_line(ctx, s, bx - dlx, by - dly,
- bx - dlx - dly, by - dly + dlx);
+ bx - dlx - dly, by - dly + dlx, rev);
fz_add_line(ctx, s, bx - dlx - dly, by - dly + dlx,
- bx + dlx - dly, by + dly + dlx);
+ bx + dlx - dly, by + dly + dlx, rev);
fz_add_line(ctx, s, bx + dlx - dly, by + dly + dlx,
- bx + dlx, by + dly);
+ bx + dlx, by + dly, rev);
break;
case FZ_LINECAP_TRIANGLE:
{
float mx = -dly;
float my = dlx;
- fz_add_line(ctx, s, bx - dlx, by - dly, bx + mx, by + my);
- fz_add_line(ctx, s, bx + mx, by + my, bx + dlx, by + dly);
+ fz_add_line(ctx, s, bx - dlx, by - dly, bx + mx, by + my, rev);
+ fz_add_line(ctx, s, bx + mx, by + my, bx + dlx, by + dly, rev);
break;
}
@@ -609,12 +704,12 @@ fz_add_line_dot(fz_context *ctx, sctx *s, float ax, float ay)
float sth = sinf(theta);
float nx = ax - cth * linewidth;
float ny = ay + sth * linewidth;
- fz_add_line(ctx, s, ox, oy, nx, ny);
+ fz_add_line(ctx, s, ox, oy, nx, ny, 0);
ox = nx;
oy = ny;
}
- fz_add_line(ctx, s, ox, oy, ax - linewidth, ay);
+ fz_add_line(ctx, s, ox, oy, ax - linewidth, ay, 0);
}
static void
@@ -622,13 +717,14 @@ fz_stroke_flush(fz_context *ctx, sctx *s, fz_linecap start_cap, fz_linecap end_c
{
if (s->sn == 2)
{
- fz_add_line_cap(ctx, s, s->beg[1].x, s->beg[1].y, s->beg[0].x, s->beg[0].y, start_cap);
- fz_add_line_cap(ctx, s, s->seg[0].x, s->seg[0].y, s->seg[1].x, s->seg[1].y, end_cap);
+ fz_add_line_cap(ctx, s, s->beg[1].x, s->beg[1].y, s->beg[0].x, s->beg[0].y, start_cap, 2);
+ fz_add_line_cap(ctx, s, s->seg[0].x, s->seg[0].y, s->seg[1].x, s->seg[1].y, end_cap, 0);
}
else if (s->dot)
{
fz_add_line_dot(ctx, s, s->beg[0].x, s->beg[0].y);
}
+ fz_gap_rasterizer(ctx, s->rast);
}
static void
@@ -646,8 +742,11 @@ fz_stroke_moveto(fz_context *ctx, void *s_, float x, float y)
static void
fz_stroke_lineto(fz_context *ctx, sctx *s, float x, float y, int from_bezier)
{
- float dx = x - s->seg[s->sn-1].x;
- float dy = y - s->seg[s->sn-1].y;
+ float ox = s->seg[s->sn-1].x;
+ float oy = s->seg[s->sn-1].y;
+ float dx = x - ox;
+ float dy = y - oy;
+ float scale, dlx, dly;
if (dx * dx + dy * dy < FLT_EPSILON)
{
@@ -656,11 +755,32 @@ fz_stroke_lineto(fz_context *ctx, sctx *s, float x, float y, int from_bezier)
return;
}
- fz_add_line_stroke(ctx, s, s->seg[s->sn-1].x, s->seg[s->sn-1].y, x, y);
+ if (s->sn == 2)
+ fz_add_line_join(ctx, s, s->seg[0].x, s->seg[0].y, ox, oy, x, y, s->from_bezier & from_bezier);
+
+ scale = s->linewidth / sqrtf(dx * dx + dy * dy);
+ dlx = dy * scale;
+ dly = -dx * scale;
+
+#if 1
+ if (0 && dx == 0)
+ {
+ fz_add_vert_rect(ctx, s, ox - dlx, oy, x + dlx, y);
+ }
+ else if (dy == 0)
+ {
+ fz_add_horiz_rect(ctx, s, ox, oy - dly, x, y + dly);
+ }
+ else
+#endif
+ {
+
+ fz_add_line(ctx, s, ox - dlx, oy - dly, x - dlx, y - dly, 0);
+ fz_add_line(ctx, s, x + dlx, y + dly, ox + dlx, oy + dly, 1);
+ }
if (s->sn == 2)
{
- fz_add_line_join(ctx, s, s->seg[0].x, s->seg[0].y, s->seg[1].x, s->seg[1].y, x, y, s->from_bezier & from_bezier);
s->seg[0] = s->seg[1];
s->seg[1].x = x;
s->seg[1].y = y;
@@ -686,16 +806,17 @@ fz_stroke_closepath(fz_context *ctx, sctx *s)
fz_add_line_join(ctx, s, s->seg[1].x, s->seg[1].y, s->beg[0].x, s->beg[0].y, s->beg[1].x, s->beg[1].y, 0);
}
else if (s->dot)
- {
fz_add_line_dot(ctx, s, s->beg[0].x, s->beg[0].y);
- }
s->seg[0] = s->beg[0];
s->sn = 1;
s->dot = 0;
s->from_bezier = 0;
+
+ fz_gap_rasterizer(ctx, s->rast);
}
+
static void
fz_stroke_bezier(fz_context *ctx, struct sctx *s,
float xa, float ya,
@@ -1274,16 +1395,14 @@ static const fz_path_walker dash_proc =
dash_quadto
};
-void
-fz_flatten_stroke_path(fz_context *ctx, fz_gel *gel, const fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm, float flatness, float linewidth, const fz_irect *scissor)
+static int
+do_flatten_stroke(fz_context *ctx, fz_rasterizer *rast, const fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm, float flatness, float linewidth, const fz_irect *scissor, fz_irect *bbox)
{
struct sctx s;
const fz_path_walker *proc = &stroke_proc;
- fz_reset_gel(ctx, gel, scissor);
-
s.stroke = stroke;
- s.gel = gel;
+ s.rast = rast;
s.ctm = ctm;
s.flatness = flatness;
s.linejoin = stroke->linejoin;
@@ -1310,11 +1429,11 @@ fz_flatten_stroke_path(fz_context *ctx, fz_gel *gel, const fz_path *path, const
for (i = 0; i < s.dash_len; i++)
s.dash_total += list[i];
if (s.dash_total == 0)
- return;
+ return 1;
- fz_gel_scissor(ctx, gel, &s.rect);
+ fz_scissor_rasterizer(ctx, rast, &s.rect);
if (fz_try_invert_matrix(&inv, ctm))
- return;
+ return 1;
fz_transform_rect(&s.rect, &inv);
s.rect.x0 -= linewidth;
s.rect.x1 += linewidth;
@@ -1333,4 +1452,24 @@ fz_flatten_stroke_path(fz_context *ctx, fz_gel *gel, const fz_path *path, const
s.cur.x = s.cur.y = 0;
fz_walk_path(ctx, path, proc, &s);
fz_stroke_flush(ctx, &s, s.cap, stroke->end_cap);
+
+ if (!bbox)
+ return 0;
+
+ return fz_is_empty_irect(fz_bound_rasterizer(ctx, rast, bbox));
+}
+
+int
+fz_flatten_stroke_path(fz_context *ctx, fz_rasterizer *rast, const fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm, float flatness, float linewidth, const fz_irect *scissor, fz_irect *bbox)
+{
+
+ if (fz_reset_rasterizer(ctx, rast, scissor))
+ {
+ if (do_flatten_stroke(ctx, rast, path, stroke, ctm, flatness, linewidth, scissor, bbox))
+ return 1;
+ fz_postindex_rasterizer(ctx, rast);
+ bbox = NULL;
+ }
+
+ return do_flatten_stroke(ctx, rast, path, stroke, ctm, flatness, linewidth, scissor, bbox);
}