reflow-doc.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. // Copyright (C) 2004-2021 Artifex Software, Inc.
  2. //
  3. // This file is part of MuPDF.
  4. //
  5. // MuPDF is free software: you can redistribute it and/or modify it under the
  6. // terms of the GNU Affero General Public License as published by the Free
  7. // Software Foundation, either version 3 of the License, or (at your option)
  8. // any later version.
  9. //
  10. // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
  11. // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12. // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. // details.
  14. //
  15. // You should have received a copy of the GNU Affero General Public License
  16. // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
  17. //
  18. // Alternative licensing terms are available from the licensor.
  19. // For commercial licensing, see <https://www.artifex.com/> or contact
  20. // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
  21. // CA 94129, USA, for further information.
  22. #include "mupdf/fitz.h"
  23. #if FZ_ENABLE_HTML_ENGINE
  24. #include <assert.h>
  25. #include <limits.h>
  26. #include <string.h>
  27. #define DEF_WIDTH 612
  28. #define DEF_HEIGHT 792
  29. #define DEF_FONTSIZE 12
  30. typedef struct
  31. {
  32. fz_document base;
  33. fz_document *underdoc;
  34. fz_stext_options opts;
  35. float w;
  36. float h;
  37. float em;
  38. } reflow_document;
  39. typedef struct {
  40. fz_page base;
  41. fz_document *html_doc;
  42. fz_page *html_page;
  43. } reflow_page;
  44. static void
  45. reflow_drop_document_imp(fz_context *ctx, fz_document *doc_)
  46. {
  47. reflow_document *doc = (reflow_document*)doc_;
  48. fz_defer_reap_start(ctx);
  49. fz_drop_document(ctx, doc->underdoc);
  50. fz_defer_reap_end(ctx);
  51. }
  52. static fz_colorspace *
  53. reflow_document_output_intent(fz_context *ctx, fz_document *doc_)
  54. {
  55. reflow_document *doc = (reflow_document*)doc_;
  56. return fz_document_output_intent(ctx, doc->underdoc);
  57. }
  58. static int
  59. reflow_needs_password(fz_context *ctx, fz_document *doc_)
  60. {
  61. reflow_document *doc = (reflow_document*)doc_;
  62. return fz_needs_password(ctx, doc->underdoc);
  63. }
  64. static int
  65. reflow_authenticate_password(fz_context *ctx, fz_document *doc_, const char *password)
  66. {
  67. reflow_document *doc = (reflow_document*)doc_;
  68. return fz_authenticate_password(ctx, doc->underdoc, password);
  69. }
  70. static int
  71. reflow_has_permission(fz_context *ctx, fz_document *doc_, fz_permission permission)
  72. {
  73. reflow_document *doc = (reflow_document*)doc_;
  74. return fz_has_permission(ctx, doc->underdoc, permission);
  75. }
  76. /* FIXME: Need to translate page targets somehow. */
  77. static fz_outline *
  78. reflow_load_outline(fz_context *ctx, fz_document *doc_)
  79. {
  80. reflow_document *doc = (reflow_document*)doc_;
  81. return fz_load_outline(ctx, doc->underdoc);
  82. }
  83. /* FIXME: Need to translate page targets somehow. */
  84. static fz_outline_iterator *
  85. reflow_outline_iterator(fz_context *ctx, fz_document *doc_)
  86. {
  87. reflow_document *doc = (reflow_document*)doc_;
  88. return fz_new_outline_iterator(ctx, doc->underdoc);
  89. }
  90. static fz_link_dest
  91. reflow_resolve_link_dest(fz_context *ctx, fz_document *doc_, const char *uri)
  92. {
  93. reflow_document *doc = (reflow_document*)doc_;
  94. return fz_resolve_link_dest(ctx, doc->underdoc, uri);
  95. }
  96. static int
  97. reflow_count_pages(fz_context *ctx, fz_document *doc_, int chapter)
  98. {
  99. reflow_document *doc = (reflow_document*)doc_;
  100. return fz_count_chapter_pages(ctx, doc->underdoc, chapter);
  101. }
  102. static fz_rect
  103. reflow_bound_page(fz_context *ctx, fz_page *page_, fz_box_type box)
  104. {
  105. reflow_page *page = (reflow_page *)page_;
  106. return fz_bound_page(ctx, page->html_page);
  107. }
  108. static void
  109. reflow_drop_page(fz_context *ctx, fz_page *page_)
  110. {
  111. reflow_page *page = (reflow_page *)page_;
  112. fz_drop_page(ctx, page->html_page);
  113. fz_drop_document(ctx, page->html_doc);
  114. }
  115. static void
  116. reflow_run_page_contents(fz_context *ctx, fz_page *page_, fz_device *dev, fz_matrix transform, fz_cookie *cookie)
  117. {
  118. reflow_page *page = (reflow_page *)page_;
  119. fz_run_page_contents(ctx, page->html_page, dev, transform, cookie);
  120. }
  121. static void
  122. reflow_run_page_annots(fz_context *ctx, fz_page *page_, fz_device *dev, fz_matrix transform, fz_cookie *cookie)
  123. {
  124. reflow_page *page = (reflow_page *)page_;
  125. fz_run_page_annots(ctx, page->html_page, dev, transform, cookie);
  126. }
  127. static void
  128. reflow_run_page_widgets(fz_context *ctx, fz_page *page_, fz_device *dev, fz_matrix transform, fz_cookie *cookie)
  129. {
  130. reflow_page *page = (reflow_page *)page_;
  131. fz_run_page_widgets(ctx, page->html_page, dev, transform, cookie);
  132. }
  133. static fz_page *
  134. reflow_load_page(fz_context *ctx, fz_document *doc_, int chapter, int pagenum)
  135. {
  136. reflow_document *doc = (reflow_document*)doc_;
  137. fz_buffer *buf = NULL;
  138. fz_stext_page *text = NULL;
  139. fz_stext_options default_opts = { FZ_STEXT_PRESERVE_IMAGES | FZ_STEXT_DEHYPHENATE };
  140. reflow_page *page = NULL;
  141. fz_stream *stm = NULL;
  142. fz_output *out = NULL;
  143. page = fz_new_derived_page(ctx, reflow_page, doc_);
  144. page->base.bound_page = reflow_bound_page;
  145. page->base.drop_page = reflow_drop_page;
  146. page->base.run_page_contents = reflow_run_page_contents;
  147. page->base.run_page_annots = reflow_run_page_annots;
  148. page->base.run_page_widgets = reflow_run_page_widgets;
  149. fz_var(buf);
  150. fz_var(out);
  151. fz_var(text);
  152. fz_var(stm);
  153. fz_try(ctx)
  154. {
  155. buf = fz_new_buffer(ctx, 8192);
  156. out = fz_new_output_with_buffer(ctx, buf);
  157. fz_print_stext_header_as_xhtml(ctx, out);
  158. text = fz_new_stext_page_from_chapter_page_number(ctx, doc->underdoc, chapter, pagenum, &default_opts);
  159. fz_print_stext_page_as_xhtml(ctx, out, text, pagenum+1); /* pagenum is not right w.r.t chapter. */
  160. fz_drop_stext_page(ctx, text);
  161. text = NULL;
  162. fz_print_stext_trailer_as_xhtml(ctx, out);
  163. fz_close_output(ctx, out);
  164. fz_terminate_buffer(ctx, buf);
  165. stm = fz_open_buffer(ctx, buf);
  166. page->html_doc = fz_open_document_with_stream(ctx, "application/xhtml+xml", stm);
  167. fz_layout_document(ctx, page->html_doc, doc->w, 0, doc->em);
  168. page->html_page = fz_load_chapter_page(ctx, page->html_doc, 0, 0);
  169. }
  170. fz_always(ctx)
  171. {
  172. fz_drop_stext_page(ctx, text);
  173. fz_drop_output(ctx, out);
  174. fz_drop_stream(ctx, stm);
  175. fz_drop_buffer(ctx, buf);
  176. }
  177. fz_catch(ctx)
  178. {
  179. fz_drop_page(ctx, &page->base);
  180. fz_rethrow(ctx);
  181. }
  182. return &page->base;
  183. }
  184. static int reflow_lookup_metadata(fz_context *ctx, fz_document *doc_, const char *key, char *buf, size_t size)
  185. {
  186. reflow_document *doc = (reflow_document*)doc_;
  187. return fz_lookup_metadata(ctx, doc->underdoc, key, buf, size);
  188. }
  189. static void *reflow_layout_page(fz_context *ctx, fz_page *page_, void *state)
  190. {
  191. reflow_page *page = (reflow_page *) page_;
  192. reflow_document *doc = (reflow_document *) page->base.doc;
  193. fz_layout_document(ctx, page->html_doc, doc->w, 0, doc->em);
  194. return NULL;
  195. }
  196. static void reflow_layout(fz_context *ctx, fz_document *doc_, float w, float h, float em)
  197. {
  198. reflow_document *doc = (reflow_document*)doc_;
  199. if (doc->w == w && doc->h == h && doc->em == em)
  200. return;
  201. doc->w = w;
  202. doc->h = h;
  203. doc->em = em;
  204. (void) fz_process_opened_pages(ctx, (fz_document *) doc, reflow_layout_page, NULL);
  205. }
  206. fz_document *
  207. fz_open_reflowed_document(fz_context *ctx, fz_document *underdoc, const fz_stext_options *opts)
  208. {
  209. reflow_document *doc = fz_new_derived_document(ctx, reflow_document);
  210. doc->base.drop_document = reflow_drop_document_imp;
  211. doc->base.get_output_intent = reflow_document_output_intent;
  212. doc->base.needs_password = reflow_needs_password;
  213. doc->base.authenticate_password = reflow_authenticate_password;
  214. doc->base.has_permission = reflow_has_permission;
  215. doc->base.load_outline = reflow_load_outline;
  216. doc->base.outline_iterator = reflow_outline_iterator;
  217. doc->base.resolve_link_dest = reflow_resolve_link_dest;
  218. doc->base.count_pages = reflow_count_pages;
  219. doc->base.load_page = reflow_load_page;
  220. doc->base.lookup_metadata = reflow_lookup_metadata;
  221. doc->base.layout = reflow_layout;
  222. doc->underdoc = fz_keep_document(ctx, underdoc);
  223. doc->opts = *opts;
  224. doc->w = DEF_WIDTH;
  225. doc->h = DEF_HEIGHT;
  226. doc->em = DEF_FONTSIZE;
  227. return &doc->base;
  228. }
  229. #else
  230. fz_document *
  231. fz_open_reflowed_document(fz_context *ctx, fz_document *underdoc, const fz_stext_options *opts)
  232. {
  233. fz_throw(ctx, FZ_ERROR_UNSUPPORTED, "reflowed documents require html engine");
  234. }
  235. #endif