| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* $Id$ */ |
| |
| package org.apache.fop.apps; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.io.OutputStreamWriter; |
| import java.io.UnsupportedEncodingException; |
| import java.lang.reflect.InvocationTargetException; |
| |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.transform.OutputKeys; |
| import javax.xml.transform.Result; |
| import javax.xml.transform.Source; |
| import javax.xml.transform.Transformer; |
| import javax.xml.transform.TransformerConfigurationException; |
| import javax.xml.transform.TransformerException; |
| import javax.xml.transform.TransformerFactory; |
| import javax.xml.transform.dom.DOMSource; |
| import javax.xml.transform.stream.StreamResult; |
| |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| |
| import org.apache.fop.render.RendererConfigOption; |
| |
| /** |
| * A builder class for creating fop.xconf XML DOMs for test purposes. You can set all the necessary |
| * fields inline and build the fop conf DOM into an {@link InputStream}. |
| * <pre> |
| * {@code |
| * new FopConfBuilder().setStrictValidation(true) |
| * .startRendererBuilder(RendererConfBuilder.class) |
| * .startFontsConfig() |
| * .startFont(null, null) |
| * .addTriplet("Gladiator", "normal", "normal") |
| * .endFont() |
| * .endFontConfig() |
| * .endRendererConfigBuilder().build() |
| * } |
| * </pre> |
| */ |
| public class FopConfBuilder implements FontConfigurator<FopConfBuilder> { |
| |
| private final Element root; |
| private final Document fopConfDOM; |
| private RendererConfBuilder currentRendererConfig; |
| private FontsConfBuilder<FopConfBuilder> currentFontsConfig; |
| |
| /** |
| * Constructs the FopConfBuilder and initializes the underlying DOM. |
| */ |
| public FopConfBuilder() { |
| try { |
| DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); |
| dbf.setNamespaceAware(true); |
| DocumentBuilder db = dbf.newDocumentBuilder(); |
| fopConfDOM = db.newDocument(); |
| root = fopConfDOM.createElement("fop"); |
| fopConfDOM.appendChild(root); |
| } catch (ParserConfigurationException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| private FopConfBuilder createElement(String elementName, String elementValue) { |
| Element el = fopConfDOM.createElement(elementName); |
| el.appendChild(fopConfDOM.createTextNode(elementValue)); |
| root.appendChild(el); |
| return this; |
| } |
| |
| /** |
| * Set the <font-base> tag within the fop.xconf. |
| * |
| * @param fontBase the font base value |
| * @return <b>this</b> |
| */ |
| public FopConfBuilder setFontBaseURI(String fontBase) { |
| return createElement("font-base", fontBase); |
| } |
| |
| /** |
| * Set the <base> tag within the fop.xconf. |
| * |
| * @param baseURI the base URI |
| * @return <b>this</b> |
| */ |
| public FopConfBuilder setBaseURI(String baseURI) { |
| return createElement("base", baseURI); |
| } |
| |
| /** |
| * Set the <strict-validation> tag within the fop.xconf. |
| * |
| * @param validateStrictly true to enforce strict FO validation |
| * @return <b>this</b> |
| */ |
| public FopConfBuilder setStrictConfiguration(boolean validateStrictly) { |
| return createElement("strict-configuration", String.valueOf(validateStrictly)); |
| } |
| |
| /** |
| * Set the <strict-validation> tag within the fop.xconf. |
| * |
| * @param validateStrictly true to enforce strict configuration validation |
| * @return <b>this</b> |
| */ |
| public FopConfBuilder setStrictValidation(boolean validateStrictly) { |
| return createElement("strict-validation", String.valueOf(validateStrictly)); |
| } |
| |
| /** |
| * Set the <accessibility> tag within the fop.xconf. |
| * |
| * @param setAccessibility true to enable accessibility features |
| * @return <b>this</b> |
| */ |
| public FopConfBuilder setAccessibility(boolean setAccessibility) { |
| return createElement("accessibility", String.valueOf(setAccessibility)); |
| } |
| |
| @Deprecated |
| public FopConfBuilder setHyphenationBaseURI(String uri) { |
| return createElement("hyphenation-base", uri); |
| } |
| |
| /** |
| * Set the <source-resolution> tag within the fop.xconf. |
| * |
| * @param srcRes the source resolution |
| * @return <b>this</b> |
| */ |
| public FopConfBuilder setSourceResolution(float srcRes) { |
| return createElement("source-resolution", String.valueOf(srcRes)); |
| } |
| |
| /** |
| * Set the <target-resolution> tag within the fop.xconf. |
| * |
| * @param targetRes the target resolution |
| * @return <b>this</b> |
| */ |
| public FopConfBuilder setTargetResolution(float targetRes) { |
| return createElement("target-resolution", String.valueOf(targetRes)); |
| } |
| |
| /** |
| * Set the <break-indent-inheritance> tag within the fop.xconf. |
| * |
| * @param value true to break indent inheritance |
| * @return <b>this</b> |
| */ |
| public FopConfBuilder setBreakIndentInheritance(boolean value) { |
| return createElement("break-indent-inheritance", String.valueOf(value)); |
| } |
| |
| /** |
| * Set the <prefer-renderer> tag within the fop.xconf. |
| * |
| * @param value true to prefer the renderer |
| * @return <b>this</b> |
| */ |
| public FopConfBuilder setPreferRenderer(boolean value) { |
| return createElement("prefer-renderer", String.valueOf(value)); |
| } |
| |
| /** |
| * Set the <default-page-settings> tag within the fop.xconf. |
| * |
| * @param height the height of the page |
| * @param width the width of the page |
| * @return <b>this</b> |
| */ |
| public FopConfBuilder setDefaultPageSettings(float height, float width) { |
| Element el = fopConfDOM.createElement("default-page-settings"); |
| el.setAttribute("height", String.valueOf(height)); |
| el.setAttribute("width", String.valueOf(width)); |
| root.appendChild(el); |
| return this; |
| } |
| |
| /** |
| * Sets whether the fonts cache is used or not. |
| * |
| * @param enableFontCaching true to enable font data caching. |
| * @return <b>this</b> |
| */ |
| public FopConfBuilder useCache(boolean enableFontCaching) { |
| return createElement("use-cache", String.valueOf(enableFontCaching)); |
| } |
| |
| /** |
| * Starts a renderer specific config builder. |
| * |
| * @param mimeType the MIME type of the builder |
| * @return the renderer config builder |
| */ |
| public <T extends RendererConfBuilder> T startRendererConfig(Class<T> rendererConfigClass) { |
| try { |
| currentRendererConfig = rendererConfigClass.getDeclaredConstructor().newInstance(); |
| } catch (InstantiationException e) { |
| throw new RuntimeException(e); |
| } catch (NoSuchMethodException e) { |
| throw new RuntimeException(e); |
| } catch (InvocationTargetException e) { |
| throw new RuntimeException(e); |
| } catch (IllegalAccessException e) { |
| throw new RuntimeException(e); |
| } |
| currentRendererConfig.init(this, fopConfDOM); |
| return rendererConfigClass.cast(currentRendererConfig); |
| } |
| |
| /** |
| * Ends a renderer specific config builder. |
| * |
| * @return <b>this</b> |
| */ |
| private FopConfBuilder endRendererConfig() { |
| Element renderersEl = fopConfDOM.createElement("renderers"); |
| renderersEl.appendChild(currentRendererConfig.rendererEl); |
| root.appendChild(renderersEl); |
| currentRendererConfig = null; |
| return this; |
| } |
| |
| /** |
| * Starts a fonts config builder, for configuring the fonts handling system within FOP i.e. |
| * the <fonts> element. |
| * |
| * @return the fop config builder |
| */ |
| public FontsConfBuilder<FopConfBuilder> startFontsConfig() { |
| currentFontsConfig = new FontsConfBuilder<FopConfBuilder>(this); |
| currentFontsConfig.setFopConfDOM(fopConfDOM); |
| return currentFontsConfig; |
| } |
| |
| /** |
| * Ends the fonts config builder. |
| * |
| * @return <b>this</b> |
| */ |
| public FopConfBuilder endFontsConfig() { |
| root.appendChild(currentFontsConfig.fontsEl); |
| currentFontsConfig = null; |
| return this; |
| } |
| |
| /** |
| * Converts the underlying DOM into an {@link InputStream} for building. |
| * |
| * @return an {@link InputStream} |
| */ |
| public InputStream build() { |
| try { |
| Source src = new DOMSource(fopConfDOM); |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| Result res = new StreamResult(baos); |
| Transformer transformer = TransformerFactory.newInstance().newTransformer(); |
| transformer.transform(src, res); |
| return new ByteArrayInputStream(baos.toByteArray()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public void dump() { |
| dump(System.out); |
| } |
| |
| public void dump(OutputStream out) { |
| TransformerFactory tf = TransformerFactory.newInstance(); |
| Transformer transformer; |
| try { |
| transformer = tf.newTransformer(); |
| } catch (TransformerConfigurationException e1) { |
| throw new RuntimeException(e1); |
| } |
| transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); |
| transformer.setOutputProperty(OutputKeys.METHOD, "xml"); |
| transformer.setOutputProperty(OutputKeys.INDENT, "yes"); |
| transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); |
| transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); |
| try { |
| transformer.transform(new DOMSource(fopConfDOM), |
| new StreamResult(new OutputStreamWriter(out, "UTF-8"))); |
| } catch (UnsupportedEncodingException e) { |
| throw new RuntimeException(e); |
| } catch (TransformerException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public abstract static class RendererConfBuilder implements FontConfigurator<RendererConfBuilder> { |
| |
| private Element rendererEl; |
| |
| private FopConfBuilder fopConfBuilder; |
| |
| private Document fopConfDOM; |
| |
| private final String mimeType; |
| |
| private FontsConfBuilder<RendererConfBuilder> fontsConfBuilder; |
| |
| protected RendererConfBuilder(String mimeType) { |
| this.mimeType = mimeType; |
| } |
| |
| private void init(FopConfBuilder fopConfBuilder, Document fopConfDOM) { |
| this.fopConfBuilder = fopConfBuilder; |
| this.fopConfDOM = fopConfDOM; |
| rendererEl = fopConfDOM.createElement("renderer"); |
| rendererEl.setAttribute("mime", mimeType); |
| } |
| |
| protected final Element createElement(String name) { |
| return createElement(name, rendererEl); |
| } |
| |
| protected final Element createElement(String name, Element parent) { |
| Element el = fopConfDOM.createElement(name); |
| parent.appendChild(el); |
| return el; |
| } |
| |
| protected final Element createTextElement(String name, String value) { |
| return createTextElement(name, value, rendererEl); |
| } |
| |
| protected final Element createTextElement(RendererConfigOption option, String value) { |
| return createTextElement(option.getName(), value, rendererEl); |
| } |
| |
| protected final Element createTextElement(String name, String value, Element parent) { |
| Element el = createElement(name, parent); |
| el.setTextContent(value); |
| return el; |
| } |
| |
| /** |
| * Starts a fonts config builder, for configuring the fonts handling system within FOP i.e. |
| * the <fonts> element. |
| * |
| * @return the fonts config builder |
| */ |
| public final FontsConfBuilder<RendererConfBuilder> startFontsConfig() { |
| fontsConfBuilder = new FontsConfBuilder<RendererConfBuilder>(this); |
| fontsConfBuilder.setFopConfDOM(fopConfBuilder.fopConfDOM); |
| return fontsConfBuilder; |
| } |
| |
| /** |
| * Ends the fonts config builder. |
| * |
| * @return <b>this</b> |
| */ |
| public final RendererConfBuilder endFontsConfig() { |
| rendererEl.appendChild(fontsConfBuilder.fontsEl); |
| fontsConfBuilder = null; |
| return this; |
| } |
| |
| /** |
| * Ends the renderer specific config. |
| * |
| * @return the parent |
| */ |
| public final FopConfBuilder endRendererConfig() { |
| return fopConfBuilder.endRendererConfig(); |
| } |
| |
| public void dump() { |
| fopConfBuilder.dump(); |
| } |
| |
| public void dump(OutputStream out) { |
| fopConfBuilder.dump(out); |
| } |
| } |
| |
| public static final class FontsConfBuilder<P extends FontConfigurator<P>> { |
| private Element fontsEl; |
| private final P parent; |
| private Document fopConfDOM; |
| private Element fontSubstitutions; |
| private FontTripletInfo<P> currentTripletInfo; |
| |
| private FontsConfBuilder(P parent) { |
| this.parent = parent; |
| } |
| |
| private void setFopConfDOM(Document fopConfDOM) { |
| this.fopConfDOM = fopConfDOM; |
| fontsEl = fopConfDOM.createElement("fonts"); |
| } |
| |
| /** |
| * Add <auto-detect> to find fonts. |
| * |
| * @return <b>this</b> |
| */ |
| public FontsConfBuilder<P> addAutoDetect() { |
| fontsEl.appendChild(fopConfDOM.createElement("auto-detect")); |
| return this; |
| } |
| |
| /** |
| * Add a <directory> for specifying a directory to check fonts in. |
| * |
| * @param directory the directory to find fonts within |
| * @param recursive true to recurse through sub-directories |
| * @return <b>this</b> |
| */ |
| public FontsConfBuilder<P> addDirectory(String directory, boolean recursive) { |
| Element dir = fopConfDOM.createElement("directory"); |
| dir.setAttribute("recursive", String.valueOf(recursive)); |
| dir.setTextContent(directory); |
| fontsEl.appendChild(dir); |
| return this; |
| } |
| |
| /** |
| * Create a font <substitution>. |
| * |
| * @param fromFamily from font family name |
| * @param fromStyle from font style |
| * @param fromWeight from font weight |
| * @param toFamily to font family name |
| * @param toStyle to font style |
| * @param toWeight to font weight |
| * @return <b>this</b> |
| */ |
| public P substituteFonts(String fromFamily, String fromStyle, |
| String fromWeight, String toFamily, String toStyle, String toWeight) { |
| if (fontSubstitutions == null) { |
| fontSubstitutions = fopConfDOM.createElement("substitutions"); |
| } |
| Element fontSubEl = fopConfDOM.createElement("substitution"); |
| fontSubEl.appendChild(createSubstitutionEl("from", fromFamily, fromStyle, fromWeight)); |
| fontSubEl.appendChild(createSubstitutionEl("to", toFamily, toStyle, toWeight)); |
| fontSubstitutions.appendChild(fontSubEl); |
| fontsEl.appendChild(fontSubstitutions); |
| return parent; |
| } |
| |
| private Element createSubstitutionEl(String elName, String family, String style, |
| String weight) { |
| Element element = fopConfDOM.createElement(elName); |
| addAttribute(element, "font-family", family); |
| addAttribute(element, "font-style", style); |
| addAttribute(element, "font-weight", weight); |
| return element; |
| } |
| |
| private void addAttribute(Element fontSub, String attName, String attValue) { |
| if (attName != null && attValue != null) { |
| fontSub.setAttribute(attName, attValue); |
| } |
| } |
| |
| /** |
| * Start a <font> configuration element. |
| * |
| * @param metricsURL the URL to the metrics resource |
| * @param embedURL the URL to the font resource |
| * @return <b>this</b> |
| */ |
| public FontTripletInfo<P> startFont(String metricsURL, String embedURL) { |
| currentTripletInfo = new FontTripletInfo<P>(this, metricsURL, embedURL); |
| return currentTripletInfo; |
| } |
| |
| private FontsConfBuilder<P> endFontTriplet(Element el) { |
| fontsEl.appendChild(el); |
| currentTripletInfo = null; |
| return this; |
| } |
| |
| /** |
| * Ends a font configuration element . |
| * |
| * @return the parent |
| */ |
| public P endFontConfig() { |
| return parent.endFontsConfig(); |
| } |
| |
| public final class FontTripletInfo<T> { |
| private final Element fontEl; |
| private final FontsConfBuilder<P> parent; |
| |
| private FontTripletInfo(FontsConfBuilder<P> parent, |
| String metricsURL, String embedURL) { |
| this.parent = parent; |
| fontEl = fopConfDOM.createElement("font"); |
| addAttribute(fontEl, "metrics-url", metricsURL); |
| addAttribute(fontEl, "embed-url", embedURL); |
| } |
| |
| /** |
| * Add triplet information to a font. |
| * |
| * @param name the font name |
| * @param style the font style |
| * @param weight the font weight |
| * @return <b>this</b> |
| */ |
| public FontTripletInfo<T> addTriplet(String name, String style, String weight) { |
| Element tripletEl = fopConfDOM.createElement("font-triplet"); |
| addAttribute(tripletEl, "name", name); |
| addAttribute(tripletEl, "style", style); |
| addAttribute(tripletEl, "weight", weight); |
| fontEl.appendChild(tripletEl); |
| return this; |
| } |
| |
| /** |
| * Ends the font configuration element. |
| * |
| * @return the parent |
| */ |
| public FontsConfBuilder<P> endFont() { |
| return parent.endFontTriplet(fontEl); |
| } |
| } |
| } |
| } |