1#include "mupdf/fitz.h"
2#include "html-imp.h"
3
4#include <string.h>
5#include <math.h>
6
7enum { T, R, B, L };
8
9typedef struct html_document_s html_document;
10typedef struct html_page_s html_page;
11
12struct html_document_s
13{
14 fz_document super;
15 fz_archive *zip;
16 fz_html_font_set *set;
17 fz_html *html;
18 fz_outline *outline;
19};
20
21struct html_page_s
22{
23 fz_page super;
24 html_document *doc;
25 int number;
26};
27
28static void
29htdoc_drop_document(fz_context *ctx, fz_document *doc_)
30{
31 html_document *doc = (html_document*)doc_;
32 fz_drop_archive(ctx, doc->zip);
33 fz_drop_html(ctx, doc->html);
34 fz_drop_html_font_set(ctx, doc->set);
35 fz_drop_outline(ctx, doc->outline);
36}
37
38static int
39htdoc_resolve_link(fz_context *ctx, fz_document *doc_, const char *dest, float *xp, float *yp)
40{
41 html_document *doc = (html_document*)doc_;
42 const char *s = strchr(dest, '#');
43 if (s && s[1] != 0)
44 {
45 float y = fz_find_html_target(ctx, doc->html, s+1);
46 if (y >= 0)
47 {
48 int page = y / doc->html->page_h;
49 if (yp) *yp = y - page * doc->html->page_h;
50 return page;
51 }
52 }
53
54 return -1;
55}
56
57static int
58htdoc_count_pages(fz_context *ctx, fz_document *doc_)
59{
60 html_document *doc = (html_document*)doc_;
61 if (doc->html->root->b > 0)
62 return ceilf(doc->html->root->b / doc->html->page_h);
63 return 1;
64}
65
66static void
67htdoc_update_outline(fz_context *ctx, fz_document *doc, fz_outline *node)
68{
69 while (node)
70 {
71 node->page = htdoc_resolve_link(ctx, doc, node->uri, &node->x, &node->y);
72 htdoc_update_outline(ctx, doc, node->down);
73 node = node->next;
74 }
75}
76
77static void
78htdoc_layout(fz_context *ctx, fz_document *doc_, float w, float h, float em)
79{
80 html_document *doc = (html_document*)doc_;
81
82 fz_layout_html(ctx, doc->html, w, h, em);
83
84 htdoc_update_outline(ctx, doc_, doc->outline);
85}
86
87static void
88htdoc_drop_page(fz_context *ctx, fz_page *page_)
89{
90}
91
92static fz_rect
93htdoc_bound_page(fz_context *ctx, fz_page *page_)
94{
95 html_page *page = (html_page*)page_;
96 html_document *doc = page->doc;
97 fz_rect bbox;
98 bbox.x0 = 0;
99 bbox.y0 = 0;
100 bbox.x1 = doc->html->page_w + doc->html->page_margin[L] + doc->html->page_margin[R];
101 bbox.y1 = doc->html->page_h + doc->html->page_margin[T] + doc->html->page_margin[B];
102 return bbox;
103}
104
105static void
106htdoc_run_page(fz_context *ctx, fz_page *page_, fz_device *dev, fz_matrix ctm, fz_cookie *cookie)
107{
108 html_page *page = (html_page*)page_;
109 html_document *doc = page->doc;
110 fz_draw_html(ctx, dev, ctm, doc->html, page->number);
111}
112
113static fz_link *
114htdoc_load_links(fz_context *ctx, fz_page *page_)
115{
116 html_page *page = (html_page*)page_;
117 html_document *doc = page->doc;
118 return fz_load_html_links(ctx, doc->html, page->number, "", doc);
119}
120
121static fz_bookmark
122htdoc_make_bookmark(fz_context *ctx, fz_document *doc_, int page)
123{
124 html_document *doc = (html_document*)doc_;
125 return fz_make_html_bookmark(ctx, doc->html, page);
126}
127
128static int
129htdoc_lookup_bookmark(fz_context *ctx, fz_document *doc_, fz_bookmark mark)
130{
131 html_document *doc = (html_document*)doc_;
132 return fz_lookup_html_bookmark(ctx, doc->html, mark);
133}
134
135static fz_page *
136htdoc_load_page(fz_context *ctx, fz_document *doc_, int number)
137{
138 html_document *doc = (html_document*)doc_;
139 html_page *page = fz_new_derived_page(ctx, html_page);
140 page->super.bound_page = htdoc_bound_page;
141 page->super.run_page_contents = htdoc_run_page;
142 page->super.load_links = htdoc_load_links;
143 page->super.drop_page = htdoc_drop_page;
144 page->doc = doc;
145 page->number = number;
146 return (fz_page*)page;
147}
148
149static fz_outline *
150htdoc_load_outline(fz_context *ctx, fz_document *doc_)
151{
152 html_document *doc = (html_document*)doc_;
153 return fz_keep_outline(ctx, doc->outline);
154}
155
156static int
157htdoc_lookup_metadata(fz_context *ctx, fz_document *doc_, const char *key, char *buf, int size)
158{
159 html_document *doc = (html_document*)doc_;
160 if (!strcmp(key, FZ_META_FORMAT))
161 return (int)fz_strlcpy(buf, "XHTML", size);
162 if (!strcmp(key, FZ_META_INFO_TITLE) && doc->html->title)
163 return (int)fz_strlcpy(buf, doc->html->title, size);
164 return -1;
165}
166
167static fz_document *
168htdoc_open_document_with_buffer(fz_context *ctx, const char *dirname, fz_buffer *buf)
169{
170 html_document *doc = fz_new_derived_document(ctx, html_document);
171 doc->super.drop_document = htdoc_drop_document;
172 doc->super.layout = htdoc_layout;
173 doc->super.load_outline = htdoc_load_outline;
174 doc->super.resolve_link = htdoc_resolve_link;
175 doc->super.make_bookmark = htdoc_make_bookmark;
176 doc->super.lookup_bookmark = htdoc_lookup_bookmark;
177 doc->super.count_pages = htdoc_count_pages;
178 doc->super.load_page = htdoc_load_page;
179 doc->super.lookup_metadata = htdoc_lookup_metadata;
180 doc->super.is_reflowable = 1;
181
182 fz_try(ctx)
183 {
184 doc->zip = fz_open_directory(ctx, dirname);
185 doc->set = fz_new_html_font_set(ctx);
186 doc->html = fz_parse_html(ctx, doc->set, doc->zip, ".", buf, fz_user_css(ctx));
187 doc->outline = fz_load_html_outline(ctx, doc->html);
188 }
189 fz_always(ctx)
190 fz_drop_buffer(ctx, buf);
191 fz_catch(ctx)
192 {
193 fz_drop_document(ctx, &doc->super);
194 fz_rethrow(ctx);
195 }
196
197 return (fz_document*)doc;
198}
199
200static fz_document *
201htdoc_open_document_with_stream(fz_context *ctx, fz_stream *file)
202{
203 return htdoc_open_document_with_buffer(ctx, ".", fz_read_all(ctx, file, 0));
204}
205
206static fz_document *
207htdoc_open_document(fz_context *ctx, const char *filename)
208{
209 char dirname[2048];
210 fz_dirname(dirname, filename, sizeof dirname);
211 return htdoc_open_document_with_buffer(ctx, dirname, fz_read_file(ctx, filename));
212}
213
214static const char *htdoc_extensions[] =
215{
216 "fb2",
217 "htm",
218 "html",
219 "xhtml",
220 "xml",
221 NULL
222};
223
224static const char *htdoc_mimetypes[] =
225{
226 "application/html+xml",
227 "application/x-fictionbook",
228 "application/xml",
229 "text/xml",
230 NULL
231};
232
233fz_document_handler html_document_handler =
234{
235 NULL,
236 htdoc_open_document,
237 htdoc_open_document_with_stream,
238 htdoc_extensions,
239 htdoc_mimetypes
240};
241