blob: c40ff156a6b6c6a3de625d75c4b45c9c2393e759 [file] [log] [blame]
/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed 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.fonts.FontInfo;
import org.apache.fop.render.Renderer;
import org.apache.fop.render.RendererFactory;
/**
* 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 renderType Desired fo.Constants output type (RENDER_PDF,
* RENDER_PS, etc.)
* @param fontInfo FontInfo object
* @param stream OutputStream
* @throws FOPException if the renderer cannot be properly initialized
*/
public RenderPagesModel (FOUserAgent userAgent, int renderType,
FontInfo fontInfo, OutputStream stream) throws FOPException {
super();
renderer = RendererFactory.createRenderer(userAgent, renderType);
try {
renderer.setupFontInfo(fontInfo);
// check that the "any,normal,400" font exists
if (!fontInfo.isSetupValid()) {
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);
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 done = renderer.supportsOutOfOrder() && page.isResolved();
if (done) {
try {
renderer.renderPage(page);
} catch (Exception e) {
// use error handler to handle this FOP or IO Exception
e.printStackTrace();
}
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) {
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
e.printStackTrace();
}
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;
}
}
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);
}
}
}