1#include "mupdf/fitz.h"
2#include "svg-imp.h"
3
4typedef struct svg_page_s svg_page;
5
6struct svg_page_s
7{
8 fz_page super;
9 svg_document *doc;
10};
11
12static void
13svg_drop_document(fz_context *ctx, fz_document *doc_)
14{
15 svg_document *doc = (svg_document*)doc_;
16 fz_drop_tree(ctx, doc->idmap, NULL);
17 fz_drop_xml(ctx, doc->xml);
18}
19
20static int
21svg_count_pages(fz_context *ctx, fz_document *doc_)
22{
23 return 1;
24}
25
26static fz_rect
27svg_bound_page(fz_context *ctx, fz_page *page_)
28{
29 svg_page *page = (svg_page*)page_;
30 svg_document *doc = page->doc;
31
32 svg_parse_document_bounds(ctx, doc, doc->root);
33
34 return fz_make_rect(0, 0, doc->width, doc->height);
35}
36
37static void
38svg_run_page(fz_context *ctx, fz_page *page_, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
39{
40 svg_page *page = (svg_page*)page_;
41 svg_document *doc = page->doc;
42 svg_run_document(ctx, doc, doc->root, dev, ctm);
43}
44
45static void
46svg_drop_page(fz_context *ctx, fz_page *page_)
47{
48 /* nothing */
49}
50
51static fz_page *
52svg_load_page(fz_context *ctx, fz_document *doc_, int number)
53{
54 svg_document *doc = (svg_document*)doc_;
55 svg_page *page;
56
57 if (number != 0)
58 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot find page %d", number);
59
60 page = fz_new_derived_page(ctx, svg_page);
61 page->super.bound_page = svg_bound_page;
62 page->super.run_page_contents = svg_run_page;
63 page->super.drop_page = svg_drop_page;
64 page->doc = doc;
65
66 return (fz_page*)page;
67}
68
69static void
70svg_build_id_map(fz_context *ctx, svg_document *doc, fz_xml *root)
71{
72 fz_xml *node;
73
74 char *id_att = fz_xml_att(root, "id");
75 if (id_att)
76 doc->idmap = fz_tree_insert(ctx, doc->idmap, id_att, root);
77
78 for (node = fz_xml_down(root); node; node = fz_xml_next(node))
79 svg_build_id_map(ctx, doc, node);
80}
81
82static fz_document *
83svg_open_document_with_xml(fz_context *ctx, fz_xml *xml, const char *base_uri, fz_archive *zip)
84{
85 svg_document *doc;
86
87 doc = fz_new_derived_document(ctx, svg_document);
88 doc->super.drop_document = svg_drop_document;
89 doc->super.count_pages = svg_count_pages;
90 doc->super.load_page = svg_load_page;
91
92 doc->idmap = NULL;
93 doc->xml = NULL;
94 doc->root = xml;
95 doc->zip = zip;
96
97 fz_try(ctx)
98 {
99 svg_build_id_map(ctx, doc, doc->root);
100 }
101 fz_catch(ctx)
102 {
103 fz_drop_document(ctx, &doc->super);
104 fz_rethrow(ctx);
105 }
106
107 return (fz_document*)doc;
108}
109
110static fz_document *
111svg_open_document_with_buffer(fz_context *ctx, fz_buffer *buf, const char *base_uri, fz_archive *zip)
112{
113 svg_document *doc;
114
115 doc = fz_new_derived_document(ctx, svg_document);
116 doc->super.drop_document = svg_drop_document;
117 doc->super.count_pages = svg_count_pages;
118 doc->super.load_page = svg_load_page;
119
120 doc->idmap = NULL;
121 if (base_uri)
122 fz_strlcpy(doc->base_uri, base_uri, sizeof doc->base_uri);
123 doc->zip = zip;
124
125 fz_try(ctx)
126 {
127 doc->xml = fz_parse_xml(ctx, buf, 0);
128 doc->root = fz_xml_root(doc->xml);
129 svg_build_id_map(ctx, doc, doc->root);
130 }
131 fz_catch(ctx)
132 {
133 fz_drop_document(ctx, &doc->super);
134 fz_rethrow(ctx);
135 }
136
137 return (fz_document*)doc;
138}
139
140static fz_document *
141svg_open_document_with_stream(fz_context *ctx, fz_stream *file)
142{
143 fz_buffer *buf;
144 fz_document *doc = NULL;
145
146 buf = fz_read_all(ctx, file, 0);
147 fz_try(ctx)
148 doc = svg_open_document_with_buffer(ctx, buf, NULL, NULL);
149 fz_always(ctx)
150 fz_drop_buffer(ctx, buf);
151 fz_catch(ctx)
152 fz_rethrow(ctx);
153
154 return doc;
155}
156
157/*
158 Parse an SVG document into a display-list.
159*/
160fz_display_list *
161fz_new_display_list_from_svg(fz_context *ctx, fz_buffer *buf, const char *base_uri, fz_archive *zip, float *w, float *h)
162{
163 fz_document *doc;
164 fz_display_list *list = NULL;
165
166 doc = svg_open_document_with_buffer(ctx, buf, base_uri, zip);
167 fz_try(ctx)
168 {
169 list = fz_new_display_list_from_page_number(ctx, doc, 0);
170 *w = ((svg_document*)doc)->width;
171 *h = ((svg_document*)doc)->height;
172 }
173 fz_always(ctx)
174 fz_drop_document(ctx, doc);
175 fz_catch(ctx)
176 fz_rethrow(ctx);
177
178 return list;
179}
180
181/*
182 Parse an SVG document into a display-list.
183*/
184fz_display_list *
185fz_new_display_list_from_svg_xml(fz_context *ctx, fz_xml *xml, const char *base_uri, fz_archive *zip, float *w, float *h)
186{
187 fz_document *doc;
188 fz_display_list *list = NULL;
189
190 doc = svg_open_document_with_xml(ctx, xml, base_uri, zip);
191 fz_try(ctx)
192 {
193 list = fz_new_display_list_from_page_number(ctx, doc, 0);
194 *w = ((svg_document*)doc)->width;
195 *h = ((svg_document*)doc)->height;
196 }
197 fz_always(ctx)
198 fz_drop_document(ctx, doc);
199 fz_catch(ctx)
200 fz_rethrow(ctx);
201
202 return list;
203}
204
205/*
206 Create a scalable image from an SVG document.
207*/
208fz_image *
209fz_new_image_from_svg(fz_context *ctx, fz_buffer *buf, const char *base_uri, fz_archive *zip)
210{
211 fz_display_list *list;
212 fz_image *image = NULL;
213 float w, h;
214
215 list = fz_new_display_list_from_svg(ctx, buf, base_uri, zip, &w, &h);
216 fz_try(ctx)
217 image = fz_new_image_from_display_list(ctx, w, h, list);
218 fz_always(ctx)
219 fz_drop_display_list(ctx, list);
220 fz_catch(ctx)
221 fz_rethrow(ctx);
222 return image;
223}
224
225/*
226 Create a scalable image from an SVG document.
227*/
228fz_image *
229fz_new_image_from_svg_xml(fz_context *ctx, fz_xml *xml, const char *base_uri, fz_archive *zip)
230{
231 fz_display_list *list;
232 fz_image *image = NULL;
233 float w, h;
234
235 list = fz_new_display_list_from_svg_xml(ctx, xml, base_uri, zip, &w, &h);
236 fz_try(ctx)
237 image = fz_new_image_from_display_list(ctx, w, h, list);
238 fz_always(ctx)
239 fz_drop_display_list(ctx, list);
240 fz_catch(ctx)
241 fz_rethrow(ctx);
242 return image;
243}
244
245static const char *svg_extensions[] =
246{
247 "svg",
248 NULL
249};
250
251static const char *svg_mimetypes[] =
252{
253 "image/svg+xml",
254 NULL
255};
256
257fz_document_handler svg_document_handler =
258{
259 NULL,
260 NULL,
261 svg_open_document_with_stream,
262 svg_extensions,
263 svg_mimetypes
264};
265