You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RenderPagesModel.java 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.area;
  19. // Java
  20. import java.io.IOException;
  21. import java.io.OutputStream;
  22. import java.util.Iterator;
  23. import java.util.List;
  24. import java.util.Locale;
  25. import org.xml.sax.SAXException;
  26. import org.apache.fop.apps.FOPException;
  27. import org.apache.fop.apps.FOUserAgent;
  28. import org.apache.fop.fonts.FontInfo;
  29. import org.apache.fop.render.Renderer;
  30. import org.apache.fop.render.RendererEventProducer;
  31. /**
  32. * This uses the AreaTreeModel to store the pages
  33. * Each page is either rendered if ready or prepared
  34. * for later rendering.
  35. * Once a page is rendered it is cleared to release the
  36. * contents but the PageViewport is retained. So even
  37. * though the pages are stored the contents are discarded.
  38. */
  39. public class RenderPagesModel extends AreaTreeModel {
  40. /**
  41. * The renderer that will render the pages.
  42. */
  43. protected Renderer renderer;
  44. /**
  45. * Pages that have been prepared but not rendered yet.
  46. */
  47. protected List<PageViewport> prepared = new java.util.ArrayList<PageViewport>();
  48. private List<OffDocumentItem> pendingODI = new java.util.ArrayList<OffDocumentItem>();
  49. private List<OffDocumentItem> endDocODI = new java.util.ArrayList<OffDocumentItem>();
  50. /**
  51. * Create a new render pages model with the given renderer.
  52. * @param userAgent FOUserAgent object for process
  53. * @param outputFormat the MIME type of the output format to use (ex. "application/pdf").
  54. * @param fontInfo FontInfo object
  55. * @param stream OutputStream
  56. * @throws FOPException if the renderer cannot be properly initialized
  57. */
  58. public RenderPagesModel(FOUserAgent userAgent, String outputFormat,
  59. FontInfo fontInfo, OutputStream stream) throws FOPException {
  60. super();
  61. this.renderer = userAgent.getRendererFactory().createRenderer(
  62. userAgent, outputFormat);
  63. try {
  64. renderer.setupFontInfo(fontInfo);
  65. // check that the "any,normal,400" font exists
  66. if (!fontInfo.isSetupValid()) {
  67. throw new FOPException(
  68. "No default font defined by OutputConverter");
  69. }
  70. renderer.startRenderer(stream);
  71. } catch (IOException e) {
  72. throw new FOPException(e);
  73. }
  74. }
  75. @Override
  76. public void setDocumentLocale(Locale locale) {
  77. renderer.setDocumentLocale(locale);
  78. }
  79. /** {@inheritDoc} */
  80. @Override
  81. public void startPageSequence(PageSequence pageSequence) {
  82. super.startPageSequence(pageSequence);
  83. if (renderer.supportsOutOfOrder()) {
  84. renderer.startPageSequence(getCurrentPageSequence());
  85. }
  86. }
  87. /**
  88. * Add a page to the render page model.
  89. * If the page is finished it can be rendered immediately.
  90. * If the page needs resolving then if the renderer supports
  91. * out of order rendering it can prepare the page. Otherwise
  92. * the page is added to a queue.
  93. * @param page the page to add to the model
  94. */
  95. @Override
  96. public void addPage(PageViewport page) {
  97. super.addPage(page);
  98. // for links the renderer needs to prepare the page
  99. // it is more appropriate to do this after queued pages but
  100. // it will mean that the renderer has not prepared a page that
  101. // could be referenced
  102. boolean ready = renderer.supportsOutOfOrder() && page.isResolved();
  103. if (ready) {
  104. if (!renderer.supportsOutOfOrder() && page.getPageSequence().isFirstPage(page)) {
  105. renderer.startPageSequence(getCurrentPageSequence());
  106. }
  107. try {
  108. renderer.renderPage(page);
  109. } catch (RuntimeException re) {
  110. String err = "Error while rendering page " + page.getPageNumberString();
  111. log.error(err, re);
  112. throw re;
  113. } catch (IOException ioe) {
  114. RendererEventProducer eventProducer = RendererEventProducer.Provider.get(
  115. renderer.getUserAgent().getEventBroadcaster());
  116. eventProducer.ioError(this, ioe);
  117. } catch (FOPException e) {
  118. //TODO use error handler to handle this FOPException or propagate exception
  119. String err = "Error while rendering page " + page.getPageNumberString();
  120. log.error(err, e);
  121. throw new IllegalStateException("Fatal error occurred. Cannot continue. "
  122. + e.getClass().getName() + ": " + err);
  123. }
  124. page.clear();
  125. } else {
  126. preparePage(page);
  127. }
  128. // check prepared pages
  129. boolean cont = checkPreparedPages(page, false);
  130. if (cont) {
  131. processOffDocumentItems(pendingODI);
  132. pendingODI.clear();
  133. }
  134. }
  135. /**
  136. * Check prepared pages
  137. *
  138. * @param newPageViewport the new page being added
  139. * @param renderUnresolved render pages with unresolved idref's
  140. * (done at end-of-document processing)
  141. * @return true if the current page should be rendered
  142. * false if the renderer doesn't support out of order
  143. * rendering and there are pending pages
  144. */
  145. protected boolean checkPreparedPages(PageViewport newPageViewport,
  146. boolean renderUnresolved) {
  147. for (Iterator iter = prepared.iterator(); iter.hasNext();) {
  148. PageViewport pageViewport = (PageViewport)iter.next();
  149. if (pageViewport.isResolved() || renderUnresolved) {
  150. if (!renderer.supportsOutOfOrder()
  151. && pageViewport.getPageSequence().isFirstPage(pageViewport)) {
  152. renderer.startPageSequence(pageViewport.getPageSequence());
  153. }
  154. renderPage(pageViewport);
  155. pageViewport.clear();
  156. iter.remove();
  157. } else {
  158. // if keeping order then stop at first page not resolved
  159. if (!renderer.supportsOutOfOrder()) {
  160. break;
  161. }
  162. }
  163. }
  164. return renderer.supportsOutOfOrder() || prepared.isEmpty();
  165. }
  166. /**
  167. * Renders the given page and notified about unresolved IDs if any.
  168. * @param pageViewport the page to be rendered.
  169. */
  170. protected void renderPage(PageViewport pageViewport) {
  171. try {
  172. renderer.renderPage(pageViewport);
  173. if (!pageViewport.isResolved()) {
  174. String[] idrefs = pageViewport.getIDRefs();
  175. for (String idref : idrefs) {
  176. AreaEventProducer eventProducer = AreaEventProducer.Provider.get(
  177. renderer.getUserAgent().getEventBroadcaster());
  178. eventProducer.unresolvedIDReferenceOnPage(this,
  179. pageViewport.getPageNumberString(), idref);
  180. }
  181. }
  182. } catch (Exception e) {
  183. AreaEventProducer eventProducer = AreaEventProducer.Provider.get(
  184. renderer.getUserAgent().getEventBroadcaster());
  185. eventProducer.pageRenderingError(this,
  186. pageViewport.getPageNumberString(), e);
  187. if (e instanceof RuntimeException) {
  188. throw (RuntimeException)e;
  189. }
  190. }
  191. }
  192. /**
  193. * Prepare a page.
  194. * An unresolved page can be prepared if the renderer supports
  195. * it and the page will be rendered later.
  196. * @param page the page to prepare
  197. */
  198. protected void preparePage(PageViewport page) {
  199. if (renderer.supportsOutOfOrder()) {
  200. renderer.preparePage(page);
  201. }
  202. prepared.add(page);
  203. }
  204. /** {@inheritDoc} */
  205. @Override
  206. public void handleOffDocumentItem(OffDocumentItem oDI) {
  207. switch(oDI.getWhenToProcess()) {
  208. case OffDocumentItem.IMMEDIATELY:
  209. renderer.processOffDocumentItem(oDI);
  210. break;
  211. case OffDocumentItem.AFTER_PAGE:
  212. pendingODI.add(oDI);
  213. break;
  214. case OffDocumentItem.END_OF_DOC:
  215. endDocODI.add(oDI);
  216. break;
  217. default:
  218. throw new RuntimeException();
  219. }
  220. }
  221. private void processOffDocumentItems(List<OffDocumentItem> list) {
  222. for (OffDocumentItem oDI : list) {
  223. renderer.processOffDocumentItem(oDI);
  224. }
  225. }
  226. /**
  227. * End the document. Render any end document OffDocumentItems
  228. * {@inheritDoc}
  229. */
  230. @Override
  231. public void endDocument() throws SAXException {
  232. // render any pages that had unresolved ids
  233. checkPreparedPages(null, true);
  234. processOffDocumentItems(pendingODI);
  235. pendingODI.clear();
  236. processOffDocumentItems(endDocODI);
  237. try {
  238. renderer.stopRenderer();
  239. } catch (IOException ex) {
  240. throw new SAXException(ex);
  241. }
  242. }
  243. }