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.

FOTreeHandler.java 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /* $Id$ */
  17. package org.apache.fop.fo;
  18. // Java
  19. import java.io.IOException;
  20. import java.io.OutputStream;
  21. import java.util.HashSet;
  22. import java.util.Iterator;
  23. // SAX
  24. import org.xml.sax.SAXException;
  25. // FOP
  26. import org.apache.fop.apps.FOUserAgent;
  27. import org.apache.fop.apps.FOPException;
  28. import org.apache.fop.area.AreaTree;
  29. import org.apache.fop.area.Title;
  30. import org.apache.fop.fo.extensions.Bookmarks;
  31. import org.apache.fop.fo.flow.BasicLink;
  32. import org.apache.fop.fo.flow.Block;
  33. import org.apache.fop.fo.flow.ExternalGraphic;
  34. import org.apache.fop.fo.flow.Footnote;
  35. import org.apache.fop.fo.flow.FootnoteBody;
  36. import org.apache.fop.fo.flow.InstreamForeignObject;
  37. import org.apache.fop.fo.flow.Inline;
  38. import org.apache.fop.fo.flow.Leader;
  39. import org.apache.fop.fo.flow.ListBlock;
  40. import org.apache.fop.fo.flow.ListItem;
  41. import org.apache.fop.fo.flow.PageNumber;
  42. import org.apache.fop.fo.flow.Table;
  43. import org.apache.fop.fo.flow.TableColumn;
  44. import org.apache.fop.fo.flow.TableBody;
  45. import org.apache.fop.fo.flow.TableCell;
  46. import org.apache.fop.fo.flow.TableRow;
  47. import org.apache.fop.fo.pagination.Flow;
  48. import org.apache.fop.fo.pagination.PageSequence;
  49. import org.apache.fop.layoutmgr.AddLMVisitor;
  50. import org.apache.fop.layoutmgr.ContentLayoutManager;
  51. import org.apache.fop.layoutmgr.InlineStackingLayoutManager;
  52. import org.apache.fop.layoutmgr.LMiter;
  53. import org.apache.fop.layoutmgr.PageLayoutManager;
  54. import org.apache.fop.render.Renderer;
  55. /**
  56. * Defines how SAX events specific to XSL-FO input should be handled when
  57. * an FO Tree needs to be built.
  58. * This initiates layout processes and corresponding
  59. * rendering processes such as start/end.
  60. * @see FOInputHandler
  61. */
  62. public class FOTreeHandler extends FOInputHandler {
  63. // TODO: Collecting of statistics should be configurable
  64. private final boolean collectStatistics = true;
  65. private static final boolean MEM_PROFILE_WITH_GC = false;
  66. private boolean pageSequenceFound = false;
  67. /**
  68. * Somewhere to get our stats from.
  69. */
  70. private Runtime runtime;
  71. /** The current AreaTree for the FOTreeHandler. */
  72. public AreaTree areaTree;
  73. /**
  74. * Keep track of the number of pages rendered.
  75. */
  76. private int pageCount;
  77. /**
  78. * Keep track of heap memory allocated,
  79. * for statistical purposes.
  80. */
  81. private long initialMemory;
  82. /**
  83. * Keep track of time used by renderer.
  84. */
  85. private long startTime;
  86. /** Useful only for allowing subclasses of AddLMVisitor to be set by those
  87. extending FOP **/
  88. private AddLMVisitor addLMVisitor = null;
  89. /**
  90. * the renderer to use to output the area tree
  91. */
  92. private Renderer renderer;
  93. /**
  94. * Main constructor
  95. * @param userAgent the apps.userAgent implementation that governs
  96. * this FO Tree
  97. * @param OutputStream stream to use to output results of renderer
  98. *
  99. * @param store if true then use the store pages model and keep the
  100. * area tree in memory
  101. */
  102. public FOTreeHandler(FOUserAgent userAgent, int renderType,
  103. OutputStream stream, boolean store) throws FOPException {
  104. super(userAgent);
  105. if (foUserAgent.getRendererOverride() != null) {
  106. renderer = foUserAgent.getRendererOverride();
  107. } else {
  108. renderer = createRenderer(renderType);
  109. renderer.setUserAgent(foUserAgent);
  110. }
  111. areaTree = new AreaTree(renderer);
  112. try {
  113. renderer.setupFontInfo(fontInfo);
  114. // check that the "any,normal,400" font exists
  115. if (!fontInfo.isSetupValid()) {
  116. throw new FOPException(
  117. "No default font defined by OutputConverter");
  118. }
  119. renderer.startRenderer(stream);
  120. } catch (IOException e) {
  121. throw new FOPException(e);
  122. }
  123. if (collectStatistics) {
  124. runtime = Runtime.getRuntime();
  125. }
  126. }
  127. /**
  128. * Creates a Renderer object based on render-type desired
  129. * @param renderType the type of renderer to use
  130. * @return Renderer the new Renderer instance
  131. * @throws IllegalArgumentException if an unsupported renderer type was requested
  132. */
  133. private Renderer createRenderer(int renderType) throws IllegalArgumentException {
  134. switch (renderType) {
  135. case Constants.RENDER_PDF:
  136. return new org.apache.fop.render.pdf.PDFRenderer();
  137. case Constants.RENDER_AWT:
  138. return new org.apache.fop.render.awt.AWTRenderer();
  139. case Constants.RENDER_PRINT:
  140. return new org.apache.fop.render.awt.AWTPrintRenderer();
  141. case Constants.RENDER_PCL:
  142. return new org.apache.fop.render.pcl.PCLRenderer();
  143. case Constants.RENDER_PS:
  144. return new org.apache.fop.render.ps.PSRenderer();
  145. case Constants.RENDER_TXT:
  146. return new org.apache.fop.render.txt.TXTRenderer();
  147. case Constants.RENDER_XML:
  148. return new org.apache.fop.render.xml.XMLRenderer();
  149. case Constants.RENDER_SVG:
  150. return new org.apache.fop.render.svg.SVGRenderer();
  151. default:
  152. throw new IllegalArgumentException("Invalid renderer type "
  153. + renderType);
  154. }
  155. }
  156. /**
  157. * Start the document.
  158. * This starts the document in the renderer.
  159. *
  160. * @throws SAXException if there is an error
  161. */
  162. public void startDocument() throws SAXException {
  163. //Initialize statistics
  164. if (collectStatistics) {
  165. pageCount = 0;
  166. if (MEM_PROFILE_WITH_GC) {
  167. System.gc(); // This takes time but gives better results
  168. }
  169. initialMemory = runtime.totalMemory() - runtime.freeMemory();
  170. startTime = System.currentTimeMillis();
  171. }
  172. }
  173. /**
  174. * End the document.
  175. *
  176. * @throws SAXException if there is some error
  177. */
  178. public void endDocument() throws SAXException {
  179. try {
  180. if (pageSequenceFound == false) {
  181. throw new SAXException("Error: No fo:page-sequence child " +
  182. "found within fo:root element.");
  183. }
  184. areaTree.endDocument();
  185. renderer.stopRenderer();
  186. } catch (IOException ex) {
  187. throw new SAXException(ex);
  188. }
  189. if (collectStatistics) {
  190. if (MEM_PROFILE_WITH_GC) {
  191. // This takes time but gives better results
  192. System.gc();
  193. }
  194. long memoryNow = runtime.totalMemory() - runtime.freeMemory();
  195. long memoryUsed = (memoryNow - initialMemory) / 1024L;
  196. long timeUsed = System.currentTimeMillis() - startTime;
  197. if (logger != null && logger.isDebugEnabled()) {
  198. logger.debug("Initial heap size: " + (initialMemory / 1024L) + "Kb");
  199. logger.debug("Current heap size: " + (memoryNow / 1024L) + "Kb");
  200. logger.debug("Total memory used: " + memoryUsed + "Kb");
  201. if (!MEM_PROFILE_WITH_GC) {
  202. logger.debug(" Memory use is indicative; no GC was performed");
  203. logger.debug(" These figures should not be used comparatively");
  204. }
  205. logger.debug("Total time used: " + timeUsed + "ms");
  206. logger.debug("Pages rendered: " + pageCount);
  207. if (pageCount > 0) {
  208. logger.debug("Avg render time: " + (timeUsed / pageCount) + "ms/page");
  209. }
  210. }
  211. }
  212. }
  213. /**
  214. * Start a page sequence.
  215. * At the start of a page sequence it can start the page sequence
  216. * on the area tree with the page sequence title.
  217. *
  218. * @param pageSeq the page sequence starting
  219. */
  220. public void startPageSequence(PageSequence pageSeq) {
  221. pageSequenceFound = true;
  222. }
  223. /**
  224. * End the PageSequence.
  225. * The PageSequence formats Pages and adds them to the AreaTree.
  226. * The area tree then handles what happens with the pages.
  227. *
  228. * @param pageSequence the page sequence ending
  229. * @throws FOPException if there is an error formatting the pages
  230. */
  231. public void endPageSequence(PageSequence pageSequence)
  232. throws FOPException {
  233. //areaTree.setFontInfo(fontInfo);
  234. if (collectStatistics) {
  235. if (MEM_PROFILE_WITH_GC) {
  236. // This takes time but gives better results
  237. System.gc();
  238. }
  239. long memoryNow = runtime.totalMemory() - runtime.freeMemory();
  240. if (logger != null) {
  241. logger.debug("Current heap size: " + (memoryNow / 1024L) + "Kb");
  242. }
  243. }
  244. areaTree.addBookmarksToAreaTree(pageSequence.getRoot().getBookmarks());
  245. formatPageSequence(pageSequence, areaTree);
  246. }
  247. /**
  248. * @see org.apache.fop.fo.FOInputHandler#startFlow(Flow)
  249. */
  250. public void startFlow(Flow fl) {
  251. }
  252. /**
  253. * @see org.apache.fop.fo.FOInputHandler#endFlow(Flow)
  254. */
  255. public void endFlow(Flow fl) {
  256. }
  257. /**
  258. * @see org.apache.fop.fo.FOInputHandler#startBlock(Block)
  259. */
  260. public void startBlock(Block bl) {
  261. }
  262. /**
  263. * @see org.apache.fop.fo.FOInputHandler#endBlock(Block)
  264. */
  265. public void endBlock(Block bl) {
  266. }
  267. /**
  268. *
  269. * @param inl Inline that is starting.
  270. */
  271. public void startInline(Inline inl){
  272. }
  273. /**
  274. *
  275. * @param inl Inline that is ending.
  276. */
  277. public void endInline(Inline inl){
  278. }
  279. /**
  280. * @see org.apache.fop.fo.FOInputHandler#startTable(Table)
  281. */
  282. public void startTable(Table tbl) {
  283. }
  284. /**
  285. * @see org.apache.fop.fo.FOInputHandler#endTable(Table)
  286. */
  287. public void endTable(Table tbl) {
  288. }
  289. /**
  290. *
  291. * @param tc TableColumn that is starting;
  292. */
  293. public void startColumn(TableColumn tc) {
  294. }
  295. /**
  296. *
  297. * @param tc TableColumn that is ending;
  298. */
  299. public void endColumn(TableColumn tc) {
  300. }
  301. /**
  302. * @see org.apache.fop.fo.FOInputHandler#startHeader(TableBody)
  303. */
  304. public void startHeader(TableBody th) {
  305. }
  306. /**
  307. * @see org.apache.fop.fo.FOInputHandler#endHeader(TableBody)
  308. */
  309. public void endHeader(TableBody th) {
  310. }
  311. /**
  312. * @see org.apache.fop.fo.FOInputHandler#startFooter(TableBody)
  313. */
  314. public void startFooter(TableBody tf) {
  315. }
  316. /**
  317. * @see org.apache.fop.fo.FOInputHandler#endFooter(TableBody)
  318. */
  319. public void endFooter(TableBody tf) {
  320. }
  321. /**
  322. * @see org.apache.fop.fo.FOInputHandler#startBody(TableBody)
  323. */
  324. public void startBody(TableBody tb) {
  325. }
  326. /**
  327. * @see org.apache.fop.fo.FOInputHandler#endBody(TableBody)
  328. */
  329. public void endBody(TableBody tb) {
  330. }
  331. /**
  332. * @see org.apache.fop.fo.FOInputHandler#startRow(TableRow)
  333. */
  334. public void startRow(TableRow tr) {
  335. }
  336. /**
  337. * @see org.apache.fop.fo.FOInputHandler#endRow(TableRow)
  338. */
  339. public void endRow(TableRow tr) {
  340. }
  341. /**
  342. * @see org.apache.fop.fo.FOInputHandler#startCell(TableCell)
  343. */
  344. public void startCell(TableCell tc) {
  345. }
  346. /**
  347. * @see org.apache.fop.fo.FOInputHandler#endCell(TableCell)
  348. */
  349. public void endCell(TableCell tc) {
  350. }
  351. // Lists
  352. /**
  353. * @see org.apache.fop.fo.FOInputHandler#startList(ListBlock)
  354. */
  355. public void startList(ListBlock lb) {
  356. }
  357. /**
  358. * @see org.apache.fop.fo.FOInputHandler#endList(ListBlock)
  359. */
  360. public void endList(ListBlock lb) {
  361. }
  362. /**
  363. * @see org.apache.fop.fo.FOInputHandler#startListItem(ListItem)
  364. */
  365. public void startListItem(ListItem li) {
  366. }
  367. /**
  368. * @see org.apache.fop.fo.FOInputHandler#endListItem(ListItem)
  369. */
  370. public void endListItem(ListItem li) {
  371. }
  372. /**
  373. * @see org.apache.fop.fo.FOInputHandler#startListLabel()
  374. */
  375. public void startListLabel() {
  376. }
  377. /**
  378. * @see org.apache.fop.fo.FOInputHandler#endListLabel()
  379. */
  380. public void endListLabel() {
  381. }
  382. /**
  383. * @see org.apache.fop.fo.FOInputHandler#startListBody()
  384. */
  385. public void startListBody() {
  386. }
  387. /**
  388. * @see org.apache.fop.fo.FOInputHandler#endListBody()
  389. */
  390. public void endListBody() {
  391. }
  392. // Static Regions
  393. /**
  394. * @see org.apache.fop.fo.FOInputHandler#startStatic()
  395. */
  396. public void startStatic() {
  397. }
  398. /**
  399. * @see org.apache.fop.fo.FOInputHandler#endStatic()
  400. */
  401. public void endStatic() {
  402. }
  403. /**
  404. * @see org.apache.fop.fo.FOInputHandler#startMarkup()
  405. */
  406. public void startMarkup() {
  407. }
  408. /**
  409. * @see org.apache.fop.fo.FOInputHandler#endMarkup()
  410. */
  411. public void endMarkup() {
  412. }
  413. /**
  414. * @see org.apache.fop.fo.FOInputHandler#startLink(BasicLink basicLink)
  415. */
  416. public void startLink(BasicLink basicLink) {
  417. }
  418. /**
  419. * @see org.apache.fop.fo.FOInputHandler#endLink()
  420. */
  421. public void endLink() {
  422. }
  423. /**
  424. * @see org.apache.fop.fo.FOInputHandler#image(ExternalGraphic)
  425. */
  426. public void image(ExternalGraphic eg) {
  427. }
  428. /**
  429. * @see org.apache.fop.fo.FOInputHandler#pageRef()
  430. */
  431. public void pageRef() {
  432. }
  433. /**
  434. * @see org.apache.fop.fo.FOInputHandler#foreignObject(InstreamForeignObject)
  435. */
  436. public void foreignObject(InstreamForeignObject ifo) {
  437. }
  438. /**
  439. * @see org.apache.fop.fo.FOInputHandler#startFootnote(Footnote)
  440. */
  441. public void startFootnote(Footnote footnote) {
  442. }
  443. /**
  444. * @see org.apache.fop.fo.FOInputHandler#endFootnote(Footnote)
  445. */
  446. public void endFootnote(Footnote footnote) {
  447. }
  448. /**
  449. * @see org.apache.fop.fo.FOInputHandler#startFootnoteBody(FootnoteBody)
  450. */
  451. public void startFootnoteBody(FootnoteBody body) {
  452. }
  453. /**
  454. * @see org.apache.fop.fo.FOInputHandler#endFootnoteBody(FootnoteBody)
  455. */
  456. public void endFootnoteBody(FootnoteBody body) {
  457. }
  458. /**
  459. * @see org.apache.fop.fo.FOInputHandler#leader(Leader)
  460. */
  461. public void leader(Leader l) {
  462. }
  463. /**
  464. * @see org.apache.fop.fo.FOInputHandler#characters(char[], int, int)
  465. */
  466. public void characters(char[] data, int start, int length) {
  467. }
  468. /**
  469. * Runs the formatting of this page sequence into the given area tree
  470. *
  471. * @param pageSeq the PageSequence to be formatted
  472. * @param areaTree the area tree to format this page sequence into
  473. * @throws FOPException if there is an error formatting the contents
  474. */
  475. private void formatPageSequence(PageSequence pageSeq, AreaTree areaTree)
  476. throws FOPException {
  477. Title title = null;
  478. if (pageSeq.getTitleFO() != null) {
  479. title = getTitleArea(pageSeq.getTitleFO());
  480. }
  481. areaTree.startPageSequence(title);
  482. // Make a new PageLayoutManager and a FlowLayoutManager
  483. // Run the PLM in a thread
  484. // Wait for them to finish.
  485. // If no main flow, nothing to layout!
  486. if (pageSeq.getMainFlow() == null) {
  487. return;
  488. }
  489. // Initialize if already used?
  490. // this.layoutMasterSet.resetPageMasters();
  491. if (pageSeq.getPageSequenceMaster() != null) {
  492. pageSeq.getPageSequenceMaster().reset();
  493. }
  494. pageSeq.initPageNumber();
  495. // This will layout pages and add them to the area tree
  496. PageLayoutManager pageLM = new PageLayoutManager(areaTree, pageSeq,
  497. this);
  498. pageLM.setPageCounting(pageSeq.getCurrentPageNumber(),
  499. pageSeq.getPageNumberGenerator());
  500. // For now, skip the threading and just call run directly.
  501. pageLM.run();
  502. // Thread layoutThread = new Thread(pageLM);
  503. // layoutThread.start();
  504. // log.debug("Layout thread started");
  505. // // wait on both managers
  506. // try {
  507. // layoutThread.join();
  508. // log.debug("Layout thread done");
  509. // } catch (InterruptedException ie) {
  510. // log.error("PageSequence.format() interrupted waiting on layout");
  511. // }
  512. pageSeq.setCurrentPageNumber(pageLM.getPageCount());
  513. // Tell the root the last page number we created.
  514. pageSeq.getRoot().setRunningPageNumberCounter(pageSeq.getCurrentPageNumber());
  515. }
  516. /**
  517. * @return the Title area
  518. */
  519. private org.apache.fop.area.Title getTitleArea(org.apache.fop.fo.pagination.Title foTitle) {
  520. // use special layout manager to add the inline areas
  521. // to the Title.
  522. InlineStackingLayoutManager lm;
  523. lm = new InlineStackingLayoutManager(foTitle);
  524. lm.setLMiter(new LMiter(lm, foTitle.children.listIterator()));
  525. lm.initialize();
  526. // get breaks then add areas to title
  527. org.apache.fop.area.Title title =
  528. new org.apache.fop.area.Title();
  529. ContentLayoutManager clm = new ContentLayoutManager(title);
  530. clm.setUserAgent(foTitle.getUserAgent());
  531. lm.setParent(clm);
  532. clm.fillArea(lm);
  533. return title;
  534. }
  535. /**
  536. * Public accessor to set the AddLMVisitor object that should be used.
  537. * This allows subclasses of AddLMVisitor to be used, which can be useful
  538. * for extensions to the FO Tree.
  539. * @param addLMVisitor the AddLMVisitor object that should be used.
  540. */
  541. public void setAddLMVisitor(AddLMVisitor addLMVisitor) {
  542. this.addLMVisitor = addLMVisitor;
  543. }
  544. /**
  545. * Public accessor to get the AddLMVisitor object that should be used.
  546. * @return the AddLMVisitor object that should be used.
  547. */
  548. public AddLMVisitor getAddLMVisitor() {
  549. if (this.addLMVisitor == null) {
  550. this.addLMVisitor = new AddLMVisitor();
  551. }
  552. return this.addLMVisitor;
  553. }
  554. /**
  555. *
  556. * @param pagenum PageNumber that is starting.
  557. */
  558. public void startPageNumber(PageNumber pagenum) {
  559. }
  560. /**
  561. *
  562. * @param pagenum PageNumber that is ending.
  563. */
  564. public void endPageNumber(PageNumber pagenum) {
  565. }
  566. }