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.

FopConfBuilder.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  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. import java.io.ByteArrayInputStream;
  20. import java.io.ByteArrayOutputStream;
  21. import java.io.InputStream;
  22. import java.io.OutputStream;
  23. import java.io.OutputStreamWriter;
  24. import java.io.UnsupportedEncodingException;
  25. import javax.xml.parsers.DocumentBuilder;
  26. import javax.xml.parsers.DocumentBuilderFactory;
  27. import javax.xml.parsers.ParserConfigurationException;
  28. import javax.xml.transform.OutputKeys;
  29. import javax.xml.transform.Result;
  30. import javax.xml.transform.Source;
  31. import javax.xml.transform.Transformer;
  32. import javax.xml.transform.TransformerConfigurationException;
  33. import javax.xml.transform.TransformerException;
  34. import javax.xml.transform.TransformerFactory;
  35. import javax.xml.transform.dom.DOMSource;
  36. import javax.xml.transform.stream.StreamResult;
  37. import org.w3c.dom.Document;
  38. import org.w3c.dom.Element;
  39. import org.apache.fop.render.RendererConfigOption;
  40. /**
  41. * A builder class for creating fop.xconf XML DOMs for test purposes. You can set all the necessary
  42. * fields inline and build the fop conf DOM into an {@link InputStream}.
  43. * <pre>
  44. * {@code
  45. * new FopConfBuilder().setStrictValidation(true)
  46. * .startRendererBuilder(RendererConfBuilder.class)
  47. * .startFontsConfig()
  48. * .startFont(null, null)
  49. * .addTriplet("Gladiator", "normal", "normal")
  50. * .endFont()
  51. * .endFontConfig()
  52. * .endRendererConfigBuilder().build()
  53. * }
  54. * </pre>
  55. */
  56. public class FopConfBuilder implements FontConfigurator<FopConfBuilder> {
  57. private final Element root;
  58. private final Document fopConfDOM;
  59. private RendererConfBuilder currentRendererConfig;
  60. private FontsConfBuilder<FopConfBuilder> currentFontsConfig;
  61. /**
  62. * Constructs the FopConfBuilder and initializes the underlying DOM.
  63. */
  64. public FopConfBuilder() {
  65. try {
  66. DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  67. dbf.setNamespaceAware(true);
  68. DocumentBuilder db = dbf.newDocumentBuilder();
  69. fopConfDOM = db.newDocument();
  70. root = fopConfDOM.createElement("fop");
  71. fopConfDOM.appendChild(root);
  72. } catch (ParserConfigurationException e) {
  73. throw new RuntimeException(e);
  74. }
  75. }
  76. private FopConfBuilder createElement(String elementName, String elementValue) {
  77. Element el = fopConfDOM.createElement(elementName);
  78. el.appendChild(fopConfDOM.createTextNode(elementValue));
  79. root.appendChild(el);
  80. return this;
  81. }
  82. /**
  83. * Set the &lt;font-base&gt; tag within the fop.xconf.
  84. *
  85. * @param fontBase the font base value
  86. * @return <b>this</b>
  87. */
  88. public FopConfBuilder setFontBaseURI(String fontBase) {
  89. return createElement("font-base", fontBase);
  90. }
  91. /**
  92. * Set the &lt;base&gt; tag within the fop.xconf.
  93. *
  94. * @param baseURI the base URI
  95. * @return <b>this</b>
  96. */
  97. public FopConfBuilder setBaseURI(String baseURI) {
  98. return createElement("base", baseURI);
  99. }
  100. /**
  101. * Set the &lt;strict-validation&gt; tag within the fop.xconf.
  102. *
  103. * @param validateStrictly true to enforce strict FO validation
  104. * @return <b>this</b>
  105. */
  106. public FopConfBuilder setStrictConfiguration(boolean validateStrictly) {
  107. return createElement("strict-configuration", String.valueOf(validateStrictly));
  108. }
  109. /**
  110. * Set the &lt;strict-validation&gt; tag within the fop.xconf.
  111. *
  112. * @param validateStrictly true to enforce strict configuration validation
  113. * @return <b>this</b>
  114. */
  115. public FopConfBuilder setStrictValidation(boolean validateStrictly) {
  116. return createElement("strict-validation", String.valueOf(validateStrictly));
  117. }
  118. /**
  119. * Set the &lt;accessibility&gt; tag within the fop.xconf.
  120. *
  121. * @param setAccessibility true to enable accessibility features
  122. * @return <b>this</b>
  123. */
  124. public FopConfBuilder setAccessibility(boolean setAccessibility) {
  125. return createElement("accessibility", String.valueOf(setAccessibility));
  126. }
  127. @Deprecated
  128. public FopConfBuilder setHyphenationBaseURI(String uri) {
  129. return createElement("hyphenation-base", uri);
  130. }
  131. /**
  132. * Set the &lt;source-resolution&gt; tag within the fop.xconf.
  133. *
  134. * @param srcRes the source resolution
  135. * @return <b>this</b>
  136. */
  137. public FopConfBuilder setSourceResolution(float srcRes) {
  138. return createElement("source-resolution", String.valueOf(srcRes));
  139. }
  140. /**
  141. * Set the &lt;target-resolution&gt; tag within the fop.xconf.
  142. *
  143. * @param targetRes the target resolution
  144. * @return <b>this</b>
  145. */
  146. public FopConfBuilder setTargetResolution(float targetRes) {
  147. return createElement("target-resolution", String.valueOf(targetRes));
  148. }
  149. /**
  150. * Set the &lt;break-indent-inheritance&gt; tag within the fop.xconf.
  151. *
  152. * @param value true to break indent inheritance
  153. * @return <b>this</b>
  154. */
  155. public FopConfBuilder setBreakIndentInheritance(boolean value) {
  156. return createElement("break-indent-inheritance", String.valueOf(value));
  157. }
  158. /**
  159. * Set the &lt;prefer-renderer&gt; tag within the fop.xconf.
  160. *
  161. * @param value true to prefer the renderer
  162. * @return <b>this</b>
  163. */
  164. public FopConfBuilder setPreferRenderer(boolean value) {
  165. return createElement("prefer-renderer", String.valueOf(value));
  166. }
  167. /**
  168. * Set the &lt;default-page-settings&gt; tag within the fop.xconf.
  169. *
  170. * @param height the height of the page
  171. * @param width the width of the page
  172. * @return <b>this</b>
  173. */
  174. public FopConfBuilder setDefaultPageSettings(float height, float width) {
  175. Element el = fopConfDOM.createElement("default-page-settings");
  176. el.setAttribute("height", String.valueOf(height));
  177. el.setAttribute("width", String.valueOf(width));
  178. root.appendChild(el);
  179. return this;
  180. }
  181. /**
  182. * Sets whether the fonts cache is used or not.
  183. *
  184. * @param enableFontCaching true to enable font data caching.
  185. * @return <b>this</b>
  186. */
  187. public FopConfBuilder useCache(boolean enableFontCaching) {
  188. return createElement("use-cache", String.valueOf(enableFontCaching));
  189. }
  190. /**
  191. * Starts a renderer specific config builder.
  192. *
  193. * @param mimeType the MIME type of the builder
  194. * @return the renderer config builder
  195. */
  196. public <T extends RendererConfBuilder> T startRendererConfig(Class<T> rendererConfigClass) {
  197. try {
  198. currentRendererConfig = rendererConfigClass.newInstance();
  199. } catch (InstantiationException e) {
  200. throw new RuntimeException(e);
  201. } catch (IllegalAccessException e) {
  202. throw new RuntimeException(e);
  203. }
  204. currentRendererConfig.init(this, fopConfDOM);
  205. return rendererConfigClass.cast(currentRendererConfig);
  206. }
  207. /**
  208. * Ends a renderer specific config builder.
  209. *
  210. * @return <b>this</b>
  211. */
  212. private FopConfBuilder endRendererConfig() {
  213. Element renderersEl = fopConfDOM.createElement("renderers");
  214. renderersEl.appendChild(currentRendererConfig.rendererEl);
  215. root.appendChild(renderersEl);
  216. currentRendererConfig = null;
  217. return this;
  218. }
  219. /**
  220. * Starts a fonts config builder, for configuring the fonts handling system within FOP i.e.
  221. * the &lt;fonts&gt; element.
  222. *
  223. * @return the fop config builder
  224. */
  225. public FontsConfBuilder<FopConfBuilder> startFontsConfig() {
  226. currentFontsConfig = new FontsConfBuilder<FopConfBuilder>(this);
  227. currentFontsConfig.setFopConfDOM(fopConfDOM);
  228. return currentFontsConfig;
  229. }
  230. /**
  231. * Ends the fonts config builder.
  232. *
  233. * @return <b>this</b>
  234. */
  235. public FopConfBuilder endFontsConfig() {
  236. root.appendChild(currentFontsConfig.fontsEl);
  237. currentFontsConfig = null;
  238. return this;
  239. }
  240. /**
  241. * Converts the underlying DOM into an {@link InputStream} for building.
  242. *
  243. * @return an {@link InputStream}
  244. */
  245. public InputStream build() {
  246. try {
  247. Source src = new DOMSource(fopConfDOM);
  248. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  249. Result res = new StreamResult(baos);
  250. Transformer transformer = TransformerFactory.newInstance().newTransformer();
  251. transformer.transform(src, res);
  252. return new ByteArrayInputStream(baos.toByteArray());
  253. } catch (Exception e) {
  254. throw new RuntimeException(e);
  255. }
  256. }
  257. public void dump() {
  258. dump(System.out);
  259. }
  260. public void dump(OutputStream out) {
  261. TransformerFactory tf = TransformerFactory.newInstance();
  262. Transformer transformer;
  263. try {
  264. transformer = tf.newTransformer();
  265. } catch (TransformerConfigurationException e1) {
  266. throw new RuntimeException(e1);
  267. }
  268. transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
  269. transformer.setOutputProperty(OutputKeys.METHOD, "xml");
  270. transformer.setOutputProperty(OutputKeys.INDENT, "yes");
  271. transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
  272. transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
  273. try {
  274. transformer.transform(new DOMSource(fopConfDOM),
  275. new StreamResult(new OutputStreamWriter(out, "UTF-8")));
  276. } catch (UnsupportedEncodingException e) {
  277. throw new RuntimeException(e);
  278. } catch (TransformerException e) {
  279. throw new RuntimeException(e);
  280. }
  281. }
  282. public abstract static class RendererConfBuilder implements FontConfigurator<RendererConfBuilder> {
  283. private Element rendererEl;
  284. private FopConfBuilder fopConfBuilder;
  285. private Document fopConfDOM;
  286. private final String mimeType;
  287. private FontsConfBuilder<RendererConfBuilder> fontsConfBuilder;
  288. protected RendererConfBuilder(String mimeType) {
  289. this.mimeType = mimeType;
  290. }
  291. private void init(FopConfBuilder fopConfBuilder, Document fopConfDOM) {
  292. this.fopConfBuilder = fopConfBuilder;
  293. this.fopConfDOM = fopConfDOM;
  294. rendererEl = fopConfDOM.createElement("renderer");
  295. rendererEl.setAttribute("mime", mimeType);
  296. }
  297. protected final Element createElement(String name) {
  298. return createElement(name, rendererEl);
  299. }
  300. protected final Element createElement(String name, Element parent) {
  301. Element el = fopConfDOM.createElement(name);
  302. parent.appendChild(el);
  303. return el;
  304. }
  305. protected final Element createTextElement(String name, String value) {
  306. return createTextElement(name, value, rendererEl);
  307. }
  308. protected final Element createTextElement(RendererConfigOption option, String value) {
  309. return createTextElement(option.getName(), value, rendererEl);
  310. }
  311. protected final Element createTextElement(String name, String value, Element parent) {
  312. Element el = createElement(name, parent);
  313. el.setTextContent(value);
  314. return el;
  315. }
  316. /**
  317. * Starts a fonts config builder, for configuring the fonts handling system within FOP i.e.
  318. * the &lt;fonts&gt; element.
  319. *
  320. * @return the fonts config builder
  321. */
  322. public final FontsConfBuilder<RendererConfBuilder> startFontsConfig() {
  323. fontsConfBuilder = new FontsConfBuilder<RendererConfBuilder>(this);
  324. fontsConfBuilder.setFopConfDOM(fopConfBuilder.fopConfDOM);
  325. return fontsConfBuilder;
  326. }
  327. /**
  328. * Ends the fonts config builder.
  329. *
  330. * @return <b>this</b>
  331. */
  332. public final RendererConfBuilder endFontsConfig() {
  333. rendererEl.appendChild(fontsConfBuilder.fontsEl);
  334. fontsConfBuilder = null;
  335. return this;
  336. }
  337. /**
  338. * Ends the renderer specific config.
  339. *
  340. * @return the parent
  341. */
  342. public final FopConfBuilder endRendererConfig() {
  343. return fopConfBuilder.endRendererConfig();
  344. }
  345. public void dump() {
  346. fopConfBuilder.dump();
  347. }
  348. public void dump(OutputStream out) {
  349. fopConfBuilder.dump(out);
  350. }
  351. }
  352. public static final class FontsConfBuilder<P extends FontConfigurator<P>> {
  353. private Element fontsEl;
  354. private final P parent;
  355. private Document fopConfDOM;
  356. private Element fontSubstitutions;
  357. private FontTripletInfo<P> currentTripletInfo;
  358. private FontsConfBuilder(P parent) {
  359. this.parent = parent;
  360. }
  361. private void setFopConfDOM(Document fopConfDOM) {
  362. this.fopConfDOM = fopConfDOM;
  363. fontsEl = fopConfDOM.createElement("fonts");
  364. }
  365. /**
  366. * Add &lt;auto-detect&gt; to find fonts.
  367. *
  368. * @return <b>this</b>
  369. */
  370. public FontsConfBuilder<P> addAutoDetect() {
  371. fontsEl.appendChild(fopConfDOM.createElement("auto-detect"));
  372. return this;
  373. }
  374. /**
  375. * Add a &lt;directory&gt; for specifying a directory to check fonts in.
  376. *
  377. * @param directory the directory to find fonts within
  378. * @param recursive true to recurse through sub-directories
  379. * @return <b>this</b>
  380. */
  381. public FontsConfBuilder<P> addDirectory(String directory, boolean recursive) {
  382. Element dir = fopConfDOM.createElement("directory");
  383. dir.setAttribute("recursive", String.valueOf(recursive));
  384. dir.setTextContent(directory);
  385. fontsEl.appendChild(dir);
  386. return this;
  387. }
  388. /**
  389. * Create a font &lt;substitution&gt;.
  390. *
  391. * @param fromFamily from font family name
  392. * @param fromStyle from font style
  393. * @param fromWeight from font weight
  394. * @param toFamily to font family name
  395. * @param toStyle to font style
  396. * @param toWeight to font weight
  397. * @return <b>this</b>
  398. */
  399. public P substituteFonts(String fromFamily, String fromStyle,
  400. String fromWeight, String toFamily, String toStyle, String toWeight) {
  401. if (fontSubstitutions == null) {
  402. fontSubstitutions = fopConfDOM.createElement("substitutions");
  403. }
  404. Element fontSubEl = fopConfDOM.createElement("substitution");
  405. fontSubEl.appendChild(createSubstitutionEl("from", fromFamily, fromStyle, fromWeight));
  406. fontSubEl.appendChild(createSubstitutionEl("to", toFamily, toStyle, toWeight));
  407. fontSubstitutions.appendChild(fontSubEl);
  408. fontsEl.appendChild(fontSubstitutions);
  409. return parent;
  410. }
  411. private Element createSubstitutionEl(String elName, String family, String style,
  412. String weight) {
  413. Element element = fopConfDOM.createElement(elName);
  414. addAttribute(element, "font-family", family);
  415. addAttribute(element, "font-style", style);
  416. addAttribute(element, "font-weight", weight);
  417. return element;
  418. }
  419. private void addAttribute(Element fontSub, String attName, String attValue) {
  420. if (attName != null && attValue != null) {
  421. fontSub.setAttribute(attName, attValue);
  422. }
  423. }
  424. /**
  425. * Start a &lt;font&gt; configuration element.
  426. *
  427. * @param metricsURL the URL to the metrics resource
  428. * @param embedURL the URL to the font resource
  429. * @return <b>this</b>
  430. */
  431. public FontTripletInfo<P> startFont(String metricsURL, String embedURL) {
  432. currentTripletInfo = new FontTripletInfo<P>(this, metricsURL, embedURL);
  433. return currentTripletInfo;
  434. }
  435. private FontsConfBuilder<P> endFontTriplet(Element el) {
  436. fontsEl.appendChild(el);
  437. currentTripletInfo = null;
  438. return this;
  439. }
  440. /**
  441. * Ends a font configuration element .
  442. *
  443. * @return the parent
  444. */
  445. public P endFontConfig() {
  446. return parent.endFontsConfig();
  447. }
  448. public final class FontTripletInfo<T> {
  449. private final Element fontEl;
  450. private final FontsConfBuilder<P> parent;
  451. private FontTripletInfo(FontsConfBuilder<P> parent,
  452. String metricsURL, String embedURL) {
  453. this.parent = parent;
  454. fontEl = fopConfDOM.createElement("font");
  455. addAttribute(fontEl, "metrics-url", metricsURL);
  456. addAttribute(fontEl, "embed-url", embedURL);
  457. }
  458. /**
  459. * Add triplet information to a font.
  460. *
  461. * @param name the font name
  462. * @param style the font style
  463. * @param weight the font weight
  464. * @return <b>this</b>
  465. */
  466. public FontTripletInfo<T> addTriplet(String name, String style, String weight) {
  467. Element tripletEl = fopConfDOM.createElement("font-triplet");
  468. addAttribute(tripletEl, "name", name);
  469. addAttribute(tripletEl, "style", style);
  470. addAttribute(tripletEl, "weight", weight);
  471. fontEl.appendChild(tripletEl);
  472. return this;
  473. }
  474. /**
  475. * Ends the font configuration element.
  476. *
  477. * @return the parent
  478. */
  479. public FontsConfBuilder<P> endFont() {
  480. return parent.endFontTriplet(fontEl);
  481. }
  482. }
  483. }
  484. }