123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- package org.apache.fop.apps;
-
- import java.io.OutputStream;
- import java.io.IOException;
- import java.util.Vector;
- import java.util.Enumeration;
-
- import org.xml.sax.SAXException;
-
- import org.apache.fop.layout.FontInfo;
- import org.apache.fop.layout.Page;
- import org.apache.fop.render.Renderer;
- import org.apache.fop.layout.AreaTree;
- import org.apache.fop.datatypes.IDReferences;
- import org.apache.fop.extensions.ExtensionObj;
- import org.apache.fop.fo.pagination.PageSequence;
-
- import org.apache.log.Logger;
-
- /**
- This class acts as a bridge between the XML:FO parser
- and the formatting/rendering classes. It will queue
- PageSequences up until all the IDs required by them
- are satisfied, at which time it will render the
- pages.<P>
-
- StreamRenderer is created by Driver and called from
- FOTreeBuilder when a PageSequence is created,
- and AreaTree when a Page is formatted.<P>
- */
- public class StreamRenderer {
- private static final boolean MEM_PROFILE_WITH_GC = false;
-
- /**
- Somewhere to get our stats from.
- */
- private Runtime runtime = Runtime.getRuntime();
-
- /**
- Keep track of the number of pages rendered.
- */
- int pageCount = 0;
-
- /**
- Keep track of heap memory allocated,
- for statistical purposes.
- */
- private long initialMemory;
-
- /**
- Keep track of time used by renderer.
- */
- private long startTime;
-
- /**
- The stream to which this rendering is to be
- written to. <B>Note</B> that some renderers
- do not render to a stream, and that this
- member can therefore be null.
- */
- private OutputStream outputStream;
-
- /**
- The renderer being used.
- */
- private Renderer renderer;
-
- /**
- The FontInfo for this renderer.
- */
- private FontInfo fontInfo = new FontInfo();
-
- /**
- The list of pages waiting to be renderered.
- */
- private Vector renderQueue = new Vector();
-
- /**
- The current set of IDReferences, passed to the
- areatrees and pages. This is used by the AreaTree
- as a single map of all IDs.
- */
- private IDReferences idReferences = new IDReferences();
-
- /**
- * The list of extensions.
- */
- private Vector extensions = new Vector();
-
- private Logger log;
-
- public StreamRenderer(OutputStream outputStream, Renderer renderer) {
- this.outputStream = outputStream;
- this.renderer = renderer;
- }
-
- public void setLogger(Logger logger) {
- log = logger;
- }
-
- public IDReferences getIDReferences() {
- return idReferences;
- }
-
- public void addExtension(ExtensionObj ext) {
- extensions.addElement(ext);
- }
-
- public void startRenderer()
- throws SAXException {
- pageCount = 0;
-
- if (MEM_PROFILE_WITH_GC)
- System.gc(); // This takes time but gives better results
-
- initialMemory = runtime.totalMemory() - runtime.freeMemory();
- startTime = System.currentTimeMillis();
-
- try {
- renderer.setupFontInfo(fontInfo);
- renderer.startRenderer(outputStream);
- } catch (IOException e) {
- throw new SAXException(e);
- }
- }
-
- public void stopRenderer()
- throws SAXException {
- /*
- Force the processing of any more queue elements,
- even if they are not resolved.
- */
- try {
- processQueue(true);
- renderer.stopRenderer();
- } catch (FOPException e) {
- throw new SAXException(e);
- }
- catch (IOException e) {
- throw new SAXException(e);
- }
-
- if (MEM_PROFILE_WITH_GC)
- System.gc(); // This takes time but gives better results
-
- long memoryNow = runtime.totalMemory() - runtime.freeMemory();
- long memoryUsed = (memoryNow - initialMemory) / 1024L;
-
- log.debug("Initial heap size: " + (initialMemory/1024L) + "Kb");
- log.debug("Current heap size: " + (memoryNow/1024L) + "Kb");
- log.debug("Total memory used: " + memoryUsed + "Kb");
-
- if (!MEM_PROFILE_WITH_GC) {
- log.debug(" Memory use is indicative; no GC was performed");
- log.debug(" These figures should not be used comparatively");
- }
-
- long timeUsed = System.currentTimeMillis() - startTime;
-
- log.debug("Total time used: " + timeUsed + "ms");
- log.debug("Pages rendererd: " + pageCount);
- log.debug("Avg render time: " + (timeUsed / pageCount) + "ms/page");
- }
-
- /**
- Format the PageSequence. The PageSequence
- formats Pages and adds them to the AreaTree,
- which subsequently calls the StreamRenderer
- instance (this) again to render the page.
- At this time the page might be printed
- or it might be queued. A page might not
- be renderable immediately if the IDReferences
- are not all valid. In this case we defer
- the rendering until they are all valid.
- */
- public void render(PageSequence pageSequence)
- throws SAXException {
- AreaTree a = new AreaTree(this);
- a.setFontInfo(fontInfo);
-
- for(Enumeration e = extensions.elements(); e.hasMoreElements(); ) {
- ExtensionObj ext = (ExtensionObj)e.nextElement();
- try {
- ext.format(a);
- } catch (FOPException fope) {
- throw new SAXException(fope);
- }
- }
-
- try {
- pageSequence.format(a);
- } catch (FOPException e) {
- throw new SAXException(e);
- }
- }
-
- public synchronized void queuePage(Page page)
- throws FOPException, IOException {
- /*
- Try to optimise on the common case that there are
- no pages pending and that all ID references are
- valid on the current pages. This short-cuts the
- pipeline and renders the area immediately.
- */
- if ((renderQueue.size() == 0) && idReferences.isEveryIdValid()) {
- //renderer.render(page, outputStream);
- } else {
- addToRenderQueue(page);
- }
- pageCount++;
- }
-
- private synchronized void addToRenderQueue(Page page)
- throws FOPException, IOException {
- RenderQueueEntry entry = new RenderQueueEntry(page);
- renderQueue.addElement(entry);
-
- /*
- The just-added entry could (possibly) resolve the
- waiting entries, so we try to process the queue
- now to see.
- */
- processQueue(false);
- }
-
- /**
- Try to process the queue from the first entry forward.
- If an entry can't be processed, then the queue can't
- move forward, so return.
- */
- private synchronized void processQueue(boolean force)
- throws FOPException, IOException {
- while (renderQueue.size() > 0) {
- RenderQueueEntry entry = (RenderQueueEntry) renderQueue.elementAt(0);
- if ((!force) && (!entry.isResolved()))
- break;
-
- //renderer.render(entry.getPage(), outputStream);
-
- /* TODO
- Enumeration rootEnumeration =
- entry.getAreaTree().getExtensions().elements();
- while (rootEnumeration.hasMoreElements())
- renderTree.addExtension((ExtensionObj) rootEnumeration.nextElement());
- */
-
- renderQueue.removeElementAt(0);
- }
- }
-
- /**
- A RenderQueueEntry consists of the Page to be queued,
- plus a list of outstanding ID references that need to be
- resolved before the Page can be renderered.<P>
- */
- class RenderQueueEntry extends Object {
- /*
- The Page that has outstanding ID references.
- */
- private Page page;
-
- /*
- A list of ID references (names).
- */
- private Vector unresolvedIdReferences = new Vector();
-
- public RenderQueueEntry(Page page) {
- this.page = page;
-
- Enumeration e = idReferences.getInvalidElements();
- while (e.hasMoreElements())
- unresolvedIdReferences.addElement(e.nextElement());
- }
-
- public Page getPage() {
- return page;
- }
-
- /**
- See if the outstanding references are resolved
- in the current copy of IDReferences.
- */
- public boolean isResolved() {
- if ((unresolvedIdReferences.size() == 0) || idReferences.isEveryIdValid())
- return true;
-
- //
- // See if any of the unresolved references are still unresolved.
- //
- Enumeration e = unresolvedIdReferences.elements();
- while (e.hasMoreElements())
- if (!idReferences.doesIDExist((String) e.nextElement()))
- return false;
-
- unresolvedIdReferences.removeAllElements();
- return true;
- }
- }
-
- public Page getNextPage(Page current, boolean isWithinPageSequence,
- boolean isFirstCall) {
- Page nextPage = null;
- int pageIndex = 0;
- if (isFirstCall)
- pageIndex = renderQueue.size();
- else
- pageIndex = renderQueue.indexOf(current);
- if ((pageIndex + 1) < renderQueue.size()) {
- nextPage = (Page)renderQueue.elementAt(pageIndex + 1);
- if (isWithinPageSequence
- &&!nextPage.getPageSequence().equals(current.getPageSequence())) {
- nextPage = null;
- }
- }
- return nextPage;
- }
-
- public Page getPreviousPage(Page current, boolean isWithinPageSequence,
- boolean isFirstCall) {
- Page previousPage = null;
- int pageIndex = 0;
- if (isFirstCall)
- pageIndex = renderQueue.size();
- else
- pageIndex = renderQueue.indexOf(current);
- // System.out.println("Page index = " + pageIndex);
- if ((pageIndex - 1) >= 0) {
- previousPage = (Page)renderQueue.elementAt(pageIndex - 1);
- PageSequence currentPS = current.getPageSequence();
- // System.out.println("Current PS = '" + currentPS + "'");
- PageSequence previousPS = previousPage.getPageSequence();
- // System.out.println("Previous PS = '" + previousPS + "'");
- if (isWithinPageSequence &&!previousPS.equals(currentPS)) {
- // System.out.println("Outside page sequence");
- previousPage = null;
- }
- }
- return previousPage;
- }
- }
|