Phase 0: Preparation This chapter describes the structure of FOP as it was in the first quarter of 2004. In the second quarter of that year the top level structure was strongly refactored. The new situation is not described here.
The preparation process FOP's processing model is the SAX parsing model: Construct a suitable content handler object of type org.xml.sax.ContentHandler, create a parser of type org.xml.sax.XMLReader, register the content handler with the parser, call the parser's parse method on the input source. From there on the parser takes control. For every XML event it passes control to the appropriate content handler methods. When these methods return, parsing continues until the next XML event is encountered. Once the parser has taken control, its content handler is the only entry point into FOP's data structures and methods. The preparatory phase of FOP concerns itself with the construction of a suitable content handler object, whose methods allow FOP's process to handle the FO elements reported by the parser and build the required output document. An application may choose to deal with the whole preparatory phase itself, and then call the parser's parse method. The input source may be an FO file, which may be fed to the parse method as a string or as an org.xml.sax.InputSource object. Alternatively, a DOM document object may be used as input, e.g. the output of an XSLT processor. In that case: the parser should be of type org.apache.fop.tools.DocumentReader, the input source should be of type org.apache.fop.tools.DocumentInputSource, created with the DOM document as the argument of the constructor. The classes Fop and Driver contain methods which applications may use as more convenient entry points into FOP. The method Fop.main may be called with the input and output file names as arguments. This is mainly useful for starting Fop from the command line. The class Driver contains a method getContentHandler, which can be used to create a suitable content handler. It also contains three render methods which are convenient entry points for applications. These 4 methods may be invoked on a driver object which already has the following members: userAgent, renderer, log, stream. In addition, the driver object may have the following members: a TreeBuilder object having a member userAgent, and a Document object, which may have a member layoutStrategy. Using one's own TreeBuilder and Document objects allows one to customize FOP's behaviour in a major way. The render methods invoke getContentHandler to create a suitable content handler. They register it as the content handler of the parser. They register the member currentDocument as a tree listener to the member foInputHandler. A suitable org.xml.sax.ContentHandler object for FOP processing is an object of type org.apache.fop.fo.FOTreeBuilder and has the following structure: treeBuilder | +--------------+------------------+ | | | foInputHandler userAgent foTreeControl | | foTreeControl driver foTreeListeners: usedFonts [foTreeControl] triplets fonts layoutStrategy -- foTreeControl areaTree -- atModel, foTreeControl atModel -- renderer foInputHandler The driver and renderer objects are complex objects: driver renderer | | treeBuilder foTreeControl renderer userAgent foInputHandler fontList ostream ostream userAgent foTreeControl
A detailed overview of the objects treeBuilder = { fobjTable: instance of java.util.HashMap(id=589) namespaces: instance of java.util.HashSet(id=590) currentFObj: null rootFObj: null foInputHandler: instance of org.apache.fop.fo.FOTreeHandler(id=591) userAgent: instance of org.apache.fop.apps.FOUserAgent(id=592) foTreeControl: instance of org.apache.fop.apps.Document(id=593) class$org$apache$fop$fo$ElementMapping: instance of java.lang.Class(reflected class=org.apache.fop.fo.ElementMapping, id=450) } treeBuilder.foInputHandler = { collectStatistics: true MEM_PROFILE_WITH_GC: false runtime: instance of java.lang.Runtime(id=595) pageCount: 0 initialMemory: 0 startTime: 0 foTreeListeners: instance of java.util.HashSet(id=596) org.apache.fop.fo.FOInputHandler.foTreeControl: instance of org.apache.fop.apps.Document(id=593) org.apache.avalon.framework.logger.AbstractLogEnabled.m_logger: instance of org.apache.avalon.framework.logger.ConsoleLogger(id=597) } treeBuilder.foTreeControl = "org.apache.fop.apps.Document@125844f" treeBuilder.foInputHandler.foTreeListeners = "[org.apache.fop.apps.Document@125844f]" treeBuilder.userAgent = { log: instance of org.apache.avalon.framework.logger.ConsoleLogger(id=597) defaults: instance of java.util.HashMap(id=601) handlers: instance of java.util.HashMap(id=602) baseURL: "" pdfEncryptionParams: null px2mm: 0.35277778 } treeBuilder.foTreeControl = { driver: instance of org.apache.fop.apps.Driver(id=587) usedFonts: instance of java.util.HashMap(id=604) triplets: instance of java.util.HashMap(id=605) fonts: instance of java.util.HashMap(id=606) layoutStrategy: instance of org.apache.fop.layoutmgr.LayoutManagerLS(id=607) areaTree: instance of org.apache.fop.area.AreaTree(id=608) atModel: instance of org.apache.fop.area.RenderPagesModel(id=609) bookmarks: null idReferences: instance of java.util.HashSet(id=610) foInputHandler: instance of org.apache.fop.fo.FOTreeHandler(id=591) } treeBuilder.foTreeControl.driver = { NOT_SET: 0 RENDER_PDF: 1 RENDER_AWT: 2 RENDER_MIF: 3 RENDER_XML: 4 RENDER_PRINT: 5 RENDER_PCL: 6 RENDER_PS: 7 RENDER_TXT: 8 RENDER_SVG: 9 RENDER_RTF: 10 treeBuilder: instance of org.apache.fop.fo.FOTreeBuilder(id=588) rendererType: 1 renderer: instance of org.apache.fop.render.pdf.PDFRenderer(id=599) foInputHandler: instance of org.apache.fop.fo.FOTreeHandler(id=591) source: null stream: instance of java.io.BufferedOutputStream(id=600) reader: null log: instance of org.apache.avalon.framework.logger.ConsoleLogger(id=597) userAgent: instance of org.apache.fop.apps.FOUserAgent(id=592) currentDocument: instance of org.apache.fop.apps.Document(id=593) } treeBuilder.foTreeControl.areaTree = { model: instance of org.apache.fop.area.RenderPagesModel(id=609) atControl: instance of org.apache.fop.apps.Document(id=593) idLocations: instance of java.util.HashMap(id=615) resolve: instance of java.util.HashMap(id=616) treeExtensions: instance of java.util.ArrayList(id=617) } treeBuilder.foTreeControl.atModel = { renderer: instance of org.apache.fop.render.pdf.PDFRenderer(id=599) prepared: instance of java.util.ArrayList(id=618) pendingExt: instance of java.util.ArrayList(id=619) endDocExt: instance of java.util.ArrayList(id=620) org.apache.fop.area.StorePagesModel.pageSequence: null org.apache.fop.area.StorePagesModel.titles: instance of java.util.ArrayList(id=621) org.apache.fop.area.StorePagesModel.currSequence: null org.apache.fop.area.StorePagesModel.extensions: instance of java.util.ArrayList(id=622) } treeBuilder.foTreeControl.atModel.renderer = { MIME_TYPE: "application/pdf" pdfDoc: instance of org.apache.fop.pdf.PDFDocument(id=624) pages: null pageReferences: instance of java.util.HashMap(id=625) pvReferences: instance of java.util.HashMap(id=626) ostream: instance of java.io.BufferedOutputStream(id=600) pdfResources: null currentStream: null currentContext: null currentPage: null currentState: null currentFontName: "" currentFontSize: 0 pageHeight: 0 filterMap: null textOpen: false prevWordY: 0 prevWordX: 0 prevWordWidth: 0 wordAreaPDF: instance of java.lang.StringBuffer(id=627) BPMarginOffset: 0 IPMarginOffset: 0 org.apache.fop.render.PrintRenderer.fontInfo: instance of org.apache.fop.apps.Document(id=593) org.apache.fop.render.PrintRenderer.fontList: null org.apache.fop.render.AbstractRenderer.userAgent: instance of org.apache.fop.apps.FOUserAgent(id=592) org.apache.fop.render.AbstractRenderer.producer: "FOP 1.0dev" org.apache.fop.render.AbstractRenderer.creator: null org.apache.fop.render.AbstractRenderer.creationDate: null org.apache.fop.render.AbstractRenderer.options: instance of java.util.HashMap(id=629) org.apache.fop.render.AbstractRenderer.currentBPPosition: 0 org.apache.fop.render.AbstractRenderer.currentIPPosition: 0 org.apache.fop.render.AbstractRenderer.currentBlockIPPosition: 0 org.apache.fop.render.AbstractRenderer.containingBPPosition: 0 org.apache.fop.render.AbstractRenderer.containingIPPosition: 0 org.apache.avalon.framework.logger.AbstractLogEnabled.m_logger: instance of org.apache.avalon.framework.logger.ConsoleLogger(id=597) } treeBuilder.foTreeControl.layoutStrategy = { name: "layoutmgr" addLMVisitor: null org.apache.fop.layout.LayoutStrategy.name: "undefined" org.apache.fop.layout.LayoutStrategy.document: instance of org.apache.fop.apps.Document(id=593) } treeBuilder.foTreeControl.atModel.renderer.ostream = { buf: instance of byte[512] (id=632) count: 15 java.io.FilterOutputStream.out: instance of java.io.FileOutputStream(id=633) } For the members fontList, fonts, usedFonts and triplets of treeBuilder.foTreeControl, see under Fonts.
A detailed overview of the entry methods Already created (e.g. in Fop.main): an object of type Driver with the members userAgent, renderer, log, stream. To create userAgent one may use Driver.getUserAgent: if driver does not have userAgent, create a new UserAgent. To create renderer one may use one of three methods: setRenderer(int renderer) setRenderer(String rendererClassName) setRenderer(Renderer renderer) All three methods set the FOP version on the renderer, and register userAgent with it, which is obtained using Driver.getUserAgent. render(InputHandler inputHandler): creates XMLReader parser, InputSource source; calls render(XMLReader parser, InputSource source). render(org.w3c.dom.Document document): creates DocumentReader reader, DocumentInputSource source; calls render(XMLReader parser, InputSource source). render(XMLReader parser, InputSource source): creates content handler by calling getContentHandler(). registers the content handler with the parser. Adds currentDocument as a tree listener to foInputHandler. calls parser.parse(source). getContentHandler(): if driver does not have a treeBuilder, call initialize(): create a new TreeBuilder, set the UserAgent on it. if driver does not have a currentDocument, create a new Document. create a new FOTreeHandler foInputHandler using currentDocument as an argument (currentDocument is member foTreeControl in foInputHandler). create a new AreaTree using currentDocument as an argument, and register it with currentDocument. create a new RenderPagesModel using renderer as an argument, and register it with currentDocument and with currentDocument.areaTree. register currentDocument with the renderer (currentDocument is member fontInfo in renderer); setup fontList in currentDocument. start the renderer with the outputstream. register foInputHandler with currentDocument. if currentDocument does not have a layoutStrategy, create a new LayoutStrategyLS for it with currentDocument as an argument. register userAgent, foInputHandler and currentDocument with treeBuilder (currentDocument is member foTreeControl in treeBuilder). return treeBuilder.