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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. /*
  2. * Copyright 1999-2005 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.apps;
  18. // Java
  19. import java.io.File;
  20. import java.io.IOException;
  21. import java.net.URL;
  22. import java.net.MalformedURLException;
  23. import java.util.Date;
  24. import java.util.List;
  25. import java.util.Map;
  26. import javax.xml.transform.Source;
  27. import javax.xml.transform.TransformerException;
  28. import javax.xml.transform.URIResolver;
  29. // avalon configuration
  30. import org.apache.avalon.framework.configuration.Configuration;
  31. import org.apache.avalon.framework.configuration.ConfigurationException;
  32. // commons logging
  33. import org.apache.commons.logging.Log;
  34. import org.apache.commons.logging.LogFactory;
  35. // FOP
  36. import org.apache.fop.Version;
  37. import org.apache.fop.fo.ElementMapping;
  38. import org.apache.fop.fo.FOEventHandler;
  39. import org.apache.fop.layoutmgr.LayoutManagerMaker;
  40. import org.apache.fop.pdf.PDFEncryptionParams;
  41. import org.apache.fop.render.Renderer;
  42. import org.apache.fop.render.RendererFactory;
  43. import org.apache.fop.render.XMLHandlerRegistry;
  44. /**
  45. * The User Agent for fo.
  46. * This user agent is used by the processing to obtain user configurable
  47. * options.
  48. * <p>
  49. * Renderer specific extensions (that do not produce normal areas on
  50. * the output) will be done like so:
  51. * <br>
  52. * The extension will create an area, custom if necessary
  53. * <br>
  54. * this area will be added to the user agent with a key
  55. * <br>
  56. * the renderer will know keys for particular extensions
  57. * <br>
  58. * eg. bookmarks will be held in a special hierarchical area representing
  59. * the title and bookmark structure
  60. * <br>
  61. * These areas may contain resolvable areas that will be processed
  62. * with other resolvable areas
  63. */
  64. public class FOUserAgent {
  65. /** Defines the default source resolution (72dpi) for FOP */
  66. public static final float DEFAULT_SOURCE_RESOLUTION = 72.0f; //dpi
  67. /** Defines the default target resolution (72dpi) for FOP */
  68. public static final float DEFAULT_TARGET_RESOLUTION = 72.0f; //dpi
  69. /** Defines the default page-height */
  70. public static final String DEFAULT_PAGE_HEIGHT = "11in";
  71. /** Defines the default page-width */
  72. public static final String DEFAULT_PAGE_WIDTH = "8.26in";
  73. /** Factory for Renderers and FOEventHandlers */
  74. private RendererFactory rendererFactory = new RendererFactory();
  75. /** Registry for XML handlers */
  76. private XMLHandlerRegistry xmlHandlers = new XMLHandlerRegistry();
  77. private String baseURL;
  78. /** A user settable URI Resolver */
  79. private URIResolver uriResolver = null;
  80. /** Our default resolver if none is set */
  81. private URIResolver foURIResolver = new FOURIResolver();
  82. private PDFEncryptionParams pdfEncryptionParams;
  83. private float sourceResolution = DEFAULT_SOURCE_RESOLUTION;
  84. private float targetResolution = DEFAULT_TARGET_RESOLUTION;
  85. private String pageHeight = DEFAULT_PAGE_HEIGHT;
  86. private String pageWidth = DEFAULT_PAGE_WIDTH;
  87. private Map rendererOptions = new java.util.HashMap();
  88. private File outputFile = null;
  89. private Renderer rendererOverride = null;
  90. private FOEventHandler foEventHandlerOverride = null;
  91. private LayoutManagerMaker lmMakerOverride = null;
  92. /* user configuration */
  93. private Configuration userConfig = null;
  94. private Log log = LogFactory.getLog("FOP");
  95. /* FOP has the ability, for some FO's, to continue processing even if the
  96. * input XSL violates that FO's content model. This is the default
  97. * behavior for FOP. However, this flag, if set, provides the user the
  98. * ability for FOP to halt on all content model violations if desired.
  99. */
  100. private boolean strictValidation = true;
  101. /** @see #setBreakIndentInheritanceOnReferenceAreaBoundary(boolean) */
  102. private boolean breakIndentInheritanceOnReferenceAreaBoundary = false;
  103. /* Additional fo.ElementMapping subclasses set by user */
  104. private List additionalElementMappings = null;
  105. /** Producer: Metadata element for the system/software that produces
  106. * the document. (Some renderers can store this in the document.)
  107. */
  108. protected String producer = "Apache FOP Version " + Version.getVersion();
  109. /** Creator: Metadata element for the user that created the
  110. * document. (Some renderers can store this in the document.)
  111. */
  112. protected String creator = null;
  113. /** Creation Date: Override of the date the document was created.
  114. * (Some renderers can store this in the document.)
  115. */
  116. protected Date creationDate = null;
  117. /** Author of the content of the document. */
  118. protected String author = null;
  119. /** Title of the document. */
  120. protected String title = null;
  121. /** Set of keywords applicable to this document. */
  122. protected String keywords = null;
  123. /**
  124. * Add the element mapping with the given class name.
  125. * @param elementMapping the class name representing the element mapping.
  126. */
  127. public void addElementMapping(ElementMapping elementMapping) {
  128. if (additionalElementMappings == null) {
  129. additionalElementMappings = new java.util.ArrayList();
  130. }
  131. additionalElementMappings.add(elementMapping);
  132. }
  133. /**
  134. * Returns the List of user-added ElementMapping class names
  135. * @return List of Strings holding ElementMapping names.
  136. */
  137. public List getAdditionalElementMappings() {
  138. return additionalElementMappings;
  139. }
  140. /**
  141. * Sets an explicit renderer to use which overrides the one defined by the
  142. * render type setting.
  143. * @param renderer the Renderer instance to use
  144. */
  145. public void setRendererOverride(Renderer renderer) {
  146. this.rendererOverride = renderer;
  147. }
  148. /**
  149. * Returns the overriding Renderer instance, if any.
  150. * @return the overriding Renderer or null
  151. */
  152. public Renderer getRendererOverride() {
  153. return rendererOverride;
  154. }
  155. /**
  156. * Sets an explicit FOEventHandler instance which overrides the one
  157. * defined by the render type setting.
  158. * @param handler the FOEventHandler instance
  159. */
  160. public void setFOEventHandlerOverride(FOEventHandler handler) {
  161. this.foEventHandlerOverride = handler;
  162. }
  163. /**
  164. * Returns the overriding FOEventHandler instance, if any.
  165. * @return the overriding FOEventHandler or null
  166. */
  167. public FOEventHandler getFOEventHandlerOverride() {
  168. return this.foEventHandlerOverride;
  169. }
  170. /**
  171. * Activates strict XSL content model validation for FOP
  172. * Default is false (FOP will continue processing where it can)
  173. * @param validateStrictly true to turn on strict validation
  174. */
  175. public void setStrictValidation(boolean validateStrictly) {
  176. this.strictValidation = validateStrictly;
  177. }
  178. /**
  179. * Returns whether FOP is strictly validating input XSL
  180. * @return true of strict validation turned on, false otherwise
  181. */
  182. public boolean validateStrictly() {
  183. return strictValidation;
  184. }
  185. /**
  186. * @return true if the indent inheritance should be broken when crossing reference area
  187. * boundaries (for more info, see the javadoc for the relative member variable)
  188. */
  189. public boolean isBreakIndentInheritanceOnReferenceAreaBoundary() {
  190. return breakIndentInheritanceOnReferenceAreaBoundary;
  191. }
  192. /**
  193. * Controls whether to enable a feature that breaks indent inheritance when crossing
  194. * reference area boundaries.
  195. * <p>
  196. * This flag controls whether FOP will enable special code that breaks property
  197. * inheritance for start-indent and end-indent when the evaluation of the inherited
  198. * value would cross a reference area. This is described under
  199. * http://wiki.apache.org/xmlgraphics-fop/IndentInheritance as is intended to
  200. * improve interoperability with commercial FO implementations and to produce
  201. * results that are more in line with the expectation of unexperienced FO users.
  202. * Note: Enabling this features violates the XSL specification!
  203. * @param value true to enable the feature
  204. */
  205. public void setBreakIndentInheritanceOnReferenceAreaBoundary(boolean value) {
  206. this.breakIndentInheritanceOnReferenceAreaBoundary = value;
  207. }
  208. /**
  209. * Sets an explicit LayoutManagerMaker instance which overrides the one
  210. * defined by the AreaTreeHandler.
  211. * @param lmMaker the LayoutManagerMaker instance
  212. */
  213. public void setLayoutManagerMakerOverride(LayoutManagerMaker lmMaker) {
  214. this.lmMakerOverride = lmMaker;
  215. }
  216. /**
  217. * Returns the overriding LayoutManagerMaker instance, if any.
  218. * @return the overriding LayoutManagerMaker or null
  219. */
  220. public LayoutManagerMaker getLayoutManagerMakerOverride() {
  221. return this.lmMakerOverride;
  222. }
  223. /**
  224. * Sets the producer of the document.
  225. * @param producer source of document
  226. */
  227. public void setProducer(String producer) {
  228. this.producer = producer;
  229. }
  230. /**
  231. * Returns the producer of the document
  232. * @return producer name
  233. */
  234. public String getProducer() {
  235. return producer;
  236. }
  237. /**
  238. * Sets the creator of the document.
  239. * @param creator of document
  240. */
  241. public void setCreator(String creator) {
  242. this.creator = creator;
  243. }
  244. /**
  245. * Returns the creator of the document
  246. * @return creator name
  247. */
  248. public String getCreator() {
  249. return creator;
  250. }
  251. /**
  252. * Sets the creation date of the document.
  253. * @param creationDate date of document
  254. */
  255. public void setCreationDate(Date creationDate) {
  256. this.creationDate = creationDate;
  257. }
  258. /**
  259. * Returns the creation date of the document
  260. * @return creation date of document
  261. */
  262. public Date getCreationDate() {
  263. return creationDate;
  264. }
  265. /**
  266. * Sets the author of the document.
  267. * @param author of document
  268. */
  269. public void setAuthor(String author) {
  270. this.author = author;
  271. }
  272. /**
  273. * Returns the author of the document
  274. * @return author name
  275. */
  276. public String getAuthor() {
  277. return author;
  278. }
  279. /**
  280. * Sets the title of the document. This will override any title coming from
  281. * an fo:title element.
  282. * @param title of document
  283. */
  284. public void setTitle(String title) {
  285. this.title = title;
  286. }
  287. /**
  288. * Returns the title of the document
  289. * @return title name
  290. */
  291. public String getTitle() {
  292. return title;
  293. }
  294. /**
  295. * Sets the keywords for the document.
  296. * @param keywords for the document
  297. */
  298. public void setKeywords(String keywords) {
  299. this.keywords = keywords;
  300. }
  301. /**
  302. * Returns the keywords for the document
  303. * @return the keywords
  304. */
  305. public String getKeywords() {
  306. return keywords;
  307. }
  308. /**
  309. * Returns the renderer options
  310. * @return renderer options
  311. */
  312. public Map getRendererOptions() {
  313. return rendererOptions;
  314. }
  315. /**
  316. * Set the user configuration.
  317. * @param userConfig configuration
  318. */
  319. public void setUserConfig(Configuration userConfig) {
  320. this.userConfig = userConfig;
  321. try {
  322. initUserConfig();
  323. } catch (ConfigurationException cfge) {
  324. log.error("Error initializing User Agent configuration: "
  325. + cfge.getMessage());
  326. }
  327. }
  328. /**
  329. * Get the user configuration.
  330. * @return the user configuration
  331. */
  332. public Configuration getUserConfig() {
  333. return userConfig;
  334. }
  335. /**
  336. * Initializes user agent settings from the user configuration
  337. * file, if present: baseURL, resolution, default page size,...
  338. *
  339. * @throws ConfigurationException when there is an entry that
  340. * misses the required attribute
  341. */
  342. public void initUserConfig() throws ConfigurationException {
  343. log.debug("Initializing User Agent Configuration");
  344. if (userConfig.getChild("base", false) != null) {
  345. try {
  346. String cfgBaseDir = userConfig.getChild("base").getValue(null);
  347. if (cfgBaseDir != null) {
  348. File dir = new File(cfgBaseDir);
  349. if (dir.isDirectory()) {
  350. cfgBaseDir = "file://" + dir.getCanonicalPath()
  351. + System.getProperty("file.separator");
  352. cfgBaseDir = cfgBaseDir.replace(
  353. System.getProperty("file.separator").charAt(0), '/');
  354. } else {
  355. //The next statement is for validation only
  356. new URL(cfgBaseDir);
  357. }
  358. }
  359. setBaseURL(cfgBaseDir);
  360. } catch (MalformedURLException mue) {
  361. log.error("Base URL in user config is malformed!");
  362. } catch (IOException ioe) {
  363. log.error("Error converting relative base directory to absolute URL.");
  364. }
  365. log.info("Base URL set to: " + baseURL);
  366. }
  367. if (userConfig.getChild("source-resolution", false) != null) {
  368. this.sourceResolution
  369. = userConfig.getChild("source-resolution").getValueAsFloat(
  370. DEFAULT_SOURCE_RESOLUTION);
  371. log.info("Source resolution set to: " + sourceResolution
  372. + "dpi (px2mm=" + getSourcePixelUnitToMillimeter() + ")");
  373. }
  374. if (userConfig.getChild("target-resolution", false) != null) {
  375. this.targetResolution
  376. = userConfig.getChild("target-resolution").getValueAsFloat(
  377. DEFAULT_TARGET_RESOLUTION);
  378. log.info("Target resolution set to: " + targetResolution
  379. + "dpi (px2mm=" + getTargetPixelUnitToMillimeter() + ")");
  380. }
  381. if (userConfig.getChild("strict-validation", false) != null) {
  382. this.strictValidation = userConfig.getChild("strict-validation").getValueAsBoolean();
  383. }
  384. if (userConfig.getChild("break-indent-inheritance", false) != null) {
  385. this.breakIndentInheritanceOnReferenceAreaBoundary
  386. = userConfig.getChild("break-indent-inheritance").getValueAsBoolean();
  387. }
  388. Configuration pageConfig = userConfig.getChild("default-page-settings");
  389. if (pageConfig.getAttribute("height", null) != null) {
  390. setPageHeight(pageConfig.getAttribute("height"));
  391. log.info("Default page-height set to: " + pageHeight);
  392. }
  393. if (pageConfig.getAttribute("width", null) != null) {
  394. setPageWidth(pageConfig.getAttribute("width"));
  395. log.info("Default page-width set to: " + pageWidth);
  396. }
  397. }
  398. /**
  399. * Returns the configuration subtree for a specific renderer.
  400. * @param mimeType MIME type of the renderer
  401. * @return the requested configuration subtree, null if there's no configuration
  402. */
  403. public Configuration getUserRendererConfig (String mimeType) {
  404. if (userConfig == null || mimeType == null) {
  405. return null;
  406. }
  407. Configuration userRendererConfig = null;
  408. Configuration[] cfgs
  409. = userConfig.getChild("renderers").getChildren("renderer");
  410. for (int i = 0; i < cfgs.length; ++i) {
  411. Configuration cfg = cfgs[i];
  412. try {
  413. if (cfg.getAttribute("mime").equals(mimeType)) {
  414. userRendererConfig = cfg;
  415. break;
  416. }
  417. } catch (ConfigurationException e) {
  418. // silently pass over configurations without mime type
  419. }
  420. }
  421. log.debug((userRendererConfig == null ? "No u" : "U")
  422. + "ser configuration found for MIME type " + mimeType);
  423. return userRendererConfig;
  424. }
  425. /**
  426. * Sets the base URL.
  427. * @param baseURL base URL
  428. */
  429. public void setBaseURL(String baseURL) {
  430. this.baseURL = baseURL;
  431. }
  432. /**
  433. * Returns the base URL.
  434. * @return the base URL
  435. */
  436. public String getBaseURL() {
  437. return this.baseURL;
  438. }
  439. /**
  440. * Sets the URI Resolver.
  441. * @param uriResolver the new URI resolver
  442. */
  443. public void setURIResolver(URIResolver uriResolver) {
  444. this.uriResolver = uriResolver;
  445. }
  446. /**
  447. * Returns the URI Resolver.
  448. * @return the URI Resolver
  449. */
  450. public URIResolver getURIResolver() {
  451. return this.uriResolver;
  452. }
  453. /**
  454. * Returns the parameters for PDF encryption.
  455. * @return the PDF encryption parameters, null if not applicable
  456. */
  457. public PDFEncryptionParams getPDFEncryptionParams() {
  458. return pdfEncryptionParams;
  459. }
  460. /**
  461. * Sets the parameters for PDF encryption.
  462. * @param pdfEncryptionParams the PDF encryption parameters, null to
  463. * disable PDF encryption
  464. */
  465. public void setPDFEncryptionParams(PDFEncryptionParams pdfEncryptionParams) {
  466. this.pdfEncryptionParams = pdfEncryptionParams;
  467. }
  468. /**
  469. * Attempts to resolve the given URI.
  470. * Will use the configured resolver and if not successful fall back
  471. * to the default resolver.
  472. * @param uri URI to access
  473. * @return A {@link javax.xml.transform.Source} object, or null if the URI
  474. * cannot be resolved.
  475. * @see org.apache.fop.apps.FOURIResolver
  476. */
  477. public Source resolveURI(String uri) {
  478. Source source = null;
  479. if (uriResolver != null) {
  480. try {
  481. source = uriResolver.resolve(uri, getBaseURL());
  482. } catch (TransformerException te) {
  483. log.error("Attempt to resolve URI '" + uri + "' failed: ", te);
  484. }
  485. }
  486. if (source == null) {
  487. // URI Resolver not configured or returned null, use default resolver
  488. try {
  489. source = foURIResolver.resolve(uri, getBaseURL());
  490. } catch (TransformerException te) {
  491. log.error("Attempt to resolve URI '" + uri + "' failed: ", te);
  492. }
  493. }
  494. return source;
  495. }
  496. /**
  497. * Sets the output File.
  498. * @param f the output File
  499. */
  500. public void setOutputFile(File f) {
  501. this.outputFile = f;
  502. }
  503. /**
  504. * Gets the output File.
  505. * @return the output File
  506. */
  507. public File getOutputFile() {
  508. return outputFile;
  509. }
  510. /**
  511. * Returns the conversion factor from pixel units to millimeters. This
  512. * depends on the desired source resolution.
  513. * @return float conversion factor
  514. * @see getSourceResolution()
  515. */
  516. public float getSourcePixelUnitToMillimeter() {
  517. return 25.4f / this.sourceResolution;
  518. }
  519. /**
  520. * Returns the conversion factor from pixel units to millimeters. This
  521. * depends on the desired target resolution.
  522. * @return float conversion factor
  523. * @see getTargetResolution()
  524. */
  525. public float getTargetPixelUnitToMillimeter() {
  526. return 25.4f / this.targetResolution;
  527. }
  528. /** @return the resolution for resolution-dependant input */
  529. public float getSourceResolution() {
  530. return this.sourceResolution;
  531. }
  532. /** @return the resolution for resolution-dependant output */
  533. public float getTargetResolution() {
  534. return this.targetResolution;
  535. }
  536. /**
  537. * Sets the source resolution in dpi. This value is used to interpret the pixel size
  538. * of source documents like SVG images and bitmap images without resolution information.
  539. * @param dpi resolution in dpi
  540. */
  541. public void setSourceResolution(int dpi) {
  542. this.sourceResolution = dpi;
  543. }
  544. /**
  545. * Sets the target resolution in dpi. This value defines the target resolution of
  546. * bitmap images generated by the bitmap renderers (such as the TIFF renderer) and of
  547. * bitmap images generated by filter effects in Apache Batik.
  548. * @param dpi resolution in dpi
  549. */
  550. public void setTargetResolution(int dpi) {
  551. this.targetResolution = dpi;
  552. }
  553. /**
  554. * Gets the default page-height to use as fallback,
  555. * in case page-height="auto"
  556. *
  557. * @return the page-height, as a String
  558. */
  559. public String getPageHeight() {
  560. return this.pageHeight;
  561. }
  562. /**
  563. * Sets the page-height to use as fallback, in case
  564. * page-height="auto"
  565. *
  566. * @param pageHeight page-height as a String
  567. */
  568. public void setPageHeight(String pageHeight) {
  569. this.pageHeight = pageHeight;
  570. }
  571. /**
  572. * Gets the default page-width to use as fallback,
  573. * in case page-width="auto"
  574. *
  575. * @return the page-width, as a String
  576. */
  577. public String getPageWidth() {
  578. return this.pageWidth;
  579. }
  580. /**
  581. * Sets the page-width to use as fallback, in case
  582. * page-width="auto"
  583. *
  584. * @param pageWidth page-width as a String
  585. */
  586. public void setPageWidth(String pageWidth) {
  587. this.pageWidth = pageWidth;
  588. }
  589. /**
  590. * If to create hot links to footnotes and before floats.
  591. * @return True if hot links should be created
  592. */
  593. /* TODO This method is never referenced!
  594. public boolean linkToFootnotes() {
  595. return true;
  596. }*/
  597. /**
  598. * @return the RendererFactory
  599. */
  600. public RendererFactory getRendererFactory() {
  601. return this.rendererFactory;
  602. }
  603. /**
  604. * @return the XML handler registry
  605. */
  606. public XMLHandlerRegistry getXMLHandlerRegistry() {
  607. return this.xmlHandlers;
  608. }
  609. }