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.

FOUserAgent.java 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.apps;
  19. // Java
  20. import java.io.File;
  21. import java.net.MalformedURLException;
  22. import java.util.Date;
  23. import java.util.Map;
  24. import javax.xml.transform.Source;
  25. import javax.xml.transform.TransformerException;
  26. import javax.xml.transform.URIResolver;
  27. import org.apache.commons.logging.Log;
  28. import org.apache.commons.logging.LogFactory;
  29. import org.apache.xmlgraphics.image.loader.ImageContext;
  30. import org.apache.xmlgraphics.image.loader.ImageSessionContext;
  31. import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext;
  32. import org.apache.xmlgraphics.util.UnitConv;
  33. import org.apache.fop.Version;
  34. import org.apache.fop.accessibility.Accessibility;
  35. import org.apache.fop.accessibility.DummyStructureTreeEventHandler;
  36. import org.apache.fop.accessibility.StructureTreeEventHandler;
  37. import org.apache.fop.events.DefaultEventBroadcaster;
  38. import org.apache.fop.events.Event;
  39. import org.apache.fop.events.EventBroadcaster;
  40. import org.apache.fop.events.EventListener;
  41. import org.apache.fop.events.FOPEventListenerProxy;
  42. import org.apache.fop.events.LoggingEventListener;
  43. import org.apache.fop.fo.FOEventHandler;
  44. import org.apache.fop.fonts.FontManager;
  45. import org.apache.fop.render.Renderer;
  46. import org.apache.fop.render.RendererFactory;
  47. import org.apache.fop.render.XMLHandlerRegistry;
  48. import org.apache.fop.render.intermediate.IFDocumentHandler;
  49. /**
  50. * This is the user agent for FOP.
  51. * It is the entity through which you can interact with the XSL-FO processing and is
  52. * used by the processing to obtain user configurable options.
  53. * <p>
  54. * Renderer specific extensions (that do not produce normal areas on
  55. * the output) will be done like so:
  56. * <br>
  57. * The extension will create an area, custom if necessary
  58. * <br>
  59. * this area will be added to the user agent with a key
  60. * <br>
  61. * the renderer will know keys for particular extensions
  62. * <br>
  63. * eg. bookmarks will be held in a special hierarchical area representing
  64. * the title and bookmark structure
  65. * <br>
  66. * These areas may contain resolvable areas that will be processed
  67. * with other resolvable areas
  68. */
  69. public class FOUserAgent {
  70. /** Defines the default target resolution (72dpi) for FOP */
  71. public static final float DEFAULT_TARGET_RESOLUTION
  72. = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION;
  73. private static Log log = LogFactory.getLog("FOP");
  74. private FopFactory factory;
  75. /**
  76. * The base URL for all URL resolutions, especially for
  77. * external-graphics.
  78. */
  79. private String base = null;
  80. /** A user settable URI Resolver */
  81. private URIResolver uriResolver = null;
  82. private float targetResolution = FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION;
  83. private Map rendererOptions = new java.util.HashMap();
  84. private File outputFile = null;
  85. private IFDocumentHandler documentHandlerOverride = null;
  86. private Renderer rendererOverride = null;
  87. private FOEventHandler foEventHandlerOverride = null;
  88. private boolean locatorEnabled = true; // true by default (for error messages).
  89. private boolean conserveMemoryPolicy = false;
  90. private EventBroadcaster eventBroadcaster = new FOPEventBroadcaster();
  91. private StructureTreeEventHandler structureTreeEventHandler
  92. = DummyStructureTreeEventHandler.INSTANCE;
  93. /** Producer: Metadata element for the system/software that produces
  94. * the document. (Some renderers can store this in the document.)
  95. */
  96. protected String producer = "Apache FOP Version " + Version.getVersion();
  97. /** Creator: Metadata element for the user that created the
  98. * document. (Some renderers can store this in the document.)
  99. */
  100. protected String creator = null;
  101. /** Creation Date: Override of the date the document was created.
  102. * (Some renderers can store this in the document.)
  103. */
  104. protected Date creationDate = null;
  105. /** Author of the content of the document. */
  106. protected String author = null;
  107. /** Title of the document. */
  108. protected String title = null;
  109. /** Subject of the document. */
  110. protected String subject = null;
  111. /** Set of keywords applicable to this document. */
  112. protected String keywords = null;
  113. private ImageSessionContext imageSessionContext = new AbstractImageSessionContext() {
  114. public ImageContext getParentContext() {
  115. return getFactory();
  116. }
  117. public float getTargetResolution() {
  118. return FOUserAgent.this.getTargetResolution();
  119. }
  120. public Source resolveURI(String uri) {
  121. return FOUserAgent.this.resolveURI(uri);
  122. }
  123. };
  124. /**
  125. * Main constructor. <b>This constructor should not be called directly. Please use the
  126. * methods from FopFactory to construct FOUserAgent instances!</b>
  127. * @param factory the factory that provides environment-level information
  128. * @see org.apache.fop.apps.FopFactory
  129. */
  130. public FOUserAgent(FopFactory factory) {
  131. if (factory == null) {
  132. throw new NullPointerException("The factory parameter must not be null");
  133. }
  134. this.factory = factory;
  135. setBaseURL(factory.getBaseURL());
  136. setTargetResolution(factory.getTargetResolution());
  137. setAccessibility(factory.isAccessibilityEnabled());
  138. }
  139. /** @return the associated FopFactory instance */
  140. public FopFactory getFactory() {
  141. return this.factory;
  142. }
  143. // ---------------------------------------------- rendering-run dependent stuff
  144. /**
  145. * Sets an explicit document handler to use which overrides the one that would be
  146. * selected by default.
  147. * @param documentHandler the document handler instance to use
  148. */
  149. public void setDocumentHandlerOverride(IFDocumentHandler documentHandler) {
  150. if (isAccessibilityEnabled()) {
  151. setStructureTreeEventHandler(documentHandler.getStructureTreeEventHandler());
  152. }
  153. this.documentHandlerOverride = documentHandler;
  154. }
  155. /**
  156. * Returns the overriding {@link IFDocumentHandler} instance, if any.
  157. * @return the overriding document handler or null
  158. */
  159. public IFDocumentHandler getDocumentHandlerOverride() {
  160. return this.documentHandlerOverride;
  161. }
  162. /**
  163. * Sets an explicit renderer to use which overrides the one defined by the
  164. * render type setting.
  165. * @param renderer the Renderer instance to use
  166. */
  167. public void setRendererOverride(Renderer renderer) {
  168. this.rendererOverride = renderer;
  169. }
  170. /**
  171. * Returns the overriding Renderer instance, if any.
  172. * @return the overriding Renderer or null
  173. */
  174. public Renderer getRendererOverride() {
  175. return rendererOverride;
  176. }
  177. /**
  178. * Sets an explicit FOEventHandler instance which overrides the one
  179. * defined by the render type setting.
  180. * @param handler the FOEventHandler instance
  181. */
  182. public void setFOEventHandlerOverride(FOEventHandler handler) {
  183. this.foEventHandlerOverride = handler;
  184. }
  185. /**
  186. * Returns the overriding FOEventHandler instance, if any.
  187. * @return the overriding FOEventHandler or null
  188. */
  189. public FOEventHandler getFOEventHandlerOverride() {
  190. return this.foEventHandlerOverride;
  191. }
  192. /**
  193. * Sets the producer of the document.
  194. * @param producer source of document
  195. */
  196. public void setProducer(String producer) {
  197. this.producer = producer;
  198. }
  199. /**
  200. * Returns the producer of the document
  201. * @return producer name
  202. */
  203. public String getProducer() {
  204. return producer;
  205. }
  206. /**
  207. * Sets the creator of the document.
  208. * @param creator of document
  209. */
  210. public void setCreator(String creator) {
  211. this.creator = creator;
  212. }
  213. /**
  214. * Returns the creator of the document
  215. * @return creator name
  216. */
  217. public String getCreator() {
  218. return creator;
  219. }
  220. /**
  221. * Sets the creation date of the document.
  222. * @param creationDate date of document
  223. */
  224. public void setCreationDate(Date creationDate) {
  225. this.creationDate = creationDate;
  226. }
  227. /**
  228. * Returns the creation date of the document
  229. * @return creation date of document
  230. */
  231. public Date getCreationDate() {
  232. return creationDate;
  233. }
  234. /**
  235. * Sets the author of the document.
  236. * @param author of document
  237. */
  238. public void setAuthor(String author) {
  239. this.author = author;
  240. }
  241. /**
  242. * Returns the author of the document
  243. * @return author name
  244. */
  245. public String getAuthor() {
  246. return author;
  247. }
  248. /**
  249. * Sets the title of the document. This will override any title coming from
  250. * an fo:title element.
  251. * @param title of document
  252. */
  253. public void setTitle(String title) {
  254. this.title = title;
  255. }
  256. /**
  257. * Returns the title of the document
  258. * @return title name
  259. */
  260. public String getTitle() {
  261. return title;
  262. }
  263. /**
  264. * Sets the subject of the document.
  265. * @param subject of document
  266. */
  267. public void setSubject(String subject) {
  268. this.subject = subject;
  269. }
  270. /**
  271. * Returns the subject of the document
  272. * @return the subject
  273. */
  274. public String getSubject() {
  275. return subject;
  276. }
  277. /**
  278. * Sets the keywords for the document.
  279. * @param keywords for the document
  280. */
  281. public void setKeywords(String keywords) {
  282. this.keywords = keywords;
  283. }
  284. /**
  285. * Returns the keywords for the document
  286. * @return the keywords
  287. */
  288. public String getKeywords() {
  289. return keywords;
  290. }
  291. /**
  292. * Returns the renderer options
  293. * @return renderer options
  294. */
  295. public Map getRendererOptions() {
  296. return rendererOptions;
  297. }
  298. /**
  299. * Sets the base URL.
  300. * @param baseUrl base URL
  301. */
  302. public void setBaseURL(String baseUrl) {
  303. this.base = baseUrl;
  304. }
  305. /**
  306. * Sets font base URL.
  307. * @param fontBaseUrl font base URL
  308. * @deprecated Use {@link FontManager#setFontBaseURL(String)} instead.
  309. */
  310. public void setFontBaseURL(String fontBaseUrl) {
  311. try {
  312. getFactory().getFontManager().setFontBaseURL(fontBaseUrl);
  313. } catch (MalformedURLException e) {
  314. throw new IllegalArgumentException(e.getMessage());
  315. }
  316. }
  317. /**
  318. * Returns the base URL.
  319. * @return the base URL
  320. */
  321. public String getBaseURL() {
  322. return this.base;
  323. }
  324. /**
  325. * Sets the URI Resolver.
  326. * @param resolver the new URI resolver
  327. */
  328. public void setURIResolver(URIResolver resolver) {
  329. this.uriResolver = resolver;
  330. }
  331. /**
  332. * Returns the URI Resolver.
  333. * @return the URI Resolver
  334. */
  335. public URIResolver getURIResolver() {
  336. return this.uriResolver;
  337. }
  338. /**
  339. * Attempts to resolve the given URI.
  340. * Will use the configured resolver and if not successful fall back
  341. * to the default resolver.
  342. * @param uri URI to access
  343. * @return A {@link javax.xml.transform.Source} object, or null if the URI
  344. * cannot be resolved.
  345. * @see org.apache.fop.apps.FOURIResolver
  346. */
  347. public Source resolveURI(String uri) {
  348. return resolveURI(uri, getBaseURL());
  349. }
  350. /**
  351. * Attempts to resolve the given URI.
  352. * Will use the configured resolver and if not successful fall back
  353. * to the default resolver.
  354. * @param href URI to access
  355. * @param base the base URI to resolve against
  356. * @return A {@link javax.xml.transform.Source} object, or null if the URI
  357. * cannot be resolved.
  358. * @see org.apache.fop.apps.FOURIResolver
  359. */
  360. public Source resolveURI(String href, String base) {
  361. Source source = null;
  362. //RFC 2397 data URLs don't need to be resolved, just decode them through FOP's default
  363. //URIResolver.
  364. boolean bypassURIResolution = href.startsWith("data:");
  365. if (!bypassURIResolution && uriResolver != null) {
  366. try {
  367. source = uriResolver.resolve(href, base);
  368. } catch (TransformerException te) {
  369. log.error("Attempt to resolve URI '" + href + "' failed: ", te);
  370. }
  371. }
  372. if (source == null) {
  373. // URI Resolver not configured or returned null, use default resolver from the factory
  374. source = getFactory().resolveURI(href, base);
  375. }
  376. return source;
  377. }
  378. /**
  379. * Sets the output File.
  380. * @param f the output File
  381. */
  382. public void setOutputFile(File f) {
  383. this.outputFile = f;
  384. }
  385. /**
  386. * Gets the output File.
  387. * @return the output File
  388. */
  389. public File getOutputFile() {
  390. return outputFile;
  391. }
  392. /**
  393. * Returns the conversion factor from pixel units to millimeters. This
  394. * depends on the desired target resolution.
  395. * @return float conversion factor
  396. * @see #getTargetResolution()
  397. */
  398. public float getTargetPixelUnitToMillimeter() {
  399. return UnitConv.IN2MM / this.targetResolution;
  400. }
  401. /** @return the resolution for resolution-dependant output */
  402. public float getTargetResolution() {
  403. return this.targetResolution;
  404. }
  405. /**
  406. * Sets the target resolution in dpi. This value defines the target resolution of
  407. * bitmap images generated by the bitmap renderers (such as the TIFF renderer) and of
  408. * bitmap images generated by filter effects in Apache Batik.
  409. * @param dpi resolution in dpi
  410. */
  411. public void setTargetResolution(float dpi) {
  412. this.targetResolution = dpi;
  413. if (log.isDebugEnabled()) {
  414. log.debug("target-resolution set to: " + targetResolution
  415. + "dpi (px2mm=" + getTargetPixelUnitToMillimeter() + ")");
  416. }
  417. }
  418. /**
  419. * Sets the target resolution in dpi. This value defines the target resolution of
  420. * bitmap images generated by the bitmap renderers (such as the TIFF renderer) and of
  421. * bitmap images generated by filter effects in Apache Batik.
  422. * @param dpi resolution in dpi
  423. */
  424. public void setTargetResolution(int dpi) {
  425. setTargetResolution((float)dpi);
  426. }
  427. /**
  428. * Returns the image session context for the image package.
  429. * @return the ImageSessionContext instance for this rendering run
  430. */
  431. public ImageSessionContext getImageSessionContext() {
  432. return this.imageSessionContext;
  433. }
  434. // ---------------------------------------------- environment-level stuff
  435. // (convenience access to FopFactory methods)
  436. /**
  437. * Returns the font base URL.
  438. * @return the font base URL
  439. * @deprecated Use {@link FontManager#getFontBaseURL()} instead. This method is not used by FOP.
  440. */
  441. public String getFontBaseURL() {
  442. String fontBase = getFactory().getFontManager().getFontBaseURL();
  443. return fontBase != null ? fontBase : getBaseURL();
  444. }
  445. /**
  446. * Returns the conversion factor from pixel units to millimeters. This
  447. * depends on the desired source resolution.
  448. * @return float conversion factor
  449. * @see #getSourceResolution()
  450. */
  451. public float getSourcePixelUnitToMillimeter() {
  452. return getFactory().getSourcePixelUnitToMillimeter();
  453. }
  454. /** @return the resolution for resolution-dependant input */
  455. public float getSourceResolution() {
  456. return getFactory().getSourceResolution();
  457. }
  458. /**
  459. * Gets the default page-height to use as fallback,
  460. * in case page-height="auto"
  461. *
  462. * @return the page-height, as a String
  463. * @see FopFactory#getPageHeight()
  464. */
  465. public String getPageHeight() {
  466. return getFactory().getPageHeight();
  467. }
  468. /**
  469. * Gets the default page-width to use as fallback,
  470. * in case page-width="auto"
  471. *
  472. * @return the page-width, as a String
  473. * @see FopFactory#getPageWidth()
  474. */
  475. public String getPageWidth() {
  476. return getFactory().getPageWidth();
  477. }
  478. /**
  479. * Returns whether FOP is strictly validating input XSL
  480. * @return true of strict validation turned on, false otherwise
  481. * @see FopFactory#validateStrictly()
  482. */
  483. public boolean validateStrictly() {
  484. return getFactory().validateStrictly();
  485. }
  486. /**
  487. * @return true if the indent inheritance should be broken when crossing reference area
  488. * boundaries (for more info, see the javadoc for the relative member variable)
  489. * @see FopFactory#isBreakIndentInheritanceOnReferenceAreaBoundary()
  490. */
  491. public boolean isBreakIndentInheritanceOnReferenceAreaBoundary() {
  492. return getFactory().isBreakIndentInheritanceOnReferenceAreaBoundary();
  493. }
  494. /**
  495. * @return the RendererFactory
  496. */
  497. public RendererFactory getRendererFactory() {
  498. return getFactory().getRendererFactory();
  499. }
  500. /**
  501. * @return the XML handler registry
  502. */
  503. public XMLHandlerRegistry getXMLHandlerRegistry() {
  504. return getFactory().getXMLHandlerRegistry();
  505. }
  506. /**
  507. * Controls the use of SAXLocators to provide location information in error
  508. * messages.
  509. *
  510. * @param enableLocator <code>false</code> if SAX Locators should be disabled
  511. */
  512. public void setLocatorEnabled(boolean enableLocator) {
  513. locatorEnabled = enableLocator;
  514. }
  515. /**
  516. * Checks if the use of Locators is enabled
  517. * @return true if context information should be stored on each node in the FO tree.
  518. */
  519. public boolean isLocatorEnabled() {
  520. return locatorEnabled;
  521. }
  522. /**
  523. * Returns the event broadcaster that control events sent inside a processing run. Clients
  524. * can register event listeners with the event broadcaster to listen for events that occur
  525. * while a document is being processed.
  526. * @return the event broadcaster.
  527. */
  528. public EventBroadcaster getEventBroadcaster() {
  529. return this.eventBroadcaster;
  530. }
  531. private class FOPEventBroadcaster extends DefaultEventBroadcaster {
  532. private EventListener rootListener;
  533. public FOPEventBroadcaster() {
  534. //Install a temporary event listener that catches the first event to
  535. //do some initialization.
  536. this.rootListener = new EventListener() {
  537. public void processEvent(Event event) {
  538. if (!listeners.hasEventListeners()) {
  539. //Backwards-compatibility: Make sure at least the LoggingEventListener is
  540. //plugged in so no events are just silently swallowed.
  541. addEventListener(
  542. new LoggingEventListener(LogFactory.getLog(FOUserAgent.class)));
  543. }
  544. //Replace with final event listener
  545. rootListener = new FOPEventListenerProxy(
  546. listeners, FOUserAgent.this);
  547. rootListener.processEvent(event);
  548. }
  549. };
  550. }
  551. /** {@inheritDoc} */
  552. public void broadcastEvent(Event event) {
  553. rootListener.processEvent(event);
  554. }
  555. }
  556. /**
  557. * Check whether memory-conservation is enabled.
  558. *
  559. * @return true if FOP is to conserve as much as possible
  560. */
  561. public boolean isConserveMemoryPolicyEnabled() {
  562. return this.conserveMemoryPolicy;
  563. }
  564. /**
  565. * Control whether memory-conservation should be enabled
  566. *
  567. * @param conserveMemoryPolicy the cachingEnabled to set
  568. */
  569. public void setConserveMemoryPolicy(boolean conserveMemoryPolicy) {
  570. this.conserveMemoryPolicy = conserveMemoryPolicy;
  571. }
  572. /**
  573. * Activates accessibility (for output formats that support it).
  574. *
  575. * @param accessibility <code>true</code> to enable accessibility support
  576. */
  577. public void setAccessibility(boolean accessibility) {
  578. if (accessibility) {
  579. getRendererOptions().put(Accessibility.ACCESSIBILITY, Boolean.TRUE);
  580. }
  581. }
  582. /**
  583. * Check if accessibility is enabled.
  584. * @return true if accessibility is enabled
  585. */
  586. public boolean isAccessibilityEnabled() {
  587. Boolean enabled = (Boolean)this.getRendererOptions().get(Accessibility.ACCESSIBILITY);
  588. if (enabled != null) {
  589. return enabled.booleanValue();
  590. } else {
  591. return false;
  592. }
  593. }
  594. /**
  595. * Sets the document's structure tree event handler, for use by accessible
  596. * output formats.
  597. *
  598. * @param structureTreeEventHandler The structure tree event handler to set
  599. */
  600. public void setStructureTreeEventHandler(StructureTreeEventHandler structureTreeEventHandler) {
  601. this.structureTreeEventHandler = structureTreeEventHandler;
  602. }
  603. /**
  604. * Returns the document's structure tree event handler, for use by
  605. * accessible output formats.
  606. *
  607. * @return The structure tree event handler
  608. */
  609. public StructureTreeEventHandler getStructureTreeEventHandler() {
  610. return this.structureTreeEventHandler;
  611. }
  612. }