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); } }
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); } }
void fz_lineto(fz_path *path, float x, float y) { if (path->len == 0) fz_moveto(path, 0, 0); growpath(path, 3); path->els[path->len++].k = FZ_LINETO; path->els[path->len++].v = x; path->els[path->len++].v = y; }
static void approx_circle(fz_context *ctx, fz_path *path, float cx, float cy, float rx, float ry) { float rxs = rx * MAGIC_CIRCLE; float rys = ry * MAGIC_CIRCLE; fz_moveto(ctx, path, cx, cy+ry); fz_curveto(ctx, path, cx + rxs, cy + ry, cx + rx, cy + rys, cx + rx, cy); fz_curveto(ctx, path, cx + rx, cy - rys, cx + rxs, cy - rys, cx, cy - ry); fz_curveto(ctx, path, cx - rxs, cy - ry, cx - rx, cy - rys, cx - rx, cy); fz_curveto(ctx, path, cx - rx, cy + rys, cx - rxs, cy + rys, cx, cy + ry); fz_closepath(ctx, path); }
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, 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_parse_arc_segment(fz_context *doc, fz_path *path, fz_xml *root, int stroking, int *skipped_stroke) { /* ArcSegment pretty much follows the SVG algorithm for converting an * arc in endpoint representation to an arc in centerpoint * representation. Once in centerpoint it can be given to the * graphics library in the form of a postscript arc. */ float rotation_angle; int is_large_arc, is_clockwise; float point_x, point_y; float size_x, size_y; int is_stroked; char *point_att = fz_xml_att(root, "Point"); char *size_att = fz_xml_att(root, "Size"); char *rotation_angle_att = fz_xml_att(root, "RotationAngle"); char *is_large_arc_att = fz_xml_att(root, "IsLargeArc"); char *sweep_direction_att = fz_xml_att(root, "SweepDirection"); char *is_stroked_att = fz_xml_att(root, "IsStroked"); if (!point_att || !size_att || !rotation_angle_att || !is_large_arc_att || !sweep_direction_att) { fz_warn(doc, "ArcSegment element is missing attributes"); return; } is_stroked = 1; if (is_stroked_att && !strcmp(is_stroked_att, "false")) is_stroked = 0; if (!is_stroked) *skipped_stroke = 1; point_x = point_y = 0; size_x = size_y = 0; xps_parse_point(point_att, &point_x, &point_y); xps_parse_point(size_att, &size_x, &size_y); rotation_angle = fz_atof(rotation_angle_att); is_large_arc = !strcmp(is_large_arc_att, "true"); is_clockwise = !strcmp(sweep_direction_att, "Clockwise"); if (stroking && !is_stroked) { fz_moveto(doc, path, point_x, point_y); return; } xps_draw_arc(doc, path, size_x, size_y, rotation_angle, is_large_arc, is_clockwise, point_x, point_y); }
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 xps_parse_poly_quadratic_bezier_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"); float x[2], y[2]; int is_stroked; fz_point pt; char *s; int n; if (!points_att) { fz_warn(doc, "PolyQuadraticBezierSegment 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; n = 0; while (*s != 0) { while (*s == ' ') s++; s = xps_parse_point(s, &x[n], &y[n]); n ++; if (n == 2) { if (stroking && !is_stroked) { fz_moveto(doc, path, x[1], y[1]); } else { pt = fz_currentpoint(doc, path); fz_curveto(doc, path, (pt.x + 2 * x[0]) / 3, (pt.y + 2 * y[0]) / 3, (x[1] + 2 * x[0]) / 3, (y[1] + 2 * y[0]) / 3, x[1], y[1]); } n = 0; } } }
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_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 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; }
void fz_curveto(fz_path *path, float x1, float y1, float x2, float y2, float x3, float y3) { if (path->len == 0) fz_moveto(path, 0, 0); growpath(path, 7); path->els[path->len++].k = FZ_CURVETO; path->els[path->len++].v = x1; path->els[path->len++].v = y1; path->els[path->len++].v = x2; path->els[path->len++].v = y2; path->els[path->len++].v = x3; path->els[path->len++].v = y3; }
static void xps_parse_poly_bezier_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"); float x[3], y[3]; int is_stroked; char *s; int n; if (!points_att) { fz_warn(doc, "PolyBezierSegment 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; n = 0; while (*s != 0) { while (*s == ' ') s++; s = xps_parse_point(s, &x[n], &y[n]); n ++; if (n == 3) { if (stroking && !is_stroked) fz_moveto(doc, path, x[2], y[2]); else fz_curveto(doc, path, x[0], y[0], x[1], y[1], x[2], y[2]); n = 0; } } }
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 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; }