diff options
Diffstat (limited to 'source/svg/svg-doc.c')
-rw-r--r-- | source/svg/svg-doc.c | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/source/svg/svg-doc.c b/source/svg/svg-doc.c new file mode 100644 index 00000000..f08cceb2 --- /dev/null +++ b/source/svg/svg-doc.c @@ -0,0 +1,143 @@ +#include "mupdf/svg.h" + +typedef struct svg_page_s svg_page; + +struct svg_page_s +{ + fz_page super; + svg_document *doc; +}; + +static void +svg_close_document(fz_context *ctx, fz_document *doc_) +{ + svg_document *doc = (svg_document*)doc_; + fz_drop_tree(ctx, doc->idmap, NULL); + fz_drop_xml(ctx, doc->root); + fz_free(ctx, doc); +} + +static int +svg_count_pages(fz_context *ctx, fz_document *doc_) +{ + return 1; +} + +static fz_rect * +svg_bound_page(fz_context *ctx, fz_page *page_, fz_rect *rect) +{ + svg_page *page = (svg_page*)page_; + svg_document *doc = page->doc; + + svg_parse_document_bounds(ctx, doc, doc->root); + + rect->x0 = 0; + rect->y0 = 0; + rect->x1 = doc->width; + rect->y1 = doc->height; + return rect; +} + +static void +svg_run_page(fz_context *ctx, fz_page *page_, fz_device *dev, const fz_matrix *ctm, fz_cookie *cookie) +{ + svg_page *page = (svg_page*)page_; + svg_document *doc = page->doc; + svg_run_document(ctx, doc, doc->root, dev, ctm); +} + +static void +svg_drop_page_imp(fz_context *ctx, fz_page *page_) +{ + /* nothing */ +} + +static fz_page * +svg_load_page(fz_context *ctx, fz_document *doc_, int number) +{ + svg_document *doc = (svg_document*)doc_; + svg_page *page; + + if (number != 0) + return NULL; + + page = fz_new_page(ctx, sizeof *page); + page->super.bound_page = svg_bound_page; + page->super.run_page_contents = svg_run_page; + page->super.drop_page_imp = svg_drop_page_imp; + page->doc = doc; + + return (fz_page*)page; +} + +static void +svg_build_id_map(fz_context *ctx, svg_document *doc, fz_xml *root) +{ + fz_xml *node; + + char *id_att = fz_xml_att(root, "id"); + if (id_att) + doc->idmap = fz_tree_insert(ctx, doc->idmap, id_att, root); + + for (node = fz_xml_down(root); node; node = fz_xml_next(node)) + svg_build_id_map(ctx, doc, node); +} + +static fz_document * +svg_open_document_with_stream(fz_context *ctx, fz_stream *file) +{ + svg_document *doc; + fz_buffer *buf; + fz_xml *root; + + buf = fz_read_all(ctx, file, 0); + root = fz_parse_xml(ctx, buf->data, buf->len, 0); + fz_drop_buffer(ctx, buf); + + doc = fz_malloc_struct(ctx, svg_document); + doc->super.close = svg_close_document; + doc->super.count_pages = svg_count_pages; + doc->super.load_page = svg_load_page; + + doc->root = root; + doc->idmap = NULL; + + svg_build_id_map(ctx, doc, root); + + return (fz_document*)doc; +} + +static fz_document * +svg_open_document(fz_context *ctx, const char *filename) +{ + fz_stream *file; + fz_document *doc; + + file = fz_open_file(ctx, filename); + fz_try(ctx) + doc = svg_open_document_with_stream(ctx, file); + fz_always(ctx) + fz_drop_stream(ctx, file); + fz_catch(ctx) + fz_rethrow(ctx); + + return doc; +} + +static int +svg_recognize(fz_context *doc, const char *magic) +{ + char *ext = strrchr(magic, '.'); + if (ext && !fz_strcasecmp(ext, ".svg")) + return 100; + if (!strcmp(magic, "svg") || !strcmp(magic, "image/svg+xml")) + return 100; + return 0; +} + +fz_document_handler svg_document_handler = +{ + &svg_recognize, + &svg_open_document, + &svg_open_document_with_stream +}; |