| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* $Id$ */ |
| |
| package org.apache.fop.area; |
| |
| // Java |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.util.List; |
| import java.util.Iterator; |
| |
| // XML |
| import org.xml.sax.SAXException; |
| |
| // FOP |
| import org.apache.fop.apps.FOPException; |
| import org.apache.fop.apps.FOUserAgent; |
| import org.apache.fop.render.Renderer; |
| |
| import org.axsl.fontR.Font; |
| import org.axsl.fontR.FontConsumer; |
| import org.axsl.fontR.FontException; |
| |
| /** |
| * This uses the AreaTreeModel to store the pages |
| * Each page is either rendered if ready or prepared |
| * for later rendering. |
| * Once a page is rendered it is cleared to release the |
| * contents but the PageViewport is retained. So even |
| * though the pages are stored the contents are discarded. |
| */ |
| public class RenderPagesModel extends AreaTreeModel { |
| /** |
| * The renderer that will render the pages. |
| */ |
| protected Renderer renderer; |
| |
| /** |
| * Pages that have been prepared but not rendered yet. |
| */ |
| protected List prepared = new java.util.ArrayList(); |
| private List pendingODI = new java.util.ArrayList(); |
| private List endDocODI = new java.util.ArrayList(); |
| |
| /** |
| * Create a new render pages model with the given renderer. |
| * @param userAgent FOUserAgent object for process |
| * @param outputFormat the MIME type of the output format to use (ex. "application/pdf"). |
| * @param fontConsumer FontConsumer object |
| * @param stream OutputStream |
| * @throws FOPException if the renderer cannot be properly initialized |
| */ |
| public RenderPagesModel (FOUserAgent userAgent, String outputFormat, |
| FontConsumer fontConsumer, OutputStream stream) throws FOPException { |
| |
| super(); |
| renderer = userAgent.getRendererFactory().createRenderer( |
| userAgent, outputFormat); |
| |
| try { |
| renderer.setupFontConsumer(fontConsumer); |
| // check that the default fallback font exists |
| try { |
| fontConsumer.selectFontXSL(Font.FONT_SELECTION_AUTO, new String[] {"any"}, |
| Font.FONT_STYLE_ANY, |
| Font.FONT_WEIGHT_ANY, |
| Font.FONT_VARIANT_ANY, |
| Font.FONT_STRETCH_ANY, |
| 10000, ' '); |
| } catch (FontException e) { |
| throw new FOPException("No default font defined by OutputConverter"); |
| } |
| renderer.startRenderer(stream); |
| } catch (IOException e) { |
| throw new FOPException(e); |
| } |
| } |
| |
| /** |
| * Start a new page sequence. |
| * This tells the renderer that a new page sequence has |
| * started with the given title. |
| * @param title the title of the new page sequence |
| */ |
| public void startPageSequence(LineArea title) { |
| super.startPageSequence(title); |
| if (renderer.supportsOutOfOrder()) { |
| renderer.startPageSequence(title); |
| } |
| } |
| |
| /** |
| * Add a page to the render page model. |
| * If the page is finished it can be rendered immediately. |
| * If the page needs resolving then if the renderer supports |
| * out of order rendering it can prepare the page. Otherwise |
| * the page is added to a queue. |
| * @param page the page to add to the model |
| */ |
| public void addPage(PageViewport page) { |
| super.addPage(page); |
| |
| // for links the renderer needs to prepare the page |
| // it is more appropriate to do this after queued pages but |
| // it will mean that the renderer has not prepared a page that |
| // could be referenced |
| boolean ready = renderer.supportsOutOfOrder() && page.isResolved(); |
| if (ready) { |
| if (!renderer.supportsOutOfOrder() && page.getPageSequence().isFirstPage(page)) { |
| renderer.startPageSequence(this.currentPageSequence.getTitle()); |
| } |
| try { |
| renderer.renderPage(page); |
| } catch (RuntimeException re) { |
| throw re; |
| } catch (Exception e) { |
| //TODO use error handler to handle this FOP or IO Exception or propagate exception |
| String err = "Error while rendering page " + page.getPageNumberString(); |
| log.error(err, e); |
| throw new IllegalStateException("Fatal error occurred. Cannot continue. " |
| + e.getClass().getName() + ": " + err); |
| } |
| page.clear(); |
| } else { |
| preparePage(page); |
| } |
| |
| |
| // check prepared pages |
| boolean cont = checkPreparedPages(page, false); |
| |
| if (cont) { |
| processOffDocumentItems(pendingODI); |
| pendingODI.clear(); |
| } |
| } |
| |
| /** |
| * Check prepared pages |
| * |
| * @param newpage the new page being added |
| * @param renderUnresolved render pages with unresolved idref's |
| * (done at end-of-document processing) |
| * @return true if the current page should be rendered |
| * false if the renderer doesn't support out of order |
| * rendering and there are pending pages |
| */ |
| protected boolean checkPreparedPages(PageViewport newpage, boolean |
| renderUnresolved) { |
| for (Iterator iter = prepared.iterator(); iter.hasNext();) { |
| PageViewport p = (PageViewport)iter.next(); |
| if (p.isResolved() || renderUnresolved) { |
| if (!renderer.supportsOutOfOrder() && p.getPageSequence().isFirstPage(p)) { |
| renderer.startPageSequence(this.currentPageSequence.getTitle()); |
| } |
| try { |
| renderer.renderPage(p); |
| if (!p.isResolved()) { |
| String[] idrefs = p.getIDRefs(); |
| for (int count = 0; count < idrefs.length; count++) { |
| log.warn("Page " + p.getPageNumberString() |
| + ": Unresolved id reference \"" + idrefs[count] |
| + "\" found."); |
| } |
| } |
| } catch (Exception e) { |
| // use error handler to handle this FOP or IO Exception |
| log.error(e); |
| } |
| p.clear(); |
| iter.remove(); |
| } else { |
| // if keeping order then stop at first page not resolved |
| if (!renderer.supportsOutOfOrder()) { |
| break; |
| } |
| } |
| } |
| return renderer.supportsOutOfOrder() || prepared.isEmpty(); |
| } |
| |
| /** |
| * Prepare a page. |
| * An unresolved page can be prepared if the renderer supports |
| * it and the page will be rendered later. |
| * @param page the page to prepare |
| */ |
| protected void preparePage(PageViewport page) { |
| if (renderer.supportsOutOfOrder()) { |
| renderer.preparePage(page); |
| } |
| prepared.add(page); |
| } |
| |
| /** |
| * @see org.apache.fop.area.AreaTreeModel#handleOffDocumentItem(OffDocumentItem) |
| */ |
| public void handleOffDocumentItem(OffDocumentItem oDI) { |
| switch(oDI.getWhenToProcess()) { |
| case OffDocumentItem.IMMEDIATELY: |
| renderer.processOffDocumentItem(oDI); |
| break; |
| case OffDocumentItem.AFTER_PAGE: |
| pendingODI.add(oDI); |
| break; |
| case OffDocumentItem.END_OF_DOC: |
| endDocODI.add(oDI); |
| break; |
| default: |
| throw new RuntimeException(); |
| } |
| } |
| |
| private void processOffDocumentItems(List list) { |
| for (int count = 0; count < list.size(); count++) { |
| OffDocumentItem oDI = (OffDocumentItem)list.get(count); |
| renderer.processOffDocumentItem(oDI); |
| } |
| } |
| |
| /** |
| * End the document. Render any end document OffDocumentItems |
| * @see org.apache.fop.area.AreaTreeModel#endDocument() |
| */ |
| public void endDocument() throws SAXException { |
| // render any pages that had unresolved ids |
| checkPreparedPages(null, true); |
| |
| processOffDocumentItems(pendingODI); |
| pendingODI.clear(); |
| processOffDocumentItems(endDocODI); |
| |
| try { |
| renderer.stopRenderer(); |
| } catch (IOException ex) { |
| throw new SAXException(ex); |
| } |
| } |
| } |
| |