summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mupdf/fitz/path.h37
-rw-r--r--source/fitz/draw-path.c822
-rw-r--r--source/fitz/font.c9
-rw-r--r--source/fitz/path.c1032
-rw-r--r--source/fitz/svg-device.c78
-rw-r--r--source/fitz/trace-device.c98
-rw-r--r--source/pdf/pdf-device.c80
-rw-r--r--source/pdf/pdf-op-run.c6
-rw-r--r--source/xps/xps-path.c11
9 files changed, 1647 insertions, 526 deletions
diff --git a/include/mupdf/fitz/path.h b/include/mupdf/fitz/path.h
index 23dc0838..1bca1858 100644
--- a/include/mupdf/fitz/path.h
+++ b/include/mupdf/fitz/path.h
@@ -17,14 +17,6 @@
typedef struct fz_path_s fz_path;
typedef struct fz_stroke_state_s fz_stroke_state;
-typedef enum fz_path_command_e
-{
- FZ_MOVETO = 'M',
- FZ_LINETO = 'L',
- FZ_CURVETO = 'C',
- FZ_CLOSE_PATH = 'Z',
-} fz_path_item_kind;
-
typedef enum fz_linecap_e
{
FZ_LINECAP_BUTT = 0,
@@ -41,18 +33,6 @@ typedef enum fz_linejoin_e
FZ_LINEJOIN_MITER_XPS = 3
} fz_linejoin;
-struct fz_path_s
-{
- int refs;
- int cmd_len, cmd_cap;
- unsigned char *cmds;
- int coord_len, coord_cap;
- float *coords;
- fz_point current;
- fz_point begin;
- int last_cmd;
-};
-
struct fz_stroke_state_s
{
int refs;
@@ -65,6 +45,21 @@ struct fz_stroke_state_s
float dash_list[32];
};
+typedef struct
+{
+ void (*moveto)(fz_context *ctx, void *arg, float x, float y);
+ void (*lineto)(fz_context *ctx, void *arg, float x, float y);
+ void (*curveto)(fz_context *ctx, void *arg, float x1, float y1, float x2, float y2, float x3, float y3);
+ void (*close)(fz_context *ctx, void *arg);
+ /* Optional ones */
+ void (*quadto)(fz_context *ctx, void *arg, float x1, float y1, float x2, float y2);
+ void (*curvetov)(fz_context *ctx, void *arg, float x2, float y2, float x3, float y3);
+ void (*curvetoy)(fz_context *ctx, void *arg, float x1, float y1, float x3, float y3);
+ void (*rectto)(fz_context *ctx, void *arg, float x1, float y1, float x2, float y2);
+} fz_path_processor;
+
+void fz_process_path(fz_context *ctx, const fz_path_processor *proc, void *arg, const fz_path *path);
+
fz_path *fz_new_path(fz_context *ctx);
fz_path *fz_keep_path(fz_context *ctx, fz_path *path);
void fz_drop_path(fz_context *ctx, fz_path *path);
@@ -73,6 +68,8 @@ void fz_trim_path(fz_context *ctx, fz_path *path);
fz_point fz_currentpoint(fz_context *ctx, fz_path *path);
void fz_moveto(fz_context*, fz_path*, float x, float y);
void fz_lineto(fz_context*, fz_path*, float x, float y);
+void fz_quadto(fz_context*, fz_path*, float x1, float y1, float x2, float y2);
+void fz_rectto(fz_context*, fz_path*, float x1, float y1, float x2, float y2);
void fz_curveto(fz_context*,fz_path*, float, float, float, float, float, float);
void fz_curvetov(fz_context*,fz_path*, float, float, float, float);
void fz_curvetoy(fz_context*,fz_path*, float, float, float, float);
diff --git a/source/fitz/draw-path.c b/source/fitz/draw-path.c
index 8ad0b334..2e751222 100644
--- a/source/fitz/draw-path.c
+++ b/source/fitz/draw-path.c
@@ -67,67 +67,137 @@ bezier(fz_context *ctx, fz_gel *gel, const fz_matrix *ctm, float flatness,
bezier(ctx, gel, ctm, flatness, xabcd, yabcd, xbcd, ybcd, xcd, ycd, xd, yd, depth + 1);
}
-void
-fz_flatten_fill_path(fz_context *ctx, fz_gel *gel, fz_path *path, const fz_matrix *ctm, float flatness)
+static void
+quad(fz_context *ctx, fz_gel *gel, const fz_matrix *ctm, float flatness,
+ float xa, float ya,
+ float xb, float yb,
+ float xc, float yc, int depth)
{
- float x1, y1, x2, y2, x3, y3;
- float cx = 0;
- float cy = 0;
- float bx = 0;
- float by = 0;
- int i = 0, k = 0;
-
- while (i < path->cmd_len)
+ float dmax;
+ float xab, yab;
+ float xbc, ybc;
+ float xabc, yabc;
+
+ /* termination check */
+ dmax = fz_abs(xa - xb);
+ dmax = fz_max(dmax, fz_abs(ya - yb));
+ dmax = fz_max(dmax, fz_abs(xc - xb));
+ dmax = fz_max(dmax, fz_abs(yc - yb));
+ if (dmax < flatness || depth >= MAX_DEPTH)
{
- switch (path->cmds[i++])
- {
- case FZ_MOVETO:
- /* implicit closepath before moveto */
- if (cx != bx || cy != by)
- line(ctx, gel, ctm, cx, cy, bx, by);
- x1 = path->coords[k++];
- y1 = path->coords[k++];
- cx = bx = x1;
- cy = by = y1;
- break;
-
- case FZ_LINETO:
- x1 = path->coords[k++];
- y1 = path->coords[k++];
- line(ctx, gel, ctm, cx, cy, x1, y1);
- cx = x1;
- cy = y1;
- break;
-
- case FZ_CURVETO:
- x1 = path->coords[k++];
- y1 = path->coords[k++];
- x2 = path->coords[k++];
- y2 = path->coords[k++];
- x3 = path->coords[k++];
- y3 = path->coords[k++];
- bezier(ctx, gel, ctm, flatness, cx, cy, x1, y1, x2, y2, x3, y3, 0);
- cx = x3;
- cy = y3;
- break;
-
- case FZ_CLOSE_PATH:
- line(ctx, gel, ctm, cx, cy, bx, by);
- cx = bx;
- cy = by;
- break;
- }
+ line(ctx, gel, ctm, xa, ya, xc, yc);
+ return;
}
- if (cx != bx || cy != by)
- line(ctx, gel, ctm, cx, cy, bx, by);
+ xab = xa + xb;
+ yab = ya + yb;
+ xbc = xb + xc;
+ ybc = yb + yc;
+
+ xabc = xab + xbc;
+ yabc = yab + ybc;
+
+ xab *= 0.5f; yab *= 0.5f;
+ xbc *= 0.5f; ybc *= 0.5f;
+
+ 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);
}
-struct sctx
+typedef struct
{
fz_gel *gel;
const fz_matrix *ctm;
float flatness;
+ fz_point b;
+ fz_point c;
+}
+flatten_arg;
+
+static void
+flatten_moveto(fz_context *ctx, void *arg_, float x, float y)
+{
+ flatten_arg *arg = (flatten_arg *)arg_;
+
+ /* 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);
+ arg->c.x = arg->b.x = x;
+ arg->c.y = arg->b.y = y;
+}
+
+static void
+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);
+ arg->c.x = x;
+ arg->c.y = y;
+}
+
+static void
+flatten_curveto(fz_context *ctx, void *arg_, float x1, float y1, float x2, float y2, float x3, float y3)
+{
+ 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);
+ arg->c.x = x3;
+ arg->c.y = y3;
+}
+
+static void
+flatten_quadto(fz_context *ctx, void *arg_, float x1, float y1, float x2, float y2)
+{
+ 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);
+ arg->c.x = x2;
+ arg->c.y = y2;
+}
+
+static void
+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);
+ arg->c.x = arg->b.x;
+ arg->c.y = arg->b.y;
+}
+
+static const fz_path_processor flatten_proc =
+{
+ flatten_moveto,
+ flatten_lineto,
+ flatten_curveto,
+ flatten_close,
+ flatten_quadto
+};
+
+void
+fz_flatten_fill_path(fz_context *ctx, fz_gel *gel, fz_path *path, const fz_matrix *ctm, float flatness)
+{
+ flatten_arg arg;
+
+ arg.gel = gel;
+ arg.ctm = ctm;
+ arg.flatness = flatness;
+ arg.b.x = arg.b.y = arg.c.x = arg.c.y = 0;
+
+ fz_process_path(ctx, &flatten_proc, &arg, path);
+ 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);
+}
+
+typedef struct sctx
+{
+ fz_gel *gel;
+ const fz_matrix *ctm;
+ float flatness;
+ const fz_stroke_state *stroke;
int linejoin;
float linewidth;
@@ -137,6 +207,7 @@ struct sctx
int sn;
int dot;
int from_bezier;
+ fz_point cur;
fz_rect rect;
const float *dash_list;
@@ -146,11 +217,12 @@ struct sctx
int toggle, cap;
int offset;
float phase;
- fz_point cur;
-};
+ fz_point dash_cur;
+ fz_point dash_beg;
+} sctx;
static void
-fz_add_line(fz_context *ctx, struct 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)
{
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;
@@ -160,7 +232,7 @@ fz_add_line(fz_context *ctx, struct sctx *s, float x0, float y0, float x1, float
}
static void
-fz_add_arc(fz_context *ctx, struct sctx *s,
+fz_add_arc(fz_context *ctx, sctx *s,
float xc, float yc,
float x0, float y0,
float x1, float y1)
@@ -204,19 +276,20 @@ fz_add_arc(fz_context *ctx, struct sctx *s,
}
static void
-fz_add_line_stroke(fz_context *ctx, struct sctx *s, fz_point a, fz_point b)
+fz_add_line_stroke(fz_context *ctx, sctx *s, float ax, float ay, float bx, float by)
{
- float dx = b.x - a.x;
- float dy = b.y - a.y;
+ 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;
- fz_add_line(ctx, s, a.x - dlx, a.y - dly, b.x - dlx, b.y - dly);
- fz_add_line(ctx, s, b.x + dlx, b.y + dly, a.x + dlx, a.y + dly);
+
+ 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);
}
static void
-fz_add_line_join(fz_context *ctx, struct sctx *s, fz_point a, fz_point b, fz_point c, int join_under)
+fz_add_line_join(fz_context *ctx, sctx *s, float ax, float ay, float bx, float by, float cx, float cy, int join_under)
{
float miterlimit = s->miterlimit;
float linewidth = s->linewidth;
@@ -231,11 +304,11 @@ fz_add_line_join(fz_context *ctx, struct sctx *s, fz_point a, fz_point b, fz_poi
float cross;
float len0, len1;
- dx0 = b.x - a.x;
- dy0 = b.y - a.y;
+ dx0 = bx - ax;
+ dy0 = by - ay;
- dx1 = c.x - b.x;
- dy1 = c.y - b.y;
+ dx1 = cx - bx;
+ dy1 = cy - by;
cross = dx1 * dy0 - dx0 * dy1;
/* Ensure that cross >= 0 */
@@ -284,12 +357,12 @@ fz_add_line_join(fz_context *ctx, struct sctx *s, fz_point a, fz_point b, fz_poi
if (join_under)
{
- fz_add_line(ctx, s, b.x + dlx1, b.y + dly1, b.x + dlx0, b.y + dly0);
+ fz_add_line(ctx, s, bx + dlx1, by + dly1, bx + dlx0, by + dly0);
}
else
{
- fz_add_line(ctx, s, b.x + dlx1, b.y + dly1, b.x, b.y);
- fz_add_line(ctx, s, b.x, b.y, b.x + dlx0, b.y + dly0);
+ 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
@@ -307,104 +380,118 @@ fz_add_line_join(fz_context *ctx, struct sctx *s, fz_point a, fz_point b, fz_poi
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);
+ 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, b.x - dlx0, b.y - dly0, t0x, t0y);
+ 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, b.x - dlx1, b.y - dly1);
+ 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 (linejoin == FZ_LINEJOIN_MITER)
+ switch (linejoin)
{
+ case FZ_LINEJOIN_MITER_XPS:
+ break;
+
+ case FZ_LINEJOIN_MITER:
scale = linewidth * linewidth / dmr2;
dmx *= scale;
dmy *= scale;
- fz_add_line(ctx, s, b.x - dlx0, b.y - dly0, b.x - dmx, b.y - dmy);
- fz_add_line(ctx, s, b.x - dmx, b.y - dmy, b.x - dlx1, b.y - dly1);
- }
+ 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);
+ break;
- if (linejoin == FZ_LINEJOIN_BEVEL)
- {
- fz_add_line(ctx, s, b.x - dlx0, b.y - dly0, b.x - dlx1, b.y - dly1);
- }
+ case FZ_LINEJOIN_BEVEL:
+ fz_add_line(ctx, s, bx - dlx0, by - dly0, bx - dlx1, by - dly1);
+ break;
- if (linejoin == FZ_LINEJOIN_ROUND)
- {
- fz_add_arc(ctx, s, b.x, b.y, -dlx0, -dly0, -dlx1, -dly1);
+ case FZ_LINEJOIN_ROUND:
+ fz_add_arc(ctx, s, bx, by, -dlx0, -dly0, -dlx1, -dly1);
+ break;
+
+ default:
+ assert("Invalid line join" == NULL);
}
}
static void
-fz_add_line_cap(fz_context *ctx, struct sctx *s, fz_point a, fz_point b, fz_linecap linecap)
+fz_add_line_cap(fz_context *ctx, sctx *s, float ax, float ay, float bx, float by, fz_linecap linecap)
{
float flatness = s->flatness;
float linewidth = s->linewidth;
- float dx = b.x - a.x;
- float dy = b.y - a.y;
+ float dx = bx - ax;
+ float dy = by - ay;
float scale = linewidth / sqrtf(dx * dx + dy * dy);
float dlx = dy * scale;
float dly = -dx * scale;
- if (linecap == FZ_LINECAP_BUTT)
- fz_add_line(ctx, s, b.x - dlx, b.y - dly, b.x + dlx, b.y + dly);
+ switch (linecap)
+ {
+ case FZ_LINECAP_BUTT:
+ fz_add_line(ctx, s, bx - dlx, by - dly, bx + dlx, by + dly);
+ break;
- if (linecap == FZ_LINECAP_ROUND)
+ case 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;
+ float ox = bx - dlx;
+ float oy = by - 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;
+ float nx = bx - dlx * cth - dly * sth;
+ float ny = by - dly * cth + dlx * sth;
fz_add_line(ctx, s, ox, oy, nx, ny);
ox = nx;
oy = ny;
}
- fz_add_line(ctx, s, ox, oy, b.x + dlx, b.y + dly);
+ fz_add_line(ctx, s, ox, oy, bx + dlx, by + dly);
+ break;
}
- if (linecap == FZ_LINECAP_SQUARE)
- {
- fz_add_line(ctx, s, b.x - dlx, b.y - dly,
- b.x - dlx - dly, b.y - dly + dlx);
- fz_add_line(ctx, s, b.x - dlx - dly, b.y - dly + dlx,
- b.x + dlx - dly, b.y + dly + dlx);
- fz_add_line(ctx, s, b.x + dlx - dly, b.y + dly + dlx,
- b.x + dlx, b.y + dly);
- }
+ case FZ_LINECAP_SQUARE:
+ fz_add_line(ctx, s, bx - dlx, by - dly,
+ bx - dlx - dly, by - dly + dlx);
+ fz_add_line(ctx, s, bx - dlx - dly, by - dly + dlx,
+ bx + dlx - dly, by + dly + dlx);
+ fz_add_line(ctx, s, bx + dlx - dly, by + dly + dlx,
+ bx + dlx, by + dly);
+ break;
- if (linecap == FZ_LINECAP_TRIANGLE)
+ case FZ_LINECAP_TRIANGLE:
{
float mx = -dly;
float my = dlx;
- fz_add_line(ctx, s, b.x - dlx, b.y - dly, b.x + mx, b.y + my);
- fz_add_line(ctx, s, b.x + mx, b.y + my, b.x + dlx, b.y + dly);
+ 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);
+ break;
+ }
+
+ default:
+ assert("Invalid line cap" == NULL);
}
}
static void
-fz_add_line_dot(fz_context *ctx, struct sctx *s, fz_point a)
+fz_add_line_dot(fz_context *ctx, sctx *s, float ax, float ay)
{
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;
+ float ox = ax - linewidth;
+ float oy = ay;
int i;
for (i = 1; i < n; i++)
@@ -412,45 +499,47 @@ fz_add_line_dot(fz_context *ctx, struct sctx *s, fz_point a)
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;
+ float nx = ax - cth * linewidth;
+ float ny = ay + sth * linewidth;
fz_add_line(ctx, s, ox, oy, nx, ny);
ox = nx;
oy = ny;
}
- fz_add_line(ctx, s, ox, oy, a.x - linewidth, a.y);
+ fz_add_line(ctx, s, ox, oy, ax - linewidth, ay);
}
static void
-fz_stroke_flush(fz_context *ctx, struct sctx *s, fz_linecap start_cap, fz_linecap end_cap)
+fz_stroke_flush(fz_context *ctx, sctx *s, fz_linecap start_cap, fz_linecap end_cap)
{
if (s->sn == 2)
{
- fz_add_line_cap(ctx, s, s->beg[1], s->beg[0], start_cap);
- fz_add_line_cap(ctx, s, s->seg[0], s->seg[1], 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);
+ fz_add_line_cap(ctx, s, s->seg[0].x, s->seg[0].y, s->seg[1].x, s->seg[1].y, end_cap);
}
else if (s->dot)
{
- fz_add_line_dot(ctx, s, s->beg[0]);
+ fz_add_line_dot(ctx, s, s->beg[0].x, s->beg[0].y);
}
}
static void
-fz_stroke_moveto(fz_context *ctx, struct sctx *s, fz_point cur)
+fz_stroke_moveto(fz_context *ctx, void *s_, float x, float y)
{
- s->seg[0] = cur;
- s->beg[0] = cur;
+ struct sctx *s = (struct sctx *)s_;
+
+ s->seg[0].x = s->beg[0].x = x;
+ s->seg[0].y = s->beg[0].y = y;
s->sn = 1;
s->dot = 0;
s->from_bezier = 0;
}
static void
-fz_stroke_lineto(fz_context *ctx, struct sctx *s, fz_point cur, int from_bezier)
+fz_stroke_lineto(fz_context *ctx, sctx *s, float x, float y, int from_bezier)
{
- float dx = cur.x - s->seg[s->sn-1].x;
- float dy = cur.y - s->seg[s->sn-1].y;
+ float dx = x - s->seg[s->sn-1].x;
+ float dy = y - s->seg[s->sn-1].y;
if (dx * dx + dy * dy < FLT_EPSILON)
{
@@ -459,37 +548,38 @@ fz_stroke_lineto(fz_context *ctx, struct sctx *s, fz_point cur, int from_bezier)
return;
}
- fz_add_line_stroke(ctx, s, s->seg[s->sn-1], cur);
+ 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], s->seg[1], cur, s->from_bezier & from_bezier);
+ 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] = cur;
+ s->seg[1].x = x;
+ s->seg[1].y = y;
}
else
{
- s->seg[1] = cur;
- s->beg[1] = cur;
+ s->seg[1].x = s->beg[1].x = x;
+ s->seg[1].y = s->beg[1].y = y;
s->sn = 2;
}
s->from_bezier = from_bezier;
}
static void
-fz_stroke_closepath(fz_context *ctx, struct sctx *s)
+fz_stroke_closepath(fz_context *ctx, sctx *s)
{
if (s->sn == 2)
{
- fz_stroke_lineto(ctx, s, s->beg[0], 0);
+ fz_stroke_lineto(ctx, s, s->beg[0].x, s->beg[0].y, 0);
if (s->seg[1].x == s->beg[0].x && s->seg[1].y == s->beg[0].y)
- fz_add_line_join(ctx, s, s->seg[0], s->beg[0], s->beg[1], 0);
+ fz_add_line_join(ctx, s, s->seg[0].x, s->seg[0].y, s->beg[0].x, s->beg[0].y, s->beg[1].x, s->beg[1].y, 0);
else
- fz_add_line_join(ctx, s, s->seg[1], s->beg[0], s->beg[1], 0);
+ 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]);
+ fz_add_line_dot(ctx, s, s->beg[0].x, s->beg[0].y);
}
s->seg[0] = s->beg[0];
@@ -520,10 +610,7 @@ fz_stroke_bezier(fz_context *ctx, struct sctx *s,
dmax = fz_max(dmax, fz_abs(yd - yc));
if (dmax < s->flatness || depth >= MAX_DEPTH)
{
- fz_point p;
- p.x = xd;
- p.y = yd;
- fz_stroke_lineto(ctx, s, p, 1);
+ fz_stroke_lineto(ctx, s, xd, yd, 1);
return;
}
@@ -555,13 +642,109 @@ fz_stroke_bezier(fz_context *ctx, struct sctx *s,
fz_stroke_bezier(ctx, s, xabcd, yabcd, xbcd, ybcd, xcd, ycd, xd, yd, depth + 1);
}
+static void
+fz_stroke_quad(fz_context *ctx, struct sctx *s,
+ float xa, float ya,
+ float xb, float yb,
+ float xc, float yc, int depth)
+{
+ float dmax;
+ float xab, yab;
+ float xbc, ybc;
+ float xabc, yabc;
+
+ /* termination check */
+ dmax = fz_abs(xa - xb);
+ dmax = fz_max(dmax, fz_abs(ya - yb));
+ dmax = fz_max(dmax, fz_abs(xc - xb));
+ dmax = fz_max(dmax, fz_abs(yc - yb));
+ if (dmax < s->flatness || depth >= MAX_DEPTH)
+ {
+ fz_stroke_lineto(ctx, s, xc, yc, 1);
+ return;
+ }
+
+ xab = xa + xb;
+ yab = ya + yb;
+ xbc = xb + xc;
+ ybc = yb + yc;
+
+ xabc = xab + xbc;
+ yabc = yab + ybc;
+
+ xab *= 0.5f; yab *= 0.5f;
+ xbc *= 0.5f; ybc *= 0.5f;
+
+ xabc *= 0.25f; yabc *= 0.25f;
+
+ fz_stroke_quad(ctx, s, xa, ya, xab, yab, xabc, yabc, depth + 1);
+ fz_stroke_quad(ctx, s, xabc, yabc, xbc, ybc, xc, yc, depth + 1);
+}
+
+static void
+stroke_moveto(fz_context *ctx, void *s_, float x, float y)
+{
+ sctx *s = (sctx *)s_;
+
+ fz_stroke_flush(ctx, s, s->stroke->start_cap, s->stroke->end_cap);
+ fz_stroke_moveto(ctx, s, x, y);
+ s->cur.x = x;
+ s->cur.y = y;
+}
+
+static void
+stroke_lineto(fz_context *ctx, void *s_, float x, float y)
+{
+ sctx *s = (sctx *)s_;
+
+ fz_stroke_lineto(ctx, s, x, y, 0);
+ s->cur.x = x;
+ s->cur.y = y;
+}
+
+static void
+stroke_curveto(fz_context *ctx, void *s_, float x1, float y1, float x2, float y2, float x3, float y3)
+{
+ sctx *s = (sctx *)s_;
+
+ fz_stroke_bezier(ctx, s, s->cur.x, s->cur.y, x1, y1, x2, y2, x3, y3, 0);
+ s->cur.x = x3;
+ s->cur.y = y3;
+}
+
+static void
+stroke_quadto(fz_context *ctx, void *s_, float x1, float y1, float x2, float y2)
+{
+ sctx *s = (sctx *)s_;
+
+ fz_stroke_quad(ctx, s, s->cur.x, s->cur.y, x1, y1, x2, y2, 0);
+ s->cur.x = x2;
+ s->cur.y = y2;
+}
+
+static void
+stroke_close(fz_context *ctx, void *s_)
+{
+ sctx *s = (sctx *)s_;
+
+ fz_stroke_closepath(ctx, s);
+}
+
+static const fz_path_processor stroke_proc =
+{
+ stroke_moveto,
+ stroke_lineto,
+ stroke_curveto,
+ stroke_close,
+ stroke_quadto
+};
+
void
fz_flatten_stroke_path(fz_context *ctx, 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, k;
+ s.stroke = stroke;
s.gel = gel;
s.ctm = ctm;
s.flatness = flatness;
@@ -581,53 +764,15 @@ fz_flatten_stroke_path(fz_context *ctx, fz_gel *gel, fz_path *path, const fz_str
s.cap = stroke->start_cap;
- if (path->cmd_len > 0 && path->cmds[0] != FZ_MOVETO)
- return;
-
- 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_stroke_flush(ctx, &s, stroke->start_cap, stroke->end_cap);
- fz_stroke_moveto(ctx, &s, p1);
- p0 = p1;
- break;
-
- case FZ_LINETO:
- p1.x = path->coords[k++];
- p1.y = path->coords[k++];
- fz_stroke_lineto(ctx, &s, p1, 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_stroke_bezier(ctx, &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(ctx, &s);
- break;
- }
- }
+ s.cur.x = s.cur.y = 0;
+ s.stroke = stroke;
+ fz_process_path(ctx, &stroke_proc, &s, path);
fz_stroke_flush(ctx, &s, stroke->start_cap, stroke->end_cap);
}
static void
-fz_dash_moveto(fz_context *ctx, struct sctx *s, fz_point a, fz_linecap start_cap, fz_linecap end_cap)
+fz_dash_moveto(fz_context *ctx, struct sctx *s, float x, float y)
{
s->toggle = 1;
s->offset = 0;
@@ -642,107 +787,114 @@ fz_dash_moveto(fz_context *ctx, struct sctx *s, fz_point a, fz_linecap start_cap
s->offset = 0;
}
- s->cur = a;
+ s->dash_cur.x = x;
+ s->dash_cur.y = y;
if (s->toggle)
{
- fz_stroke_flush(ctx, s, s->cap, end_cap);
- s->cap = start_cap;
- fz_stroke_moveto(ctx, s, a);
+ fz_stroke_flush(ctx, s, s->cap, s->stroke->end_cap);
+ s->cap = s->stroke->start_cap;
+ fz_stroke_moveto(ctx, s, x, y);
}
}
static void
-fz_dash_lineto(fz_context *ctx, struct sctx *s, fz_point b, int dash_cap, int from_bezier)
+fz_dash_lineto(fz_context *ctx, struct sctx *s, float bx, float by, int from_bezier)
{
float dx, dy, d;
float total, used, ratio, tail;
- fz_point a;
- fz_point m;
- fz_point old_b;
+ float ax, ay;
+ float mx, my;
+ float old_bx, old_by;
int n;
+ int dash_cap = s->stroke->dash_cap;
- a = s->cur;
- dx = b.x - a.x;
- dy = b.y - a.y;
+ ax = s->dash_cur.x;
+ ay = s->dash_cur.y;
+ dx = bx - ax;
+ dy = by - ay;
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 ((d = s->rect.x0 - ax) > 0)
{
- if (b.x < s->rect.x0)
+ if (bx < s->rect.x0)
{
/* Entirely off screen */
tail = total;
- old_b = b;
+ old_bx = bx;
+ old_by = by;
goto adjust_for_tail;
}
- a.x = s->rect.x0; /* d > 0, dx > 0 */
+ ax = s->rect.x0; /* d > 0, dx > 0 */
goto a_moved_horizontally;
}
- else if (d < 0 && (d = (s->rect.x1 - a.x)) < 0)
+ else if (d < 0 && (d = (s->rect.x1 - ax)) < 0)
{
- if (b.x > s->rect.x1)
+ if (bx > s->rect.x1)
{
/* Entirely off screen */
tail = total;
- old_b = b;
+ old_bx = bx;
+ old_by = by;
goto adjust_for_tail;
}
- a.x = s->rect.x1; /* d < 0, dx < 0 */
+ ax = s->rect.x1; /* d < 0, dx < 0 */
a_moved_horizontally: /* d and dx have the same sign */
- a.y += dy * d/dx;
+ ay += dy * d/dx;
used = total * d/dx;
total -= used;
- dx = b.x - a.x;
- dy = b.y - a.y;
+ dx = bx - ax;
+ dy = by - ay;
}
/* Then vertically... */
- if ((d = s->rect.y0 - a.y) > 0)
+ if ((d = s->rect.y0 - ay) > 0)
{
- if (b.y < s->rect.y0)
+ if (by < s->rect.y0)
{
/* Entirely off screen */
tail = total;
- old_b = b;
+ old_bx = bx;
+ old_by = by;
goto adjust_for_tail;
}
- a.y = s->rect.y0; /* d > 0, dy > 0 */
+ ay = s->rect.y0; /* d > 0, dy > 0 */
goto a_moved_vertically;
}
- else if (d < 0 && (d = (s->rect.y1 - a.y)) < 0)
+ else if (d < 0 && (d = (s->rect.y1 - ay)) < 0)
{
- if (b.y > s->rect.y1)
+ if (by > s->rect.y1)
{
/* Entirely off screen */
tail = total;
- old_b = b;
+ old_bx = bx;
+ old_by = by;
goto adjust_for_tail;
}
- a.y = s->rect.y1; /* d < 0, dy < 0 */
+ ay = s->rect.y1; /* d < 0, dy < 0 */
a_moved_vertically: /* d and dy have the same sign */
- a.x += dx * d/dy;
+ ax += dx * d/dy;
d = total * d/dy;
total -= d;
used += d;
- dx = b.x - a.x;
- dy = b.y - a.y;
+ dx = bx - ax;
+ dy = by - ay;
}
if (used != 0.0f)
{
/* Update the position in the dash array */
if (s->toggle)
{
- fz_stroke_lineto(ctx, s, a, from_bezier);
+ fz_stroke_lineto(ctx, s, ax, ay, from_bezier);
}
else
{
- fz_stroke_flush(ctx, s, s->cap, dash_cap);
- s->cap = dash_cap;
- fz_stroke_moveto(ctx, s, a);
+ fz_stroke_flush(ctx, s, s->cap, s->stroke->dash_cap);
+ s->cap = s->stroke->dash_cap;
+ fz_stroke_moveto(ctx, s, ax, ay);
}
used += s->phase;
n = used/s->dash_total;
@@ -759,73 +911,77 @@ a_moved_vertically: /* d and dy have the same sign */
}
if (s->toggle)
{
- fz_stroke_lineto(ctx, s, a, from_bezier);
+ fz_stroke_lineto(ctx, s, ax, ay, from_bezier);
}
else
{
- fz_stroke_flush(ctx, s, s->cap, dash_cap);
- s->cap = dash_cap;
- fz_stroke_moveto(ctx, s, a);
+ fz_stroke_flush(ctx, s, s->cap, s->stroke->dash_cap);
+ s->cap = s->stroke->dash_cap;
+ fz_stroke_moveto(ctx, s, ax, ay);
}
s->phase = used;
used = 0;
}
- /* Now if b.x is off screen, bring it back */
- if ((d = b.x - s->rect.x0) < 0)
+ /* Now if bx is off screen, bring it back */
+ if ((d = bx - s->rect.x0) < 0)
{
- old_b = b;
- b.x = s->rect.x0; /* d < 0, dx < 0 */
+ old_bx = bx;
+ old_by = by;
+ bx = s->rect.x0; /* d < 0, dx < 0 */
goto b_moved_horizontally;
}
- else if (d > 0 && (d = (b.x - s->rect.x1)) > 0)
+ else if (d > 0 && (d = (bx - s->rect.x1)) > 0)
{
- old_b = b;
- b.x = s->rect.x1; /* d > 0, dx > 0 */
+ old_bx = bx;
+ old_by = by;
+ bx = s->rect.x1; /* d > 0, dx > 0 */
b_moved_horizontally: /* d and dx have the same sign */
- b.y -= dy * d/dx;
+ by -= dy * d/dx;
tail = total * d/dx;
total -= tail;
- dx = b.x - a.x;
- dy = b.y - a.y;
+ dx = bx - ax;
+ dy = by - ay;
}
/* Then vertically... */
- if ((d = b.y - s->rect.y0) < 0)
+ if ((d = by - s->rect.y0) < 0)
{
- old_b = b;
- b.y = s->rect.y0; /* d < 0, dy < 0 */
+ old_bx = bx;
+ old_by = by;
+ by = s->rect.y0; /* d < 0, dy < 0 */
goto b_moved_vertically;
}
- else if (d > 0 && (d = (b.y - s->rect.y1)) > 0)
+ else if (d > 0 && (d = (by - s->rect.y1)) > 0)
{
float t;
- old_b = b;
- b.y = s->rect.y1; /* d > 0, dy > 0 */
+ old_bx = bx;
+ old_by = by;
+ by = s->rect.y1; /* d > 0, dy > 0 */
b_moved_vertically: /* d and dy have the same sign */
- b.x -= dx * d/dy;
+ bx -= dx * d/dy;
t = total * d/dy;
tail += t;
total -= t;
- dx = b.x - a.x;
- dy = b.y - a.y;
+ dx = bx - ax;
+ dy = by - ay;
}
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;
+ mx = ax + ratio * dx;
+ my = ay + ratio * dy;
if (s->toggle)
{
- fz_stroke_lineto(ctx, s, m, from_bezier);
+ fz_stroke_lineto(ctx, s, mx, my, from_bezier);
}
else
{
fz_stroke_flush(ctx, s, s->cap, dash_cap);
s->cap = dash_cap;
- fz_stroke_moveto(ctx, s, m);
+ fz_stroke_moveto(ctx, s, mx, my);
}
s->toggle = !s->toggle;
@@ -839,27 +995,29 @@ b_moved_vertically: /* d and dy have the same sign */
if (tail == 0.0f)
{
- s->cur = b;
+ s->dash_cur.x = bx;
+ s->dash_cur.y = by;
if (s->toggle)
{
- fz_stroke_lineto(ctx, s, b, from_bezier);
+ fz_stroke_lineto(ctx, s, bx, by, from_bezier);
}
}
else
{
adjust_for_tail:
- s->cur = old_b;
+ s->dash_cur.x = old_bx;
+ s->dash_cur.y = old_by;
/* Update the position in the dash array */
if (s->toggle)
{
- fz_stroke_lineto(ctx, s, old_b, from_bezier);
+ fz_stroke_lineto(ctx, s, old_bx, old_by, from_bezier);
}
else
{
fz_stroke_flush(ctx, s, s->cap, dash_cap);
s->cap = dash_cap;
- fz_stroke_moveto(ctx, s, old_b);
+ fz_stroke_moveto(ctx, s, old_bx, old_by);
}
tail += s->phase;
n = tail/s->dash_total;
@@ -876,13 +1034,13 @@ adjust_for_tail:
}
if (s->toggle)
{
- fz_stroke_lineto(ctx, s, old_b, from_bezier);
+ fz_stroke_lineto(ctx, s, old_bx, old_by, from_bezier);
}
else
{
fz_stroke_flush(ctx, s, s->cap, dash_cap);
s->cap = dash_cap;
- fz_stroke_moveto(ctx, s, old_b);
+ fz_stroke_moveto(ctx, s, old_bx, old_by);
}
s->phase = tail;
}
@@ -893,8 +1051,7 @@ fz_dash_bezier(fz_context *ctx, struct sctx *s,
float xa, float ya,
float xb, float yb,
float xc, float yc,
- float xd, float yd, int depth,
- int dash_cap)
+ float xd, float yd, int depth)
{
float dmax;
float xab, yab;
@@ -911,10 +1068,7 @@ fz_dash_bezier(fz_context *ctx, struct sctx *s,
dmax = fz_max(dmax, fz_abs(yd - yc));
if (dmax < s->flatness || depth >= MAX_DEPTH)
{
- fz_point p;
- p.x = xd;
- p.y = yd;
- fz_dash_lineto(ctx, s, p, dash_cap, 1);
+ fz_dash_lineto(ctx, s, xd, yd, 1);
return;
}
@@ -942,19 +1096,117 @@ fz_dash_bezier(fz_context *ctx, struct sctx *s,
xabcd *= 0.125f; yabcd *= 0.125f;
- fz_dash_bezier(ctx, s, xa, ya, xab, yab, xabc, yabc, xabcd, yabcd, depth + 1, dash_cap);
- fz_dash_bezier(ctx, s, xabcd, yabcd, xbcd, ybcd, xcd, ycd, xd, yd, depth + 1, dash_cap);
+ fz_dash_bezier(ctx, s, xa, ya, xab, yab, xabc, yabc, xabcd, yabcd, depth + 1);
+ fz_dash_bezier(ctx, s, xabcd, yabcd, xbcd, ybcd, xcd, ycd, xd, yd, depth + 1);
+}
+
+static void
+fz_dash_quad(fz_context *ctx, struct sctx *s,
+ float xa, float ya,
+ float xb, float yb,
+ float xc, float yc, int depth)
+{
+ float dmax;
+ float xab, yab;
+ float xbc, ybc;
+ float xabc, yabc;
+
+ /* termination check */
+ dmax = fz_abs(xa - xb);
+ dmax = fz_max(dmax, fz_abs(ya - yb));
+ dmax = fz_max(dmax, fz_abs(xc - xb));
+ dmax = fz_max(dmax, fz_abs(yc - yb));
+ if (dmax < s->flatness || depth >= MAX_DEPTH)
+ {
+ fz_dash_lineto(ctx, s, xc, yc, 1);
+ return;
+ }
+
+ xab = xa + xb;
+ yab = ya + yb;
+ xbc = xb + xc;
+ ybc = yb + yc;
+
+ xabc = xab + xbc;
+ yabc = yab + ybc;
+
+ xab *= 0.5f; yab *= 0.5f;
+ xbc *= 0.5f; ybc *= 0.5f;
+
+ xabc *= 0.25f; yabc *= 0.25f;
+
+ fz_dash_quad(ctx, s, xa, ya, xab, yab, xabc, yabc, depth + 1);
+ fz_dash_quad(ctx, s, xabc, yabc, xbc, ybc, xc, yc, depth + 1);
+}
+
+static void
+dash_moveto(fz_context *ctx, void *s_, float x, float y)
+{
+ sctx *s = (sctx *)s_;
+
+ fz_dash_moveto(ctx, s, x, y);
+ s->dash_beg.x = s->cur.x = x;
+ s->dash_beg.y = s->cur.y = y;
+}
+
+static void
+dash_lineto(fz_context *ctx, void *s_, float x, float y)
+{
+ sctx *s = (sctx *)s_;
+
+ fz_dash_lineto(ctx, s, x, y, 0);
+ s->cur.x = x;
+ s->cur.y = y;
+}
+
+static void
+dash_curveto(fz_context *ctx, void *s_, float x1, float y1, float x2, float y2, float x3, float y3)
+{
+ sctx *s = (sctx *)s_;
+
+ fz_dash_bezier(ctx, s, s->cur.x, s->cur.y, x1, y1, x2, y2, x3, y3, 0);
+ s->cur.x = x3;
+ s->cur.y = y3;
+}
+
+static void
+dash_quadto(fz_context *ctx, void *s_, float x1, float y1, float x2, float y2)
+{
+ sctx *s = (sctx *)s_;
+
+ fz_dash_quad(ctx, s, s->cur.x, s->cur.y, x1, y1, x2, y2, 0);
+ s->cur.x = x2;
+ s->cur.y = y2;
+}
+
+static void
+dash_close(fz_context *ctx, void *s_)
+{
+ sctx *s = (sctx *)s_;
+
+ fz_dash_lineto(ctx, s, s->dash_beg.x, s->dash_beg.y, 0);
+ s->cur.x = s->dash_beg.x;
+ s->cur.y = s->dash_beg.y;
}
+static const fz_path_processor dash_proc =
+{
+ dash_moveto,
+ dash_lineto,
+ dash_curveto,
+ dash_close,
+ dash_quadto
+};
+
void
fz_flatten_dash_path(fz_context *ctx, 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;
+ int i;
fz_matrix inv;
+ s.stroke = stroke;
s.gel = gel;
s.ctm = ctm;
s.flatness = flatness;
@@ -974,9 +1226,6 @@ fz_flatten_dash_path(fz_context *ctx, fz_gel *gel, fz_path *path, const fz_strok
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];
@@ -999,44 +1248,7 @@ fz_flatten_dash_path(fz_context *ctx, fz_gel *gel, fz_path *path, const fz_strok
}
s.dash_total = phase_len;
- 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(ctx, &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(ctx, &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(ctx, &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(ctx, &s, beg, stroke->dash_cap, 0);
- p0 = p1 = beg;
- break;
- }
- }
-
+ s.cur.x = s.cur.y = 0;
+ fz_process_path(ctx, &dash_proc, &s, path);
fz_stroke_flush(ctx, &s, s.cap, stroke->end_cap);
}
diff --git a/source/fitz/font.c b/source/fitz/font.c
index 3d4a06e5..64cea107 100644
--- a/source/fitz/font.c
+++ b/source/fitz/font.c
@@ -892,18 +892,11 @@ static int conic_to(const FT_Vector *c, const FT_Vector *p, void *cc_)
fz_context *ctx = cc->ctx;
fz_path *path = cc->path;
fz_point ct, pt;
- fz_point s, c1, c2;
fz_transform_point_xy(&ct, &cc->trm, c->x, c->y);
fz_transform_point_xy(&pt, &cc->trm, p->x, p->y);
- s = fz_currentpoint(ctx, path);
- c1.x = (s.x + ct.x * 2) / 3;
- c1.y = (s.y + ct.y * 2) / 3;
- c2.x = (pt.x + ct.x * 2) / 3;
- c2.y = (pt.y + ct.y * 2) / 3;
-
- fz_curveto(ctx, path, c1.x, c1.y, c2.x, c2.y, pt.x, pt.y);
+ fz_quadto(ctx, path, ct.x, ct.y, pt.x, pt.y);
return 0;
}
diff --git a/source/fitz/path.c b/source/fitz/path.c
index 8deb85b8..fed574da 100644
--- a/source/fitz/path.c
+++ b/source/fitz/path.c
@@ -1,6 +1,54 @@
#include <assert.h>
#include "mupdf/fitz.h"
+// Thoughts for further optimisations:
+// All paths start with MoveTo. We could probably avoid most cases where
+// we store that. The next thing after a close must be a move.
+// Commands are MOVE, LINE, HORIZ, VERT, DEGEN, CURVE, CURVEV, CURVEY, QUAD, RECT.
+// We'd need to drop 2 to get us down to 3 bits.
+// Commands can be followed by CLOSE. Use 1 bit for close.
+// PDF 'RECT' implies close according to the spec, but I suspect
+// we can ignore this as filling closes implicitly.
+// We use a single bit in the path header to tell us whether we have
+// a trailing move. Trailing moves can always be stripped when path
+// construction completes.
+
+typedef enum fz_path_command_e
+{
+ FZ_MOVETO = 'M',
+ FZ_LINETO = 'L',
+ FZ_DEGENLINETO = 'D',
+ FZ_CURVETO = 'C',
+ FZ_CURVETOV = 'V',
+ FZ_CURVETOY = 'Y',
+ FZ_HORIZTO = 'H',
+ FZ_VERTTO = 'I',
+ FZ_QUADTO = 'Q',
+ FZ_RECTTO = 'R',
+ FZ_MOVETOCLOSE = 'm',
+ FZ_LINETOCLOSE = 'l',
+ FZ_DEGENLINETOCLOSE = 'd',
+ FZ_CURVETOCLOSE = 'c',
+ FZ_CURVETOVCLOSE = 'v',
+ FZ_CURVETOYCLOSE = 'y',
+ FZ_HORIZTOCLOSE = 'h',
+ FZ_VERTTOCLOSE = 'i',
+ FZ_QUADTOCLOSE = 'q',
+} fz_path_item_kind;
+
+struct fz_path_s
+{
+ int refs;
+ int cmd_len, cmd_cap;
+ unsigned char *cmds;
+ int coord_len, coord_cap;
+ float *coords;
+ fz_point current;
+ fz_point begin;
+};
+
+#define LAST_CMD(path) ((path)->cmd_len > 0 ? (path)->cmds[(path)->cmd_len-1] : 0)
+
fz_path *
fz_new_path(fz_context *ctx)
{
@@ -8,7 +56,6 @@ fz_new_path(fz_context *ctx)
path = fz_malloc_struct(ctx, fz_path);
path->refs = 1;
- path->last_cmd = 0;
path->current.x = 0;
path->current.y = 0;
path->begin.x = 0;
@@ -50,7 +97,6 @@ push_cmd(fz_context *ctx, fz_path *path, int cmd)
}
path->cmds[path->cmd_len++] = cmd;
- path->last_cmd = cmd;
}
static void
@@ -70,6 +116,24 @@ push_coord(fz_context *ctx, fz_path *path, float x, float y)
path->current.y = y;
}
+static void
+push_ord(fz_context *ctx, fz_path *path, float xy, int isx)
+{
+ if (path->coord_len + 1 >= path->coord_cap)
+ {
+ int new_coord_cap = fz_maxi(32, path->coord_cap * 2);
+ path->coords = fz_resize_array(ctx, path->coords, new_coord_cap, sizeof(float));
+ path->coord_cap = new_coord_cap;
+ }
+
+ path->coords[path->coord_len++] = xy;
+
+ if (isx)
+ path->current.x = xy;
+ else
+ path->current.y = xy;
+}
+
fz_point
fz_currentpoint(fz_context *ctx, fz_path *path)
{
@@ -79,7 +143,7 @@ fz_currentpoint(fz_context *ctx, fz_path *path)
void
fz_moveto(fz_context *ctx, fz_path *path, float x, float y)
{
- if (path->cmd_len > 0 && path->last_cmd == FZ_MOVETO)
+ if (path->cmd_len > 0 && LAST_CMD(path) == FZ_MOVETO)
{
/* Collapse moveto followed by moveto. */
path->coords[path->coord_len-2] = x;
@@ -108,12 +172,34 @@ fz_lineto(fz_context *ctx, fz_path *path, float x, float y)
return;
}
- /* Anything other than MoveTo followed by LineTo the same place is a nop */
- if (path->last_cmd != FZ_MOVETO && x0 == x && y0 == y)
+ /* (Anything other than MoveTo) followed by (LineTo the same place) is a nop */
+ if (LAST_CMD(path) != FZ_MOVETO && x0 == x && y0 == y)
return;
- push_cmd(ctx, path, FZ_LINETO);
- push_coord(ctx, path, x, y);
+ if (x0 == x)
+ {
+ if (y0 == y)
+ {
+ if (LAST_CMD(path) != FZ_MOVETO)
+ return;
+ push_cmd(ctx, path, FZ_DEGENLINETO);
+ }
+ else
+ {
+ push_cmd(ctx, path, FZ_VERTTO);
+ push_ord(ctx, path, y, 0);
+ }
+ }
+ else if (y0 == y)
+ {
+ push_cmd(ctx, path, FZ_HORIZTO);
+ push_ord(ctx, path, x, 1);
+ }
+ else
+ {
+ push_cmd(ctx, path, FZ_LINETO);
+ push_coord(ctx, path, x, y);
+ }
}
void
@@ -137,23 +223,29 @@ fz_curveto(fz_context *ctx, fz_path *path,
if (x2 == x3 && y2 == y3)
{
/* If (x1,y1)==(x2,y2) and prev wasn't a moveto, then skip */
- if (x1 == x2 && y1 == y2 && path->last_cmd != FZ_MOVETO)
+ if (x1 == x2 && y1 == y2 && LAST_CMD(path) != FZ_MOVETO)
return;
/* Otherwise a line will suffice */
fz_lineto(ctx, path, x3, y3);
- return;
}
- if (x1 == x2 && y1 == y2)
+ else if (x1 == x2 && y1 == y2)
{
/* A line will suffice */
fz_lineto(ctx, path, x3, y3);
- return;
}
+ else
+ fz_curvetov(ctx, path, x2, y2, x3, y3);
+ return;
}
- else if (x1 == x2 && y1 == y2 && x2 == x3 && y2 == y3)
+ else if (x2 == x3 && y2 == y3)
{
- /* A line will suffice */
- fz_lineto(ctx, path, x3, y3);
+ if (x1 == x2 && y1 == y2)
+ {
+ /* A line will suffice */
+ fz_lineto(ctx, path, x3, y3);
+ }
+ else
+ fz_curvetoy(ctx, path, x1, y1, x3, y3);
return;
}
@@ -164,40 +256,170 @@ fz_curveto(fz_context *ctx, fz_path *path,
}
void
+fz_quadto(fz_context *ctx, fz_path *path,
+ float x1, float y1,
+ float x2, float y2)
+{
+ float x0 = path->current.x;
+ float y0 = path->current.y;
+
+ if (path->cmd_len == 0)
+ {
+ fz_warn(ctx, "quadto with no current point");
+ return;
+ }
+
+ /* Check for degenerate cases: */
+ if ((x0 == x1 && y0 == y1) || (x1 == x2 && y1 == y2))
+ {
+ if (x0 == x2 && y0 == y2 && LAST_CMD(path) != FZ_MOVETO)
+ return;
+ /* A line will suffice */
+ fz_lineto(ctx, path, x2, y2);
+ return;
+ }
+
+ push_cmd(ctx, path, FZ_QUADTO);
+ push_coord(ctx, path, x1, y1);
+ push_coord(ctx, path, x2, y2);
+}
+
+void
fz_curvetov(fz_context *ctx, fz_path *path, float x2, float y2, float x3, float y3)
{
- float x1 = path->current.x;
- float y1 = path->current.y;
+ float x0 = path->current.x;
+ float y0 = path->current.y;
if (path->cmd_len == 0)
{
- fz_warn(ctx, "curvetov with no current point");
+ fz_warn(ctx, "curveto with no current point");
return;
}
- fz_curveto(ctx, path, x1, y1, x2, y2, x3, y3);
+ /* Check for degenerate cases: */
+ if (x2 == x3 && y2 == y3)
+ {
+ /* If (x0,y0)==(x2,y2) and prev wasn't a moveto, then skip */
+ if (x0 == x2 && y0 == y2 && LAST_CMD(path) != FZ_MOVETO)
+ return;
+ /* Otherwise a line will suffice */
+ fz_lineto(ctx, path, x3, y3);
+ }
+ else if (x0 == x2 && y0 == y2)
+ {
+ /* A line will suffice */
+ fz_lineto(ctx, path, x3, y3);
+ }
+
+ push_cmd(ctx, path, FZ_CURVETOV);
+ push_coord(ctx, path, x2, y2);
+ push_coord(ctx, path, x3, y3);
}
void
fz_curvetoy(fz_context *ctx, fz_path *path, float x1, float y1, float x3, float y3)
{
- fz_curveto(ctx, path, x1, y1, x3, y3, x3, y3);
+ float x0 = path->current.x;
+ float y0 = path->current.y;
+
+ if (path->cmd_len == 0)
+ {
+ fz_warn(ctx, "curveto with no current point");
+ return;
+ }
+
+ /* Check for degenerate cases: */
+ if (x1 == x3 && y1 == y3)
+ {
+ /* If (x0,y0)==(x1,y1) and prev wasn't a moveto, then skip */
+ if (x0 == x1 && y0 == y1 && LAST_CMD(path) != FZ_MOVETO)
+ return;
+ /* Otherwise a line will suffice */
+ fz_lineto(ctx, path, x3, y3);
+ }
+
+ push_cmd(ctx, path, FZ_CURVETOY);
+ push_coord(ctx, path, x1, y1);
+ push_coord(ctx, path, x3, y3);
}
void
fz_closepath(fz_context *ctx, fz_path *path)
{
+ uint8_t rep;
+
if (path->cmd_len == 0)
{
fz_warn(ctx, "closepath with no current point");
return;
}
- /* CLOSE following a CLOSE is a NOP */
- if (path->last_cmd == FZ_CLOSE_PATH)
+ switch(LAST_CMD(path))
+ {
+ case FZ_MOVETO:
+ rep = FZ_MOVETOCLOSE;
+ break;
+ case FZ_LINETO:
+ rep = FZ_LINETOCLOSE;
+ break;
+ case FZ_DEGENLINETO:
+ rep = FZ_DEGENLINETOCLOSE;
+ break;
+ case FZ_CURVETO:
+ rep = FZ_CURVETOCLOSE;
+ break;
+ case FZ_CURVETOV:
+ rep = FZ_CURVETOVCLOSE;
+ break;
+ case FZ_CURVETOY:
+ rep = FZ_CURVETOYCLOSE;
+ break;
+ case FZ_HORIZTO:
+ rep = FZ_HORIZTOCLOSE;
+ break;
+ case FZ_VERTTO:
+ rep = FZ_VERTTOCLOSE;
+ break;
+ case FZ_QUADTO:
+ rep = FZ_QUADTOCLOSE;
+ break;
+ case FZ_RECTTO:
+ /* RectTo implies close */
+ return;
+ case FZ_MOVETOCLOSE:
+ case FZ_LINETOCLOSE:
+ case FZ_DEGENLINETOCLOSE:
+ case FZ_CURVETOCLOSE:
+ case FZ_CURVETOVCLOSE:
+ case FZ_CURVETOYCLOSE:
+ case FZ_HORIZTOCLOSE:
+ case FZ_VERTTOCLOSE:
+ case FZ_QUADTOCLOSE:
+ /* CLOSE following a CLOSE is a NOP */
return;
+ case 0:
+ /* Closing an empty path is a NOP */
+ return;
+ }
+
+ path->cmds[path->cmd_len-1] = rep;
+
+ path->current = path->begin;
+}
+
+void
+fz_rectto(fz_context *ctx, fz_path *path, float x1, float y1, float x2, float y2)
+{
+ if (path->cmd_len > 0 && LAST_CMD(path) == FZ_MOVETO)
+ {
+ /* Collapse moveto followed by rectto. */
+ path->coord_len -= 2;
+ path->cmd_len--;
+ }
- push_cmd(ctx, path, FZ_CLOSE_PATH);
+ push_cmd(ctx, path, FZ_RECTTO);
+ push_coord(ctx, path, x1, y1);
+ push_coord(ctx, path, x2, y2);
path->current = path->begin;
}
@@ -211,67 +433,334 @@ static inline fz_rect *bound_expand(fz_rect *r, const fz_point *p)
return r;
}
-fz_rect *
-fz_bound_path(fz_context *ctx, fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm, fz_rect *r)
+void fz_process_path(fz_context *ctx, const fz_path_processor *proc, void *arg, const fz_path *path)
{
- fz_point p;
- int i = 0, k = 0;
-
- /* If the path is empty, return the empty rectangle here - don't wait
- * for it to be expanded in the stroked case below.
- * A path must start with a moveto - and if that's all there is
- * then the path is empty. */
- if (path->cmd_len == 0 || path->cmd_len == 1)
- {
- *r = fz_empty_rect;
- return r;
- }
+ int i, k;
+ float x, y, sx, sy;
- /* Initial moveto point */
- p.x = path->coords[0];
- p.y = path->coords[1];
- fz_transform_point(&p, ctm);
- r->x0 = r->x1 = p.x;
- r->y0 = r->y1 = p.y;
+ if (path->cmd_len == 0)
+ return;
- while (i < path->cmd_len)
+ for (k=0, i = 0; i < path->cmd_len; i++)
{
- switch (path->cmds[i++])
+ uint8_t cmd = path->cmds[i];
+
+ switch (cmd)
{
case FZ_CURVETO:
- p.x = path->coords[k++];
- p.y = path->coords[k++];
- bound_expand(r, fz_transform_point(&p, ctm));
- p.x = path->coords[k++];
- p.y = path->coords[k++];
- bound_expand(r, fz_transform_point(&p, ctm));
- p.x = path->coords[k++];
- p.y = path->coords[k++];
- bound_expand(r, fz_transform_point(&p, ctm));
+ case FZ_CURVETOCLOSE:
+ proc->curveto(ctx, arg,
+ path->coords[k],
+ path->coords[k+1],
+ path->coords[k+2],
+ path->coords[k+3],
+ x = path->coords[k+4],
+ y = path->coords[k+5]);
+ k += 6;
+ if (cmd == FZ_CURVETOCLOSE)
+ {
+ if (proc->close)
+ proc->close(ctx, arg);
+ x = sx;
+ y = sy;
+ }
+ break;
+ case FZ_CURVETOV:
+ case FZ_CURVETOVCLOSE:
+ if (proc->curvetov)
+ proc->curvetov(ctx, arg,
+ path->coords[k],
+ path->coords[k+1],
+ x = path->coords[k+2],
+ y = path->coords[k+3]);
+ else
+ {
+ proc->curveto(ctx, arg,
+ x,
+ y,
+ path->coords[k],
+ path->coords[k+1],
+ path->coords[k+2],
+ path->coords[k+3]);
+ x = path->coords[k+2];
+ y = path->coords[k+3];
+ }
+ k += 4;
+ if (cmd == FZ_CURVETOVCLOSE)
+ {
+ if (proc->close)
+ proc->close(ctx, arg);
+ x = sx;
+ y = sy;
+ }
+ break;
+ case FZ_CURVETOY:
+ case FZ_CURVETOYCLOSE:
+ if (proc->curvetoy)
+ proc->curvetoy(ctx, arg,
+ path->coords[k],
+ path->coords[k+1],
+ x = path->coords[k+2],
+ y = path->coords[k+3]);
+ else
+ proc->curveto(ctx, arg,
+ path->coords[k],
+ path->coords[k+1],
+ path->coords[k+2],
+ path->coords[k+3],
+ x = path->coords[k+2],
+ y = path->coords[k+3]);
+ k += 4;
+ if (cmd == FZ_CURVETOYCLOSE)
+ {
+ if (proc->close)
+ proc->close(ctx, arg);
+ x = sx;
+ y = sy;
+ }
+ break;
+ case FZ_QUADTO:
+ case FZ_QUADTOCLOSE:
+ if (proc->quadto)
+ proc->quadto(ctx, arg,
+ path->coords[k],
+ path->coords[k+1],
+ x = path->coords[k+2],
+ y = path->coords[k+3]);
+ else
+ {
+ float c2x = path->coords[k] * 2;
+ float c2y = path->coords[k+1] * 2;
+ float c1x = (x + c2x) / 3;
+ float c1y = (y + c2y) / 3;
+ x = path->coords[k+2];
+ y = path->coords[k+3];
+ c2x = (c2x + x) / 3;
+ c2y = (c2y + y) / 3;
+
+ proc->curveto(ctx, arg,
+ c1x,
+ c1y,
+ c2x,
+ c2y,
+ x,
+ y);
+ }
+ k += 4;
+ if (cmd == FZ_QUADTOCLOSE)
+ {
+ if (proc->close)
+ proc->close(ctx, arg);
+ x = sx;
+ y = sy;
+ }
break;
case FZ_MOVETO:
- if (k + 2 == path->coord_len)
+ case FZ_MOVETOCLOSE:
+ proc->moveto(ctx, arg,
+ x = path->coords[k],
+ y = path->coords[k+1]);
+ k += 2;
+ sx = x;
+ sy = y;
+ if (cmd == FZ_MOVETOCLOSE)
{
- /* Trailing Moveto - cannot affect bbox */
- k += 2;
- break;
+ if (proc->close)
+ proc->close(ctx, arg);
+ x = sx;
+ y = sy;
}
- /* fallthrough */
+ break;
case FZ_LINETO:
- p.x = path->coords[k++];
- p.y = path->coords[k++];
- bound_expand(r, fz_transform_point(&p, ctm));
+ case FZ_LINETOCLOSE:
+ proc->lineto(ctx, arg,
+ x = path->coords[k],
+ y = path->coords[k+1]);
+ k += 2;
+ if (cmd == FZ_LINETOCLOSE)
+ {
+ if (proc->close)
+ proc->close(ctx, arg);
+ x = sx;
+ y = sy;
+ }
break;
- case FZ_CLOSE_PATH:
+ case FZ_HORIZTO:
+ case FZ_HORIZTOCLOSE:
+ proc->lineto(ctx, arg,
+ x = path->coords[k],
+ y);
+ k += 1;
+ if (cmd == FZ_HORIZTOCLOSE)
+ {
+ if (proc->close)
+ proc->close(ctx, arg);
+ x = sx;
+ y = sy;
+ }
+ break;
+ case FZ_VERTTO:
+ case FZ_VERTTOCLOSE:
+ proc->lineto(ctx, arg,
+ x,
+ y = path->coords[k]);
+ k += 1;
+ if (cmd == FZ_VERTTOCLOSE)
+ {
+ if (proc->close)
+ proc->close(ctx, arg);
+ x = sx;
+ y = sy;
+ }
+ break;
+ case FZ_DEGENLINETO:
+ case FZ_DEGENLINETOCLOSE:
+ proc->lineto(ctx, arg,
+ x,
+ y);
+ if (cmd == FZ_DEGENLINETOCLOSE)
+ {
+ if (proc->close)
+ proc->close(ctx, arg);
+ x = sx;
+ y = sy;
+ }
+ break;
+ case FZ_RECTTO:
+ if (proc->rectto)
+ {
+ proc->rectto(ctx, arg,
+ x = path->coords[k],
+ y = path->coords[k+1],
+ path->coords[k+2],
+ path->coords[k+3]);
+ }
+ else
+ {
+ proc->moveto(ctx, arg,
+ x = path->coords[k],
+ y = path->coords[k+1]);
+ proc->lineto(ctx, arg,
+ path->coords[k+2],
+ path->coords[k+1]);
+ proc->lineto(ctx, arg,
+ path->coords[k+2],
+ path->coords[k+3]);
+ proc->lineto(ctx, arg,
+ path->coords[k],
+ path->coords[k+3]);
+ if (proc->close)
+ proc->close(ctx, arg);
+ }
+ sx = x;
+ sy = y;
+ k += 4;
break;
}
}
+}
+
+typedef struct
+{
+ const fz_matrix *ctm;
+ fz_rect rect;
+ fz_point move;
+ int trailing_move;
+ int first;
+} bound_path_arg;
+
+static void
+bound_moveto(fz_context *ctx, void *arg_, float x, float y)
+{
+ bound_path_arg *arg = (bound_path_arg *)arg_;
+
+ arg->move.x = x;
+ arg->move.y = y;
+ fz_transform_point(&arg->move, arg->ctm);
+ arg->trailing_move = 1;
+}
+
+static void
+bound_lineto(fz_context *ctx, void *arg_, float x, float y)
+{
+ bound_path_arg *arg = (bound_path_arg *)arg_;
+ fz_point p;
+
+ p.x = x;
+ p.y = y;
+ fz_transform_point(&p, arg->ctm);
+ if (arg->first)
+ {
+ arg->rect.x0 = arg->rect.x1 = p.x;
+ arg->rect.y0 = arg->rect.y1 = p.y;
+ arg->first = 0;
+ }
+ else
+ bound_expand(&arg->rect, &p);
+
+ if (arg->trailing_move)
+ {
+ arg->trailing_move = 0;
+ bound_expand(&arg->rect, &arg->move);
+ }
+}
+
+static void
+bound_curveto(fz_context *ctx, void *arg_, float x1, float y1, float x2, float y2, float x3, float y3)
+{
+ bound_path_arg *arg = (bound_path_arg *)arg_;
+ fz_point p;
+
+ p.x = x1;
+ p.y = y1;
+ fz_transform_point(&p, arg->ctm);
+ if (arg->first)
+ {
+ arg->rect.x0 = arg->rect.x1 = p.x;
+ arg->rect.y0 = arg->rect.y1 = p.y;
+ arg->first = 0;
+ }
+ else
+ bound_expand(&arg->rect, &p);
+ p.x = x2;
+ p.y = y2;
+ bound_expand(&arg->rect, fz_transform_point(&p, arg->ctm));
+ p.x = x3;
+ p.y = y3;
+ bound_expand(&arg->rect, fz_transform_point(&p, arg->ctm));
+ if (arg->trailing_move)
+ {
+ arg->trailing_move = 0;
+ bound_expand(&arg->rect, &arg->move);
+ }
+}
+
+static const fz_path_processor bound_path_proc =
+{
+ bound_moveto,
+ bound_lineto,
+ bound_curveto,
+ NULL
+};
+
+fz_rect *
+fz_bound_path(fz_context *ctx, fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm, fz_rect *r)
+{
+ bound_path_arg arg;
+
+ arg.ctm = ctm;
+ arg.rect = fz_empty_rect;
+ arg.trailing_move = 0;
+ arg.first = 1;
- if (stroke)
+ fz_process_path(ctx, &bound_path_proc, &arg, path);
+
+ if (!arg.first && stroke)
{
- fz_adjust_rect_for_stroke(ctx, r, stroke, ctm);
+ fz_adjust_rect_for_stroke(ctx, &arg.rect, stroke, ctm);
}
+ *r = arg.rect;
return r;
}
@@ -300,9 +789,371 @@ fz_adjust_rect_for_stroke(fz_context *ctx, fz_rect *r, const fz_stroke_state *st
void
fz_transform_path(fz_context *ctx, fz_path *path, const fz_matrix *ctm)
{
- int i;
- for (i = 0; i < path->coord_len; i += 2)
- fz_transform_point((fz_point *)&path->coords[i], ctm);
+ int i, k, n;
+ fz_point p, p1, p2, p3, q, s;
+
+ if (ctm->b == 0 && ctm->c == 0)
+ {
+ /* Simple, in place transform */
+ i = 0;
+ k = 0;
+ while (i < path->cmd_len)
+ {
+ uint8_t cmd = path->cmds[i];
+
+ switch (cmd)
+ {
+ case FZ_MOVETO:
+ case FZ_LINETO:
+ case FZ_MOVETOCLOSE:
+ case FZ_LINETOCLOSE:
+ n = 1;
+ break;
+ case FZ_DEGENLINETO:
+ case FZ_DEGENLINETOCLOSE:
+ n = 0;
+ break;
+ case FZ_CURVETO:
+ case FZ_CURVETOCLOSE:
+ n = 3;
+ break;
+ case FZ_RECTTO:
+ s.x = path->coords[k];
+ s.y = path->coords[k+1];
+ n = 2;
+ break;
+ case FZ_CURVETOV:
+ case FZ_CURVETOY:
+ case FZ_QUADTO:
+ case FZ_CURVETOVCLOSE:
+ case FZ_CURVETOYCLOSE:
+ case FZ_QUADTOCLOSE:
+ n = 2;
+ break;
+ case FZ_HORIZTO:
+ case FZ_HORIZTOCLOSE:
+ q.x = path->coords[k];
+ p = q;
+ fz_transform_point(&p, ctm);
+ path->coords[k++] = p.x;
+ n = 0;
+ break;
+ case FZ_VERTTO:
+ case FZ_VERTTOCLOSE:
+ q.y = path->coords[k];
+ p = q;
+ fz_transform_point(&p, ctm);
+ path->coords[k++] = p.y;
+ n = 0;
+ break;
+ default:
+ assert("Unknown path cmd" == NULL);
+ }
+ while (n > 0)
+ {
+ q.x = path->coords[k];
+ q.y = path->coords[k+1];
+ p = q;
+ fz_transform_point(&p, ctm);
+ path->coords[k++] = p.x;
+ path->coords[k++] = p.y;
+ n--;
+ }
+ switch (cmd)
+ {
+ case FZ_MOVETO:
+ case FZ_MOVETOCLOSE:
+ s = q;
+ break;
+ case FZ_LINETOCLOSE:
+ case FZ_DEGENLINETOCLOSE:
+ case FZ_CURVETOCLOSE:
+ case FZ_CURVETOVCLOSE:
+ case FZ_CURVETOYCLOSE:
+ case FZ_QUADTOCLOSE:
+ case FZ_HORIZTOCLOSE:
+ case FZ_VERTTOCLOSE:
+ case FZ_RECTTO:
+ q = s;
+ break;
+ }
+ i++;
+ }
+ }
+ else if (ctm->a == 0 && ctm->d == 0)
+ {
+ /* In place transform with command rewriting */
+ i = 0;
+ k = 0;
+ while (i < path->cmd_len)
+ {
+ uint8_t cmd = path->cmds[i];
+
+ switch (cmd)
+ {
+ case FZ_MOVETO:
+ case FZ_LINETO:
+ case FZ_MOVETOCLOSE:
+ case FZ_LINETOCLOSE:
+ n = 1;
+ break;
+ case FZ_DEGENLINETO:
+ case FZ_DEGENLINETOCLOSE:
+ n = 0;
+ break;
+ case FZ_CURVETO:
+ case FZ_CURVETOCLOSE:
+ n = 3;
+ break;
+ case FZ_RECTTO:
+ s.x = path->coords[k];
+ s.y = path->coords[k+1];
+ n = 2;
+ break;
+ case FZ_CURVETOV:
+ case FZ_CURVETOY:
+ case FZ_QUADTO:
+ case FZ_CURVETOVCLOSE:
+ case FZ_CURVETOYCLOSE:
+ case FZ_QUADTOCLOSE:
+ n = 2;
+ break;
+ case FZ_HORIZTO:
+ q.x = path->coords[k];
+ p = q;
+ fz_transform_point(&p, ctm);
+ path->coords[k++] = p.y;
+ path->cmds[i] = FZ_VERTTO;
+ n = 0;
+ break;
+ case FZ_HORIZTOCLOSE:
+ q.x = path->coords[k];
+ p = q;
+ fz_transform_point(&p, ctm);
+ path->coords[k++] = p.y;
+ path->cmds[i] = FZ_VERTTOCLOSE;
+ n = 0;
+ break;
+ case FZ_VERTTO:
+ q.y = path->coords[k];
+ p = q;
+ fz_transform_point(&p, ctm);
+ path->coords[k++] = p.x;
+ path->cmds[i] = FZ_HORIZTO;
+ n = 0;
+ break;
+ case FZ_VERTTOCLOSE:
+ q.y = path->coords[k];
+ p = q;
+ fz_transform_point(&p, ctm);
+ path->coords[k++] = p.x;
+ path->cmds[i] = FZ_HORIZTOCLOSE;
+ n = 0;
+ break;
+ default:
+ assert("Unknown path cmd" == NULL);
+ }
+ while (n > 0)
+ {
+ p.x = path->coords[k];
+ p.y = path->coords[k+1];
+ q = p;
+ fz_transform_point(&p, ctm);
+ path->coords[k++] = p.x;
+ path->coords[k++] = p.y;
+ n--;
+ }
+ switch (cmd)
+ {
+ case FZ_MOVETO:
+ case FZ_MOVETOCLOSE:
+ s = q;
+ break;
+ case FZ_LINETOCLOSE:
+ case FZ_DEGENLINETOCLOSE:
+ case FZ_CURVETOCLOSE:
+ case FZ_CURVETOVCLOSE:
+ case FZ_CURVETOYCLOSE:
+ case FZ_QUADTOCLOSE:
+ case FZ_HORIZTOCLOSE:
+ case FZ_VERTTOCLOSE:
+ case FZ_RECTTO:
+ q = s;
+ break;
+ }
+ i++;
+ }
+ }
+ else
+ {
+ int extra_coord = 0;
+ int extra_cmd = 0;
+ int coord_read, coord_write, cmd_read, cmd_write;
+
+ /* General case. Have to allow for rects/horiz/verts
+ * becoming non-rects/horiz/verts. */
+ for (i = 0; i < path->cmd_len; i++)
+ {
+ uint8_t cmd = path->cmds[i];
+ switch (cmd)
+ {
+ case FZ_HORIZTO:
+ case FZ_VERTTO:
+ case FZ_HORIZTOCLOSE:
+ case FZ_VERTTOCLOSE:
+ extra_coord += 1;
+ break;
+ case FZ_RECTTO:
+ extra_coord += 2;
+ extra_cmd += 3;
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+ }
+ if (path->cmd_len + extra_cmd < path->cmd_cap)
+ {
+ path->cmds = fz_resize_array(ctx, path->cmds, path->cmd_len + extra_cmd, sizeof(unsigned char));
+ path->cmd_cap = path->cmd_len + extra_cmd;
+ }
+ if (path->coord_len + extra_coord < path->coord_cap)
+ {
+ path->coords = fz_resize_array(ctx, path->coords, path->coord_len + extra_coord, sizeof(float));
+ path->coord_cap = path->coord_len + extra_coord;
+ }
+ memmove(path->cmds + extra_cmd, path->cmds, path->cmd_len * sizeof(unsigned char));
+ path->cmd_len += extra_cmd;
+ memmove(path->coords + extra_coord, path->coords, path->coord_len * sizeof(float));
+ path->coord_len += extra_coord;
+
+ for (cmd_write = 0, cmd_read = extra_cmd, coord_write = 0, coord_read = extra_coord; cmd_read < path->cmd_len; i += 2)
+ {
+ uint8_t cmd = path->cmds[cmd_write++] = path->cmds[cmd_read++];
+
+ switch (cmd)
+ {
+ case FZ_MOVETO:
+ case FZ_LINETO:
+ case FZ_MOVETOCLOSE:
+ case FZ_LINETOCLOSE:
+ n = 1;
+ break;
+ case FZ_DEGENLINETO:
+ case FZ_DEGENLINETOCLOSE:
+ n = 0;
+ break;
+ case FZ_CURVETO:
+ case FZ_CURVETOCLOSE:
+ n = 3;
+ break;
+ case FZ_CURVETOV:
+ case FZ_CURVETOY:
+ case FZ_QUADTO:
+ case FZ_CURVETOVCLOSE:
+ case FZ_CURVETOYCLOSE:
+ case FZ_QUADTOCLOSE:
+ n = 2;
+ break;
+ case FZ_RECTTO:
+ p.x = path->coords[coord_read++];
+ p.y = path->coords[coord_read++];
+ p2.x = path->coords[coord_read++];
+ p2.y = path->coords[coord_read++];
+ p1.x = p2.x;
+ p1.y = p.y;
+ p3.x = p.x;
+ p3.y = p2.y;
+ s = p;
+ fz_transform_point(&p, ctm);
+ fz_transform_point(&p1, ctm);
+ fz_transform_point(&p2, ctm);
+ fz_transform_point(&p3, ctm);
+ path->coords[coord_write++] = p.x;
+ path->coords[coord_write++] = p.y;
+ path->coords[coord_write++] = p1.x;
+ path->coords[coord_write++] = p1.y;
+ path->coords[coord_write++] = p2.x;
+ path->coords[coord_write++] = p2.y;
+ path->coords[coord_write++] = p3.x;
+ path->coords[coord_write++] = p3.y;
+ path->cmds[cmd_write-1] = FZ_MOVETO;
+ path->cmds[cmd_write++] = FZ_LINETO;
+ path->cmds[cmd_write++] = FZ_LINETO;
+ path->cmds[cmd_write++] = FZ_LINETOCLOSE;
+ n = 0;
+ break;
+ case FZ_HORIZTO:
+ q.x = path->coords[coord_read++];
+ p = q;
+ fz_transform_point(&p, ctm);
+ path->coords[coord_write++] = p.x;
+ path->coords[coord_write++] = p.y;
+ path->cmds[cmd_write-1] = FZ_LINETO;
+ n = 0;
+ break;
+ case FZ_HORIZTOCLOSE:
+ p.x = path->coords[coord_read++];
+ p.y = q.y;
+ fz_transform_point(&p, ctm);
+ path->coords[coord_write++] = p.x;
+ path->coords[coord_write++] = p.y;
+ path->cmds[cmd_write-1] = FZ_LINETOCLOSE;
+ q = s;
+ n = 0;
+ break;
+ case FZ_VERTTO:
+ q.y = path->coords[coord_read++];
+ p = q;
+ fz_transform_point(&p, ctm);
+ path->coords[coord_write++] = p.x;
+ path->coords[coord_write++] = p.y;
+ path->cmds[cmd_write-1] = FZ_LINETO;
+ n = 0;
+ break;
+ case FZ_VERTTOCLOSE:
+ p.x = q.x;
+ p.y = path->coords[coord_read++];
+ fz_transform_point(&p, ctm);
+ path->coords[coord_write++] = p.x;
+ path->coords[coord_write++] = p.y;
+ path->cmds[cmd_write-1] = FZ_LINETOCLOSE;
+ q = s;
+ n = 0;
+ break;
+ default:
+ assert("Unknown path cmd" == NULL);
+ }
+ while (n > 0)
+ {
+ p.x = path->coords[coord_read++];
+ p.y = path->coords[coord_read++];
+ q = p;
+ fz_transform_point(&p, ctm);
+ path->coords[coord_write++] = p.x;
+ path->coords[coord_write++] = p.y;
+ n--;
+ }
+ switch (cmd)
+ {
+ case FZ_MOVETO:
+ case FZ_MOVETOCLOSE:
+ s = q;
+ break;
+ case FZ_LINETOCLOSE:
+ case FZ_DEGENLINETOCLOSE:
+ case FZ_CURVETOCLOSE:
+ case FZ_CURVETOYCLOSE:
+ case FZ_CURVETOVCLOSE:
+ case FZ_QUADTOCLOSE:
+ case FZ_HORIZTOCLOSE:
+ case FZ_VERTTOCLOSE:
+ case FZ_RECTTO:
+ q = s;
+ break;
+ }
+ }
+ }
}
void fz_trim_path(fz_context *ctx, fz_path *path)
@@ -328,20 +1179,39 @@ fz_print_path(fz_context *ctx, FILE *out, fz_path *path, int indent)
int n;
while (i < path->cmd_len)
{
+ uint8_t cmd = path->cmds[i++];
+
for (n = 0; n < indent; n++)
fputc(' ', out);
- switch (path->cmds[i++])
+ switch (cmd)
{
case FZ_MOVETO:
+ case FZ_MOVETOCLOSE:
x = path->coords[k++];
y = path->coords[k++];
- fprintf(out, "%g %g m\n", x, y);
+ fprintf(out, "%g %g m%s\n", x, y, cmd == FZ_MOVETOCLOSE ? " z" : "");
break;
case FZ_LINETO:
+ case FZ_LINETOCLOSE:
x = path->coords[k++];
y = path->coords[k++];
- fprintf(out, "%g %g l\n", x, y);
+ fprintf(out, "%g %g l%s\n", x, y, cmd == FZ_LINETOCLOSE ? " z" : "");
+ break;
+ case FZ_DEGENLINETO:
+ case FZ_DEGENLINETOCLOSE:
+ fprintf(out, "d%s\n", cmd == FZ_DEGENLINETOCLOSE ? " z" : "");
+ break;
+ case FZ_HORIZTO:
+ case FZ_HORIZTOCLOSE:
+ x = path->coords[k++];
+ fprintf(out, "%g h%s\n", x, cmd == FZ_HORIZTOCLOSE ? " z" : "");
break;
+ case FZ_VERTTOCLOSE:
+ case FZ_VERTTO:
+ y = path->coords[k++];
+ fprintf(out, "%g i%s\n", y, cmd == FZ_VERTTOCLOSE ? " z" : "");
+ break;
+ case FZ_CURVETOCLOSE:
case FZ_CURVETO:
x = path->coords[k++];
y = path->coords[k++];
@@ -351,10 +1221,26 @@ fz_print_path(fz_context *ctx, FILE *out, fz_path *path, int indent)
fprintf(out, "%g %g ", x, y);
x = path->coords[k++];
y = path->coords[k++];
- fprintf(out, "%g %g c\n", x, y);
+ fprintf(out, "%g %g c%s\n", x, y, cmd == FZ_CURVETOCLOSE ? " z" : "");
+ break;
+ case FZ_CURVETOVCLOSE:
+ case FZ_CURVETOV:
+ case FZ_CURVETOYCLOSE:
+ case FZ_CURVETOY:
+ x = path->coords[k++];
+ y = path->coords[k++];
+ fprintf(out, "%g %g ", x, y);
+ x = path->coords[k++];
+ y = path->coords[k++];
+ fprintf(out, "%g %g %c%s\n", x, y, (cmd == FZ_CURVETOVCLOSE || cmd == FZ_CURVETOV ? 'v' : 'y'), (cmd == FZ_CURVETOVCLOSE || cmd == FZ_CURVETOYCLOSE) ? " z" : "");
break;
- case FZ_CLOSE_PATH:
- fprintf(out, "h\n");
+ case FZ_RECTTO:
+ x = path->coords[k++];
+ y = path->coords[k++];
+ fprintf(out, "%g %g ", x, y);
+ x = path->coords[k++];
+ y = path->coords[k++];
+ fprintf(out, "%g %g r\n", x, y);
break;
}
}
diff --git a/source/fitz/svg-device.c b/source/fitz/svg-device.c
index 4345c225..4461f79e 100644
--- a/source/fitz/svg-device.c
+++ b/source/fitz/svg-device.c
@@ -88,43 +88,51 @@ end_def(fz_context *ctx, svg_device *sdev)
/* Helper functions */
static void
+svg_path_moveto(fz_context *ctx, void *arg, float x, float y)
+{
+ fz_output *out = (fz_output *)arg;
+
+ fz_printf(ctx, out, "M %g %g ", x, y);
+}
+
+static void
+svg_path_lineto(fz_context *ctx, void *arg, float x, float y)
+{
+ fz_output *out = (fz_output *)arg;
+
+ fz_printf(ctx, out, "L %g %g ", x, y);
+}
+
+static void
+svg_path_curveto(fz_context *ctx, void *arg, float x1, float y1, float x2, float y2, float x3, float y3)
+{
+ fz_output *out = (fz_output *)arg;
+
+ fz_printf(ctx, out, "C %g %g %g %g %g %g ", x1, y1, x2, y2, x3, y3);
+}
+
+static void
+svg_path_close(fz_context *ctx, void *arg)
+{
+ fz_output *out = (fz_output *)arg;
+
+ fz_printf(ctx, out, "Z ");
+}
+
+static const fz_path_processor svg_path_proc =
+{
+ svg_path_moveto,
+ svg_path_lineto,
+ svg_path_curveto,
+ svg_path_close
+};
+
+static void
svg_dev_path(fz_context *ctx, svg_device *sdev, fz_path *path)
{
- fz_output *out = sdev->out;
- float x, y;
- int i, k;
- fz_printf(ctx, out, " d=\"");
- for (i = 0, k = 0; i < path->cmd_len; i++)
- {
- switch (path->cmds[i])
- {
- case FZ_MOVETO:
- x = path->coords[k++];
- y = path->coords[k++];
- fz_printf(ctx, out, "M %g %g ", x, y);
- break;
- case FZ_LINETO:
- x = path->coords[k++];
- y = path->coords[k++];
- fz_printf(ctx, out, "L %g %g ", x, y);
- break;
- case FZ_CURVETO:
- x = path->coords[k++];
- y = path->coords[k++];
- fz_printf(ctx, out, "C %g %g ", x, y);
- x = path->coords[k++];
- y = path->coords[k++];
- fz_printf(ctx, out, "%g %g ", x, y);
- x = path->coords[k++];
- y = path->coords[k++];
- fz_printf(ctx, out, "%g %g ", x, y);
- break;
- case FZ_CLOSE_PATH:
- fz_printf(ctx, out, "Z ");
- break;
- }
- }
- fz_printf(ctx, out, "\"");
+ fz_printf(ctx, sdev->out, " d=\"");
+ fz_process_path(ctx, &svg_path_proc, sdev->out, path);
+ fz_printf(ctx, sdev->out, "\"");
}
static void
diff --git a/source/fitz/trace-device.c b/source/fitz/trace-device.c
index 97dd4f79..105f7e6b 100644
--- a/source/fitz/trace-device.c
+++ b/source/fitz/trace-device.c
@@ -27,42 +27,62 @@ fz_trace_color(fz_colorspace *colorspace, float *color, float alpha)
}
static void
-fz_trace_path(fz_path *path, int indent)
+trace_moveto(fz_context *ctx, void *arg, float x, float y)
{
- float x, y;
- int i = 0, k = 0, n;
- while (i < path->cmd_len)
- {
- for (n = 0; n < indent; n++)
- putchar(' ');
- switch (path->cmds[i++])
- {
- case FZ_MOVETO:
- x = path->coords[k++];
- y = path->coords[k++];
- printf("<moveto x=\"%g\" y=\"%g\"/>\n", x, y);
- break;
- case FZ_LINETO:
- x = path->coords[k++];
- y = path->coords[k++];
- printf("<lineto x=\"%g\" y=\"%g\"/>\n", x, y);
- break;
- case FZ_CURVETO:
- x = path->coords[k++];
- y = path->coords[k++];
- printf("<curveto x1=\"%g\" y1=\"%g\"", x, y);
- x = path->coords[k++];
- y = path->coords[k++];
- printf(" x2=\"%g\" y2=\"%g\"", x, y);
- x = path->coords[k++];
- y = path->coords[k++];
- printf(" x3=\"%g\" y3=\"%g\"/>\n", x, y);
- break;
- case FZ_CLOSE_PATH:
- printf("<closepath/>\n");
- break;
- }
- }
+ int indent = (int)(intptr_t)arg;
+ int n;
+
+ for (n = 0; n < indent; n++)
+ putchar(' ');
+ printf("<moveto x=\"%g\" y=\"%g\"/>\n", x, y);
+}
+
+static void
+trace_lineto(fz_context *ctx, void *arg, float x, float y)
+{
+ int indent = (int)(intptr_t)arg;
+ int n;
+
+ for (n = 0; n < indent; n++)
+ putchar(' ');
+ printf("<lineto x=\"%g\" y=\"%g\"/>\n", x, y);
+}
+
+static void
+trace_curveto(fz_context *ctx, void *arg, float x1, float y1, float x2, float y2, float x3, float y3)
+{
+ int indent = (int)(intptr_t)arg;
+ int n;
+
+ for (n = 0; n < indent; n++)
+ putchar(' ');
+ printf("<curveto x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\" x3=\"%g\" y3=\"%g\"/>\n", x1, y1, x2, y2, x3, y3);
+}
+
+static void
+trace_close(fz_context *ctx, void *arg)
+{
+ int indent = (int)(intptr_t)arg;
+ int n;
+
+ for (n = 0; n < indent; n++)
+ putchar(' ');
+ printf("<closepath/>\n");
+}
+
+
+static const fz_path_processor trace_path_proc =
+{
+ trace_moveto,
+ trace_lineto,
+ trace_curveto,
+ trace_close
+};
+
+static void
+fz_trace_path(fz_context *ctx, fz_path *path, int indent)
+{
+ fz_process_path(ctx, &trace_path_proc, (void *)(intptr_t)indent, path);
}
static void
@@ -91,7 +111,7 @@ fz_trace_fill_path(fz_context *ctx, fz_device *dev, fz_path *path, int even_odd,
fz_trace_color(colorspace, color, alpha);
fz_trace_matrix(ctm);
printf(">\n");
- fz_trace_path(path, 0);
+ fz_trace_path(ctx, path, 0);
printf("</fill_path>\n");
}
@@ -119,7 +139,7 @@ fz_trace_stroke_path(fz_context *ctx, fz_device *dev, fz_path *path, fz_stroke_s
fz_trace_matrix(ctm);
printf(">\n");
- fz_trace_path(path, 0);
+ fz_trace_path(ctx, path, 0);
printf("</stroke_path>\n");
}
@@ -137,7 +157,7 @@ fz_trace_clip_path(fz_context *ctx, fz_device *dev, fz_path *path, const fz_rect
printf(" contentbbox=\"%g %g %g %g\">\n", rect->x0, rect->y0, rect->x1, rect->y1);
else
printf(">\n");
- fz_trace_path(path, 0);
+ fz_trace_path(ctx, path, 0);
printf("</clip_path>\n");
}
@@ -147,7 +167,7 @@ fz_trace_clip_stroke_path(fz_context *ctx, fz_device *dev, fz_path *path, const
printf("<clip_stroke_path");
fz_trace_matrix(ctm);
printf(">\n");
- fz_trace_path(path, 0);
+ fz_trace_path(ctx, path, 0);
printf("</clip_stroke_path>\n");
}
diff --git a/source/pdf/pdf-device.c b/source/pdf/pdf-device.c
index 553810f6..e3b63dc5 100644
--- a/source/pdf/pdf-device.c
+++ b/source/pdf/pdf-device.c
@@ -360,42 +360,58 @@ pdf_dev_stroke_state(fz_context *ctx, pdf_device *pdev, fz_stroke_state *stroke_
gs->stroke_state = fz_keep_stroke_state(ctx, stroke_state);
}
+typedef struct
+{
+ fz_context *ctx;
+ fz_buffer *buf;
+} pdf_dev_path_arg;
+
+static void
+pdf_dev_path_moveto(fz_context *ctx, void *arg, float x, float y)
+{
+ fz_buffer *buf = (fz_buffer *)arg;
+
+ fz_buffer_printf(ctx, buf, "%f %f m\n", x, y);
+}
+
+static void
+pdf_dev_path_lineto(fz_context *ctx, void *arg, float x, float y)
+{
+ fz_buffer *buf = (fz_buffer *)arg;
+
+ fz_buffer_printf(ctx, buf, "%f %f l\n", x, y);
+}
+
+static void
+pdf_dev_path_curveto(fz_context *ctx, void *arg, float x1, float y1, float x2, float y2, float x3, float y3)
+{
+ fz_buffer *buf = (fz_buffer *)arg;
+
+ fz_buffer_printf(ctx, buf, "%f %f %f %f %f %f c\n", x1, y1, x2, y2, x3, y3);
+}
+
+static void
+pdf_dev_path_close(fz_context *ctx, void *arg)
+{
+ fz_buffer *buf = (fz_buffer *)arg;
+
+ fz_buffer_printf(ctx, buf, "h\n");
+}
+
+static const fz_path_processor pdf_dev_path_proc =
+{
+ pdf_dev_path_moveto,
+ pdf_dev_path_lineto,
+ pdf_dev_path_curveto,
+ pdf_dev_path_close
+};
+
static void
pdf_dev_path(fz_context *ctx, pdf_device *pdev, fz_path *path)
{
gstate *gs = CURRENT_GSTATE(pdev);
- float x, y;
- int i = 0, k = 0;
- while (i < path->cmd_len)
- {
- switch (path->cmds[i++])
- {
- case FZ_MOVETO:
- x = path->coords[k++];
- y = path->coords[k++];
- fz_buffer_printf(ctx, gs->buf, "%f %f m\n", x, y);
- break;
- case FZ_LINETO:
- x = path->coords[k++];
- y = path->coords[k++];
- fz_buffer_printf(ctx, gs->buf, "%f %f l\n", x, y);
- break;
- case FZ_CURVETO:
- x = path->coords[k++];
- y = path->coords[k++];
- fz_buffer_printf(ctx, gs->buf, "%f %f ", x, y);
- x = path->coords[k++];
- y = path->coords[k++];
- fz_buffer_printf(ctx, gs->buf, "%f %f ", x, y);
- x = path->coords[k++];
- y = path->coords[k++];
- fz_buffer_printf(ctx, gs->buf, "%f %f c\n", x, y);
- break;
- case FZ_CLOSE_PATH:
- fz_buffer_printf(ctx, gs->buf, "h\n");
- break;
- }
- }
+
+ fz_process_path(ctx, &pdf_dev_path_proc, (void *)gs->buf, path);
}
static void
diff --git a/source/pdf/pdf-op-run.c b/source/pdf/pdf-op-run.c
index 2bdd3b55..e153dbd1 100644
--- a/source/pdf/pdf-op-run.c
+++ b/source/pdf/pdf-op-run.c
@@ -1516,11 +1516,7 @@ static void pdf_run_h(fz_context *ctx, pdf_processor *proc)
static void pdf_run_re(fz_context *ctx, pdf_processor *proc, float x, float y, float w, float h)
{
pdf_run_processor *pr = (pdf_run_processor *)proc;
- fz_moveto(ctx, pr->path, x, y);
- fz_lineto(ctx, pr->path, x + w, y);
- fz_lineto(ctx, pr->path, x + w, y + h);
- fz_lineto(ctx, pr->path, x, y + h);
- fz_closepath(ctx, pr->path);
+ fz_rectto(ctx, pr->path, x, y, x+w, y+h);
}
/* path painting */
diff --git a/source/xps/xps-path.c b/source/xps/xps-path.c
index e1245a9a..8c352272 100644
--- a/source/xps/xps-path.c
+++ b/source/xps/xps-path.c
@@ -397,15 +397,11 @@ xps_parse_abbreviated_geometry(fz_context *ctx, xps_document *doc, char *geom, i
case 'Q':
if (i + 3 >= n) break;
- pt = fz_currentpoint(ctx, path);
x1 = fz_atof(args[i+0]);
y1 = fz_atof(args[i+1]);
x2 = fz_atof(args[i+2]);
y2 = fz_atof(args[i+3]);
- fz_curveto(ctx, path,
- (pt.x + 2 * x1) / 3, (pt.y + 2 * y1) / 3,
- (x2 + 2 * x1) / 3, (y2 + 2 * y1) / 3,
- x2, y2);
+ fz_quadto(ctx, path, x1, y1, x2, y2);
i += 4;
break;
case 'q':
@@ -415,10 +411,7 @@ xps_parse_abbreviated_geometry(fz_context *ctx, xps_document *doc, char *geom, i
y1 = fz_atof(args[i+1]) + pt.y;
x2 = fz_atof(args[i+2]) + pt.x;
y2 = fz_atof(args[i+3]) + pt.y;
- fz_curveto(ctx, path,
- (pt.x + 2 * x1) / 3, (pt.y + 2 * y1) / 3,
- (x2 + 2 * x1) / 3, (y2 + 2 * y1) / 3,
- x2, y2);
+ fz_quadto(ctx, path, x1, y1, x2, y2);
i += 4;
break;