/* Draw an arc segment transformed by the matrix, we approximate with straight * line segments. We cannot use the fz_arc function because they only draw * circular arcs, we need to transform the line to make them elliptical but * without transforming the line width. * * We are guaranteed that on entry the point is at the point that would be * calculated by th0, and on exit, a point is generated for us at th0. */ static void xps_draw_arc_segment(fz_context *ctx, xps_document *doc, fz_path *path, fz_matrix mtx, float th0, float th1, int iscw) { float t, d; fz_point p; while (th1 < th0) th1 += FZ_PI * 2; d = FZ_PI / 180; /* 1-degree precision */ if (iscw) { for (t = th0 + d; t < th1 - d/2; t += d) { p = fz_transform_point_xy(cosf(t), sinf(t), mtx); fz_lineto(ctx, path, p.x, p.y); } } else { th0 += FZ_PI * 2; for (t = th0 - d; t > th1 + d/2; t -= d) { p = fz_transform_point_xy(cosf(t), sinf(t), mtx); fz_lineto(ctx, path, p.x, p.y); } } }
/* Draw an arc segment transformed by the matrix, we approximate with straight * line segments. We cannot use the fz_arc function because they only draw * circular arcs, we need to transform the line to make them elliptical but * without transforming the line width. * * We are guaranteed that on entry the point is at the point that would be * calculated by th0, and on exit, a point is generated for us at th0. */ static void xps_draw_arc_segment(fz_context *doc, fz_path *path, const fz_matrix *mtx, float th0, float th1, int iscw) { float t, d; fz_point p; while (th1 < th0) th1 += (float)M_PI * 2; d = (float)M_PI / 180; /* 1-degree precision */ if (iscw) { for (t = th0 + d; t < th1 - d/2; t += d) { p.x = cosf(t); p.y = sinf(t); fz_transform_point(&p, mtx); fz_lineto(doc, path, p.x, p.y); } } else { th0 += (float)M_PI * 2; for (t = th0 - d; t > th1 + d/2; t -= d) { p.x = cosf(t); p.y = sinf(t); fz_transform_point(&p, mtx); fz_lineto(doc, path, p.x, p.y); } } }
static void svg_add_arc_segment(fz_context *ctx, fz_path *path, const fz_matrix *mtx, float th0, float th1, int iscw) { float t, d; fz_point p; while (th1 < th0) th1 += FZ_PI * 2; d = FZ_PI / 180; /* 1-degree precision */ if (iscw) { for (t = th0 + d; t < th1 - d/2; t += d) { fz_transform_point_xy(&p, mtx, cosf(t), sinf(t)); fz_lineto(ctx, path, p.x, p.y); } } else { th0 += FZ_PI * 2; for (t = th0 - d; t > th1 + d/2; t -= d) { fz_transform_point_xy(&p, mtx, cosf(t), sinf(t)); fz_lineto(ctx, path, p.x, p.y); } } }
void fz_curveto(fz_context *ctx, fz_path *path, float x1, float y1, float x2, float y2, float x3, float y3) { float x0, y0; if (path->last < 0) { fz_warn(ctx, "curveto with no current point"); return; } if (path->items[path->last].k == FZ_CLOSE_PATH) { x0 = path->items[path->last-2].v; y0 = path->items[path->last-1].v; } else { x0 = path->items[path->len-2].v; y0 = path->items[path->len-1].v; } /* Check for degenerate cases: */ if (x0 == x1 && y0 == y1) { if (x2 == x3 && y2 == y3) { /* If (x1,y1)==(x2,y2) and prev wasn't a moveto, then skip */ if (x1 == x2 && y1 == y2 && path->items[path->last].k != FZ_MOVETO) return; /* Otherwise a line will suffice */ fz_lineto(ctx, path, x3, y3); return; } if (x1 == x2 && y1 == y2) { /* A line will suffice */ fz_lineto(ctx, path, x3, y3); return; } } else if (x1 == x2 && y1 == y2 && x2 == x3 && y2 == y3) { /* A line will suffice */ fz_lineto(ctx, path, x3, y3); return; } grow_path(ctx, path, 7); path->items[path->len++].k = FZ_CURVETO; path->items[path->len++].v = x1; path->items[path->len++].v = y1; path->items[path->len++].v = x2; path->items[path->len++].v = y2; path->items[path->len++].v = x3; path->items[path->len++].v = y3; }
static void draw_rect(fz_context *ctx, fz_device *dev, const fz_matrix *ctm, float *rgba, float x0, float y0, float x1, float y1) { fz_path *path = fz_new_path(ctx); fz_moveto(ctx, path, x0, y0); fz_lineto(ctx, path, x1, y0); fz_lineto(ctx, path, x1, y1); fz_lineto(ctx, path, x0, y1); fz_closepath(ctx, path); fz_fill_path(ctx, dev, path, 0, ctm, fz_device_rgb(ctx), rgba, rgba[3]); fz_drop_path(ctx, path); }
static void xps_paint_tiling_brush_clipped(xps_document *doc, const fz_matrix *ctm, const fz_rect *viewbox, struct closure *c) { fz_path *path = fz_new_path(doc->ctx); fz_moveto(doc->ctx, path, viewbox->x0, viewbox->y0); fz_lineto(doc->ctx, path, viewbox->x0, viewbox->y1); fz_lineto(doc->ctx, path, viewbox->x1, viewbox->y1); fz_lineto(doc->ctx, path, viewbox->x1, viewbox->y0); fz_closepath(doc->ctx, path); fz_clip_path(doc->dev, path, NULL, 0, ctm); fz_free_path(doc->ctx, path); c->func(doc, ctm, viewbox, c->base_uri, c->dict, c->root, c->user); fz_pop_clip(doc->dev); }
static void xps_paint_tiling_brush_clipped(xps_context *ctx, fz_matrix ctm, fz_rect viewbox, struct closure *c) { fz_path *path = fz_new_path(); fz_moveto(path, viewbox.x0, viewbox.y0); fz_lineto(path, viewbox.x0, viewbox.y1); fz_lineto(path, viewbox.x1, viewbox.y1); fz_lineto(path, viewbox.x1, viewbox.y0); fz_closepath(path); fz_clip_path(ctx->dev, path, NULL, 0, ctm); fz_free_path(path); c->func(ctx, ctm, viewbox, c->base_uri, c->dict, c->root, c->user); fz_pop_clip(ctx->dev); }
static void svg_run_line(fz_context *ctx, fz_device *dev, svg_document *doc, fz_xml *node, const svg_state *inherit_state) { svg_state local_state = *inherit_state; char *x1_att = fz_xml_att(node, "x1"); char *y1_att = fz_xml_att(node, "y1"); char *x2_att = fz_xml_att(node, "x2"); char *y2_att = fz_xml_att(node, "y2"); float x1 = 0; float y1 = 0; float x2 = 0; float y2 = 0; svg_parse_common(ctx, doc, node, &local_state); if (x1_att) x1 = svg_parse_length(x1_att, local_state.viewbox_w, local_state.fontsize); if (y1_att) y1 = svg_parse_length(y1_att, local_state.viewbox_h, local_state.fontsize); if (x2_att) x2 = svg_parse_length(x2_att, local_state.viewbox_w, local_state.fontsize); if (y2_att) y2 = svg_parse_length(y2_att, local_state.viewbox_h, local_state.fontsize); if (local_state.stroke_is_set) { fz_path *path = fz_new_path(ctx); fz_moveto(ctx, path, x1, y1); fz_lineto(ctx, path, x2, y2); svg_stroke(ctx, dev, doc, path, &local_state); fz_drop_path(ctx, path); } }
static void xps_paint_tiling_brush_clipped(xps_document *doc, const fz_matrix *ctm, const fz_rect *viewbox, struct closure *c) { fz_path *path = fz_new_path(doc->ctx); fz_rect rect; fz_moveto(doc->ctx, path, viewbox->x0, viewbox->y0); fz_lineto(doc->ctx, path, viewbox->x0, viewbox->y1); fz_lineto(doc->ctx, path, viewbox->x1, viewbox->y1); fz_lineto(doc->ctx, path, viewbox->x1, viewbox->y0); fz_closepath(doc->ctx, path); /* SumatraPDF: try to match rendering with and without display list */ fz_clip_path(doc->dev, path, fz_bound_path(doc->ctx, path, NULL, ctm, &rect), 0, ctm); fz_free_path(doc->ctx, path); c->func(doc, ctm, viewbox, c->base_uri, c->dict, c->root, c->user); fz_pop_clip(doc->dev); }
static void xps_paint_tiling_brush_clipped(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, const fz_rect *viewbox, struct closure *c) { fz_device *dev = doc->dev; fz_path *path = fz_new_path(ctx); fz_moveto(ctx, path, viewbox->x0, viewbox->y0); fz_lineto(ctx, path, viewbox->x0, viewbox->y1); fz_lineto(ctx, path, viewbox->x1, viewbox->y1); fz_lineto(ctx, path, viewbox->x1, viewbox->y0); fz_closepath(ctx, path); fz_clip_path(ctx, dev, path, 0, ctm, NULL); fz_drop_path(ctx, path); c->func(ctx, doc, ctm, viewbox, c->base_uri, c->dict, c->root, c->user); fz_pop_clip(ctx, dev); }
static void xps_parse_poly_line_segment(fz_context *doc, fz_path *path, fz_xml *root, int stroking, int *skipped_stroke) { char *points_att = fz_xml_att(root, "Points"); char *is_stroked_att = fz_xml_att(root, "IsStroked"); int is_stroked; float x, y; char *s; if (!points_att) { fz_warn(doc, "PolyLineSegment element has no points"); return; } is_stroked = 1; if (is_stroked_att && !strcmp(is_stroked_att, "false")) is_stroked = 0; if (!is_stroked) *skipped_stroke = 1; s = points_att; while (*s != 0) { while (*s == ' ') s++; s = xps_parse_point(s, &x, &y); if (stroking && !is_stroked) fz_moveto(doc, path, x, y); else fz_lineto(doc, path, x, y); } }
void fz_curveto(fz_context *ctx, fz_path *path, float x1, float y1, float x2, float y2, float x3, float 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 (x0 == x1 && y0 == y1) { 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) return; /* Otherwise a line will suffice */ fz_lineto(ctx, path, x3, y3); return; } if (x1 == x2 && y1 == y2) { /* A line will suffice */ fz_lineto(ctx, path, x3, y3); return; } } else if (x1 == x2 && y1 == y2 && x2 == x3 && y2 == y3) { /* A line will suffice */ fz_lineto(ctx, path, x3, y3); return; } push_cmd(ctx, path, FZ_CURVETO); push_coord(ctx, path, x1, y1); push_coord(ctx, path, x2, y2); push_coord(ctx, path, x3, y3); }
static void xps_parse_path_figure(fz_context *doc, fz_path *path, fz_xml *root, int stroking) { fz_xml *node; char *is_closed_att; char *start_point_att; char *is_filled_att; int is_closed = 0; int is_filled = 1; float start_x = 0; float start_y = 0; int skipped_stroke = 0; is_closed_att = fz_xml_att(root, "IsClosed"); start_point_att = fz_xml_att(root, "StartPoint"); is_filled_att = fz_xml_att(root, "IsFilled"); if (is_closed_att) is_closed = !strcmp(is_closed_att, "true"); if (is_filled_att) is_filled = !strcmp(is_filled_att, "true"); if (start_point_att) xps_parse_point(start_point_att, &start_x, &start_y); if (!stroking && !is_filled) /* not filled, when filling */ return; fz_moveto(doc, path, start_x, start_y); for (node = fz_xml_down(root); node; node = fz_xml_next(node)) { if (!strcmp(fz_xml_tag(node), "ArcSegment")) xps_parse_arc_segment(doc, path, node, stroking, &skipped_stroke); if (!strcmp(fz_xml_tag(node), "PolyBezierSegment")) xps_parse_poly_bezier_segment(doc, path, node, stroking, &skipped_stroke); if (!strcmp(fz_xml_tag(node), "PolyLineSegment")) xps_parse_poly_line_segment(doc, path, node, stroking, &skipped_stroke); if (!strcmp(fz_xml_tag(node), "PolyQuadraticBezierSegment")) xps_parse_poly_quadratic_bezier_segment(doc, path, node, stroking, &skipped_stroke); } if (is_closed) { if (stroking && skipped_stroke) fz_lineto(doc, path, start_x, start_y); /* we've skipped using fz_moveto... */ else fz_closepath(doc, path); /* no skipped segments, safe to closepath properly */ } }
static void draw_rect(fz_context *ctx, fz_device *dev, const fz_matrix *ctm, fz_css_color color, float x0, float y0, float x1, float y1) { if (color.a > 0) { float rgb[3]; fz_path *path = fz_new_path(ctx); fz_moveto(ctx, path, x0, y0); fz_lineto(ctx, path, x1, y0); fz_lineto(ctx, path, x1, y1); fz_lineto(ctx, path, x0, y1); fz_closepath(ctx, path); rgb[0] = color.r / 255.0f; rgb[1] = color.g / 255.0f; rgb[2] = color.b / 255.0f; fz_fill_path(ctx, dev, path, 0, ctm, fz_device_rgb(ctx), rgb, color.a / 255.0f); fz_drop_path(ctx, path); } }
static fz_path * svg_parse_polygon_imp(fz_context *ctx, svg_document *doc, fz_xml *node, int doclose) { fz_path *path; const char *str = fz_xml_att(node, "points"); float number; float args[2]; int nargs; int isfirst; if (!str) return NULL; isfirst = 1; nargs = 0; path = fz_new_path(ctx); while (*str) { while (svg_is_whitespace_or_comma(*str)) str ++; if (svg_is_digit(*str)) { str = svg_lex_number(&number, str); args[nargs++] = number; } if (nargs == 2) { if (isfirst) { fz_moveto(ctx, path, args[0], args[1]); isfirst = 0; } else { fz_lineto(ctx, path, args[0], args[1]); } nargs = 0; } } return path; }
/* Some explaination of the parameters here is warranted. See: http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes Add an arc segment to path, that describes a section of an elliptical arc from the current point of path to (point_x,point_y), such that: The arc segment is taken from an elliptical arc of semi major radius size_x, semi minor radius size_y, where the semi major axis of the ellipse is rotated by rotation_angle. If is_large_arc, then the arc segment is selected to be > 180 degrees. If is_clockwise, then the arc sweeps clockwise. */ static void xps_draw_arc(fz_context *doc, fz_path *path, float size_x, float size_y, float rotation_angle, int is_large_arc, int is_clockwise, float point_x, float point_y) { fz_matrix rotmat, revmat; fz_matrix mtx; fz_point pt; float rx, ry; float x1, y1, x2, y2; float x1t, y1t; float cxt, cyt, cx, cy; float t1, t2, t3; float sign; float th1, dth; pt = fz_currentpoint(doc, path); x1 = pt.x; y1 = pt.y; x2 = point_x; y2 = point_y; rx = size_x; ry = size_y; if (is_clockwise != is_large_arc) sign = 1; else sign = -1; fz_rotate(&rotmat, rotation_angle); fz_rotate(&revmat, -rotation_angle); /* http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes */ /* Conversion from endpoint to center parameterization */ /* F.6.6.1 -- ensure radii are positive and non-zero */ rx = fabsf(rx); ry = fabsf(ry); if (rx < 0.001f || ry < 0.001f || (x1 == x2 && y1 == y2)) { fz_lineto(doc, path, x2, y2); return; } /* F.6.5.1 */ pt.x = (x1 - x2) / 2; pt.y = (y1 - y2) / 2; fz_transform_vector(&pt, &revmat); x1t = pt.x; y1t = pt.y; /* F.6.6.2 -- ensure radii are large enough */ t1 = (x1t * x1t) / (rx * rx) + (y1t * y1t) / (ry * ry); if (t1 > 1) { rx = rx * sqrtf(t1); ry = ry * sqrtf(t1); } /* F.6.5.2 */ t1 = (rx * rx * ry * ry) - (rx * rx * y1t * y1t) - (ry * ry * x1t * x1t); t2 = (rx * rx * y1t * y1t) + (ry * ry * x1t * x1t); t3 = t1 / t2; /* guard against rounding errors; sqrt of negative numbers is bad for your health */ if (t3 < 0) t3 = 0; t3 = sqrtf(t3); cxt = sign * t3 * (rx * y1t) / ry; cyt = sign * t3 * -(ry * x1t) / rx; /* F.6.5.3 */ pt.x = cxt; pt.y = cyt; fz_transform_vector(&pt, &rotmat); cx = pt.x + (x1 + x2) / 2; cy = pt.y + (y1 + y2) / 2; /* F.6.5.4 */ { fz_point coord1, coord2, coord3, coord4; coord1.x = 1; coord1.y = 0; coord2.x = (x1t - cxt) / rx; coord2.y = (y1t - cyt) / ry; coord3.x = (x1t - cxt) / rx; coord3.y = (y1t - cyt) / ry; coord4.x = (-x1t - cxt) / rx; coord4.y = (-y1t - cyt) / ry; th1 = angle_between(coord1, coord2); dth = angle_between(coord3, coord4); if (dth < 0 && !is_clockwise) dth += (((float)M_PI / 180) * 360); if (dth > 0 && is_clockwise) dth -= (((float)M_PI / 180) * 360); } fz_pre_scale(fz_pre_rotate(fz_translate(&mtx, cx, cy), rotation_angle), rx, ry); xps_draw_arc_segment(doc, path, &mtx, th1, th1 + dth, is_clockwise); fz_lineto(doc, path, point_x, point_y); }
static void svg_run_rect(fz_context *ctx, fz_device *dev, svg_document *doc, fz_xml *node, const svg_state *inherit_state) { svg_state local_state = *inherit_state; char *x_att = fz_xml_att(node, "x"); char *y_att = fz_xml_att(node, "y"); char *w_att = fz_xml_att(node, "width"); char *h_att = fz_xml_att(node, "height"); char *rx_att = fz_xml_att(node, "rx"); char *ry_att = fz_xml_att(node, "ry"); float x = 0; float y = 0; float w = 0; float h = 0; float rx = 0; float ry = 0; fz_path *path; svg_parse_common(ctx, doc, node, &local_state); if (x_att) x = svg_parse_length(x_att, local_state.viewbox_w, local_state.fontsize); if (y_att) y = svg_parse_length(y_att, local_state.viewbox_h, local_state.fontsize); if (w_att) w = svg_parse_length(w_att, local_state.viewbox_w, local_state.fontsize); if (h_att) h = svg_parse_length(h_att, local_state.viewbox_h, local_state.fontsize); if (rx_att) rx = svg_parse_length(rx_att, local_state.viewbox_w, local_state.fontsize); if (ry_att) ry = svg_parse_length(ry_att, local_state.viewbox_h, local_state.fontsize); if (rx_att && !ry_att) ry = rx; if (ry_att && !rx_att) rx = ry; if (rx > w * 0.5) rx = w * 0.5; if (ry > h * 0.5) ry = h * 0.5; if (w <= 0 || h <= 0) return; path = fz_new_path(ctx); if (rx == 0 || ry == 0) { fz_moveto(ctx, path, x, y); fz_lineto(ctx, path, x + w, y); fz_lineto(ctx, path, x + w, y + h); fz_lineto(ctx, path, x, y + h); } else { float rxs = rx * MAGIC_CIRCLE; float rys = rx * MAGIC_CIRCLE; fz_moveto(ctx, path, x + w - rx, y); fz_curveto(ctx, path, x + w - rxs, y, x + w, y + rys, x + w, y + ry); fz_lineto(ctx, path, x + w, y + h - ry); fz_curveto(ctx, path, x + w, y + h - rys, x + w - rxs, y + h, x + w - rx, y + h); fz_lineto(ctx, path, x + rx, y + h); fz_curveto(ctx, path, x + rxs, y + h, x, y + h - rys, x, y + h - rx); fz_lineto(ctx, path, x, y + rx); fz_curveto(ctx, path, x, y + rxs, x + rxs, y, x + rx, y); } fz_closepath(ctx, path); svg_draw_path(ctx, dev, doc, path, &local_state); fz_drop_path(ctx, path); }
static fz_path * svg_parse_path_data(fz_context *ctx, svg_document *doc, const char *str) { fz_path *path = fz_new_path(ctx); fz_point p; float x1, y1, x2, y2; int cmd; float number; float args[6]; int nargs; /* saved control point for smooth curves */ int reset_smooth = 1; float smooth_x = 0.0; float smooth_y = 0.0; cmd = 0; nargs = 0; fz_try(ctx) { fz_moveto(ctx, path, 0.0, 0.0); /* for the case of opening 'm' */ while (*str) { while (svg_is_whitespace_or_comma(*str)) str ++; if (svg_is_digit(*str)) { str = svg_lex_number(&number, str); if (nargs == 6) fz_throw(ctx, FZ_ERROR_GENERIC, "stack overflow in path data"); args[nargs++] = number; } else if (svg_is_alpha(*str)) { if (nargs != 0) fz_throw(ctx, FZ_ERROR_GENERIC, "syntax error in path data (wrong number of parameters to '%c')", cmd); cmd = *str++; } else if (*str == 0) { break; } else { fz_throw(ctx, FZ_ERROR_GENERIC, "syntax error in path data: '%c'", *str); } if (reset_smooth) { smooth_x = 0.0; smooth_y = 0.0; } reset_smooth = 1; switch (cmd) { case 'M': if (nargs == 2) { fz_moveto(ctx, path, args[0], args[1]); nargs = 0; cmd = 'L'; /* implicit lineto after */ } break; case 'm': if (nargs == 2) { p = fz_currentpoint(ctx, path); fz_moveto(ctx, path, p.x + args[0], p.y + args[1]); nargs = 0; cmd = 'l'; /* implicit lineto after */ } break; case 'Z': case 'z': if (nargs == 0) { fz_closepath(ctx, path); } break; case 'L': if (nargs == 2) { fz_lineto(ctx, path, args[0], args[1]); nargs = 0; } break; case 'l': if (nargs == 2) { p = fz_currentpoint(ctx, path); fz_lineto(ctx, path, p.x + args[0], p.y + args[1]); nargs = 0; } break; case 'H': if (nargs == 1) { p = fz_currentpoint(ctx, path); fz_lineto(ctx, path, args[0], p.y); nargs = 0; } break; case 'h': if (nargs == 1) { p = fz_currentpoint(ctx, path); fz_lineto(ctx, path, p.x + args[0], p.y); nargs = 0; } break; case 'V': if (nargs == 1) { p = fz_currentpoint(ctx, path); fz_lineto(ctx, path, p.x, args[0]); nargs = 0; } break; case 'v': if (nargs == 1) { p = fz_currentpoint(ctx, path); fz_lineto(ctx, path, p.x, p.y + args[0]); nargs = 0; } break; case 'C': reset_smooth = 0; if (nargs == 6) { fz_curveto(ctx, path, args[0], args[1], args[2], args[3], args[4], args[5]); smooth_x = args[4] - args[2]; smooth_y = args[5] - args[3]; nargs = 0; } break; case 'c': reset_smooth = 0; if (nargs == 6) { p = fz_currentpoint(ctx, path); fz_curveto(ctx, path, p.x + args[0], p.y + args[1], p.x + args[2], p.y + args[3], p.x + args[4], p.y + args[5]); smooth_x = args[4] - args[2]; smooth_y = args[5] - args[3]; nargs = 0; } break; case 'S': reset_smooth = 0; if (nargs == 4) { p = fz_currentpoint(ctx, path); fz_curveto(ctx, path, p.x + smooth_x, p.y + smooth_y, args[0], args[1], args[2], args[3]); smooth_x = args[2] - args[0]; smooth_y = args[3] - args[1]; nargs = 0; } break; case 's': reset_smooth = 0; if (nargs == 4) { p = fz_currentpoint(ctx, path); fz_curveto(ctx, path, p.x + smooth_x, p.y + smooth_y, p.x + args[0], p.y + args[1], p.x + args[2], p.y + args[3]); smooth_x = args[2] - args[0]; smooth_y = args[3] - args[1]; nargs = 0; } break; case 'Q': reset_smooth = 0; if (nargs == 4) { p = fz_currentpoint(ctx, path); x1 = args[0]; y1 = args[1]; x2 = args[2]; y2 = args[3]; fz_curveto(ctx, path, (p.x + 2 * x1) / 3, (p.y + 2 * y1) / 3, (x2 + 2 * x1) / 3, (y2 + 2 * y1) / 3, x2, y2); smooth_x = x2 - x1; smooth_y = y2 - y1; nargs = 0; } break; case 'q': reset_smooth = 0; if (nargs == 4) { p = fz_currentpoint(ctx, path); x1 = args[0] + p.x; y1 = args[1] + p.y; x2 = args[2] + p.x; y2 = args[3] + p.y; fz_curveto(ctx, path, (p.x + 2 * x1) / 3, (p.y + 2 * y1) / 3, (x2 + 2 * x1) / 3, (y2 + 2 * y1) / 3, x2, y2); smooth_x = x2 - x1; smooth_y = y2 - y1; nargs = 0; } break; case 'T': reset_smooth = 0; if (nargs == 4) { p = fz_currentpoint(ctx, path); x1 = p.x + smooth_x; y1 = p.y + smooth_y; x2 = args[0]; y2 = args[1]; fz_curveto(ctx, path, (p.x + 2 * x1) / 3, (p.y + 2 * y1) / 3, (x2 + 2 * x1) / 3, (y2 + 2 * y1) / 3, x2, y2); smooth_x = x2 - x1; smooth_y = y2 - y1; nargs = 0; } break; case 't': reset_smooth = 0; if (nargs == 4) { p = fz_currentpoint(ctx, path); x1 = p.x + smooth_x; y1 = p.y + smooth_y; x2 = args[0] + p.x; y2 = args[1] + p.y; fz_curveto(ctx, path, (p.x + 2 * x1) / 3, (p.y + 2 * y1) / 3, (x2 + 2 * x1) / 3, (y2 + 2 * y1) / 3, x2, y2); smooth_x = x2 - x1; smooth_y = y2 - y1; nargs = 0; } break; case 0: if (nargs != 0) fz_throw(ctx, FZ_ERROR_GENERIC, "path data must begin with a command"); break; default: fz_throw(ctx, FZ_ERROR_GENERIC, "unrecognized command in path data: '%c'", cmd); } } } fz_catch(ctx) { fz_drop_path(ctx, path); fz_rethrow(ctx); } return path; }
static int make_fake_doc(pdfapp_t *app) { fz_context *ctx = app->ctx; fz_matrix ctm = { 1, 0, 0, 1, 0, 0 }; fz_rect bounds; pdf_page *newpage = NULL; pdf_document *pdf = NULL; fz_device *dev = NULL; fz_path *path = NULL; fz_stroke_state stroke = fz_default_stroke_state; float red[3] = { 1, 0, 0 }; int i; fz_var(pdf); fz_var(dev); fz_var(newpage); fz_try(ctx) { pdf = pdf_create_document(ctx); app->doc = &pdf->super; bounds.x0 = 0; bounds.y0 = 0; bounds.x1 = app->winw; bounds.y1 = app->winh; newpage = pdf_create_page(ctx, pdf, bounds, 72, 0); dev = pdf_page_write(ctx, pdf, newpage); /* Now the page content */ fz_begin_page(ctx, dev, &bounds, &ctm); path = fz_new_path(ctx); fz_moveto(ctx, path, 0, 0); fz_lineto(ctx, path, bounds.x1, bounds.y1); fz_moveto(ctx, path, 0, bounds.y1); fz_lineto(ctx, path, bounds.x1, 0); stroke.linewidth = fz_min(bounds.x1, bounds.y1)/4; fz_stroke_path(ctx, dev, path, &stroke, &ctm, fz_device_rgb(ctx), red, 1); fz_end_page(ctx, dev); fz_drop_device(ctx, dev); dev = NULL; /* Create enough copies of our blank(ish) page so that the * page number is preserved if and when a subsequent load * works. */ for (i = 0; i < app->pagecount; i++) pdf_insert_page(ctx, pdf, newpage, INT_MAX); } fz_always(ctx) { fz_drop_path(ctx, path); pdf_drop_page(ctx, newpage); fz_drop_device(ctx, dev); dev = NULL; } fz_catch(ctx) { fz_rethrow(ctx); } return 0; }
static fz_path * xps_parse_abbreviated_geometry(xps_document *doc, char *geom, int *fill_rule) { fz_path *path; char **args; char **pargs; char *s = geom; fz_point pt; int i, n; int cmd, old; float x1, y1, x2, y2, x3, y3; float smooth_x, smooth_y; /* saved cubic bezier control point for smooth curves */ int reset_smooth; path = fz_new_path(doc->ctx); args = fz_malloc_array(doc->ctx, strlen(geom) + 1, sizeof(char*)); pargs = args; while (*s) { if ((*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z')) { *pargs++ = s++; } else if ((*s >= '0' && *s <= '9') || *s == '.' || *s == '+' || *s == '-' || *s == 'e' || *s == 'E') { *pargs++ = s; while ((*s >= '0' && *s <= '9') || *s == '.' || *s == '+' || *s == '-' || *s == 'e' || *s == 'E') s ++; } else { s++; } } *pargs = s; n = pargs - args; i = 0; old = 0; reset_smooth = 1; smooth_x = 0; smooth_y = 0; while (i < n) { cmd = args[i][0]; if (cmd == '+' || cmd == '.' || cmd == '-' || (cmd >= '0' && cmd <= '9')) cmd = old; /* it's a number, repeat old command */ else i ++; if (reset_smooth) { smooth_x = 0; smooth_y = 0; } reset_smooth = 1; switch (cmd) { case 'F': if (i >= n) break; *fill_rule = atoi(args[i]); i ++; break; case 'M': if (i + 1 >= n) break; fz_moveto(doc->ctx, path, fz_atof(args[i]), fz_atof(args[i+1])); i += 2; break; case 'm': if (i + 1 >= n) break; pt = fz_currentpoint(doc->ctx, path); fz_moveto(doc->ctx, path, pt.x + fz_atof(args[i]), pt.y + fz_atof(args[i+1])); i += 2; break; case 'L': if (i + 1 >= n) break; fz_lineto(doc->ctx, path, fz_atof(args[i]), fz_atof(args[i+1])); i += 2; break; case 'l': if (i + 1 >= n) break; pt = fz_currentpoint(doc->ctx, path); fz_lineto(doc->ctx, path, pt.x + fz_atof(args[i]), pt.y + fz_atof(args[i+1])); i += 2; break; case 'H': if (i >= n) break; pt = fz_currentpoint(doc->ctx, path); fz_lineto(doc->ctx, path, fz_atof(args[i]), pt.y); i += 1; break; case 'h': if (i >= n) break; pt = fz_currentpoint(doc->ctx, path); fz_lineto(doc->ctx, path, pt.x + fz_atof(args[i]), pt.y); i += 1; break; case 'V': if (i >= n) break; pt = fz_currentpoint(doc->ctx, path); fz_lineto(doc->ctx, path, pt.x, fz_atof(args[i])); i += 1; break; case 'v': if (i >= n) break; pt = fz_currentpoint(doc->ctx, path); fz_lineto(doc->ctx, path, pt.x, pt.y + fz_atof(args[i])); i += 1; break; case 'C': if (i + 5 >= n) break; x1 = fz_atof(args[i+0]); y1 = fz_atof(args[i+1]); x2 = fz_atof(args[i+2]); y2 = fz_atof(args[i+3]); x3 = fz_atof(args[i+4]); y3 = fz_atof(args[i+5]); fz_curveto(doc->ctx, path, x1, y1, x2, y2, x3, y3); i += 6; reset_smooth = 0; smooth_x = x3 - x2; smooth_y = y3 - y2; break; case 'c': if (i + 5 >= n) break; pt = fz_currentpoint(doc->ctx, path); x1 = fz_atof(args[i+0]) + pt.x; y1 = fz_atof(args[i+1]) + pt.y; x2 = fz_atof(args[i+2]) + pt.x; y2 = fz_atof(args[i+3]) + pt.y; x3 = fz_atof(args[i+4]) + pt.x; y3 = fz_atof(args[i+5]) + pt.y; fz_curveto(doc->ctx, path, x1, y1, x2, y2, x3, y3); i += 6; reset_smooth = 0; smooth_x = x3 - x2; smooth_y = y3 - y2; break; case 'S': if (i + 3 >= n) break; pt = fz_currentpoint(doc->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(doc->ctx, path, pt.x + smooth_x, pt.y + smooth_y, x1, y1, x2, y2); i += 4; reset_smooth = 0; smooth_x = x2 - x1; smooth_y = y2 - y1; break; case 's': if (i + 3 >= n) break; pt = fz_currentpoint(doc->ctx, path); x1 = fz_atof(args[i+0]) + pt.x; 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(doc->ctx, path, pt.x + smooth_x, pt.y + smooth_y, x1, y1, x2, y2); i += 4; reset_smooth = 0; smooth_x = x2 - x1; smooth_y = y2 - y1; break; case 'Q': if (i + 3 >= n) break; pt = fz_currentpoint(doc->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(doc->ctx, path, (pt.x + 2 * x1) / 3, (pt.y + 2 * y1) / 3, (x2 + 2 * x1) / 3, (y2 + 2 * y1) / 3, x2, y2); i += 4; break; case 'q': if (i + 3 >= n) break; pt = fz_currentpoint(doc->ctx, path); x1 = fz_atof(args[i+0]) + pt.x; 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(doc->ctx, path, (pt.x + 2 * x1) / 3, (pt.y + 2 * y1) / 3, (x2 + 2 * x1) / 3, (y2 + 2 * y1) / 3, x2, y2); i += 4; break; case 'A': if (i + 6 >= n) break; xps_draw_arc(doc->ctx, path, fz_atof(args[i+0]), fz_atof(args[i+1]), fz_atof(args[i+2]), atoi(args[i+3]), atoi(args[i+4]), fz_atof(args[i+5]), fz_atof(args[i+6])); i += 7; break; case 'a': if (i + 6 >= n) break; pt = fz_currentpoint(doc->ctx, path); xps_draw_arc(doc->ctx, path, fz_atof(args[i+0]), fz_atof(args[i+1]), fz_atof(args[i+2]), atoi(args[i+3]), atoi(args[i+4]), fz_atof(args[i+5]) + pt.x, fz_atof(args[i+6]) + pt.y); i += 7; break; case 'Z': case 'z': fz_closepath(doc->ctx, path); break; default: /* eek */ fz_warn(doc->ctx, "ignoring invalid command '%c'", cmd); /* Skip any trailing numbers to avoid an infinite loop */ while (i < n && (args[i][0] == '+' || args[i][0] == '.' || args[i][0] == '-' || (args[i][0] >= '0' && args[i][0] <= '9'))) i ++; break; } old = cmd; } fz_free(doc->ctx, args); return path; }