View Javadoc

1   /*
2    * Copyright 2007 - 2007 JEuclid, http://jeuclid.sf.net
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  
17  /* $Id: Processor.java,v 5a7becda9147 2009/10/23 10:57:54 max $ */
18  
19  package net.sourceforge.jeuclid.converter;
20  
21  import java.io.IOException;
22  
23  import javax.xml.transform.Result;
24  import javax.xml.transform.Source;
25  import javax.xml.transform.Transformer;
26  import javax.xml.transform.TransformerException;
27  import javax.xml.transform.TransformerFactory;
28  import javax.xml.transform.dom.DOMResult;
29  import javax.xml.transform.dom.DOMSource;
30  
31  import net.sourceforge.jeuclid.LayoutContext;
32  import net.sourceforge.jeuclid.context.LayoutContextImpl;
33  import net.sourceforge.jeuclid.converter.ConverterPlugin.DocumentWithDimension;
34  import net.sourceforge.jeuclid.elements.AbstractJEuclidElement;
35  import net.sourceforge.jeuclid.elements.generic.MathImpl;
36  import net.sourceforge.jeuclid.parser.Parser;
37  
38  import org.apache.commons.logging.Log;
39  import org.apache.commons.logging.LogFactory;
40  import org.w3c.dom.Element;
41  import org.w3c.dom.Node;
42  import org.w3c.dom.NodeList;
43  import org.xml.sax.SAXException;
44  
45  /**
46   * Contains the actual processing routines.
47   * <p>
48   * To use this class obtain an instance of the Processor singleton instance.
49   * Then use the {@link #process(Source, Result)} function to process your
50   * Document.
51   * <p>
52   * This will replace all occurrences of MathML within fo:instream tags by the
53   * equivalent SVG code. It will also add a baseline-shift attribute so that the
54   * formula is in line with the rest of the text.
55   * 
56   * @version $Revision: 5a7becda9147 $
57   */
58  public final class Processor {
59  
60      private static final class SingletonHolder {
61          private static final Processor INSTANCE = new Processor();
62  
63          private SingletonHolder() {
64          }
65      }
66  
67      /**
68       * Logger for this class
69       */
70      private static final Log LOGGER = LogFactory.getLog(Processor.class);
71  
72      // private static final String NAMESPACE_HTML =
73      // "http://www.w3.org/1999/xhtml";
74  
75      private final Transformer transformer;
76  
77      /**
78       * Default constructor.
79       */
80      protected Processor() {
81          Transformer t;
82          try {
83              t = TransformerFactory.newInstance().newTransformer();
84          } catch (final TransformerException e) {
85              t = null;
86              Processor.LOGGER.warn(e.getMessage());
87              assert false;
88          }
89          this.transformer = t;
90      }
91  
92      /**
93       * Retrieve the processor singleton object.
94       * 
95       * @return the Processor.
96       */
97      public static Processor getInstance() {
98          return Processor.SingletonHolder.INSTANCE;
99      }
100 
101     /**
102      * use {@link #getInstance()} instead.
103      * 
104      * @return see {@link #getInstance()}
105      * @throws TransformerException
106      *             see {@link #getInstance()}
107      * @deprecated use {@link #getInstance()} instead.
108      */
109     @Deprecated
110     public static Processor getProcessor() throws TransformerException {
111         return Processor.getInstance();
112     }
113 
114     /**
115      * Pre-process a .fo file.
116      * 
117      * @param inputSource
118      *            Input File
119      * @param result
120      *            Output File
121      * @param context
122      *            LayoutContext.
123      * @throws TransformerException
124      *             an error occurred during the processing.
125      */
126     public void process(final Source inputSource, final Result result,
127             final LayoutContext context) throws TransformerException {
128         Processor.LOGGER.info("Processing " + inputSource.getSystemId()
129                 + " to " + result.getSystemId());
130         try {
131             final Node doc = Parser.getInstance().parse(inputSource);
132             this.processSubtree(doc, context);
133             final DOMSource source = new DOMSource(doc);
134             this.transformer.transform(source, result);
135         } catch (final IOException e) {
136             throw new TransformerException("IOException", e);
137         } catch (final SAXException e) {
138             throw new TransformerException("SAXException", e);
139         }
140     }
141 
142     /**
143      * Pre-process a .fo file.
144      * 
145      * @param inputSource
146      *            Input File
147      * @param result
148      *            Output File
149      * @throws TransformerException
150      *             an error occurred during the processing.
151      */
152     public void process(final Source inputSource, final Result result)
153             throws TransformerException {
154         this.process(inputSource, result, LayoutContextImpl
155                 .getDefaultLayoutContext());
156     }
157 
158     private void processSubtree(final Node node, final LayoutContext context) {
159         if (AbstractJEuclidElement.URI.equals(node.getNamespaceURI())
160                 && MathImpl.ELEMENT.equals(node.getLocalName())) {
161 
162             final DocumentWithDimension svgdocdim = Converter
163                     .getInstance()
164                     .convert(
165                             node,
166                             net.sourceforge.jeuclid.converter.Converter.TYPE_SVG,
167                             context);
168 
169             final float baselinePercent = -(svgdocdim.getBaseline() / (float) svgdocdim
170                     .getDimension().getHeight()) * 100f;
171 
172             final Node parent = node.getParentNode();
173             if ("http://www.w3.org/1999/XSL/Format".equals(parent
174                     .getNamespaceURI())
175                     && "instream-foreign-object".equals(parent.getLocalName())) {
176                 final Element pElement = (Element) parent;
177                 pElement
178                         .setAttribute("alignment-adjust", baselinePercent + "%");
179             }
180             this.safeReplaceChild(parent, node, svgdocdim.getDocument()
181                     .getFirstChild());
182         } else {
183             this.processChildren(node, context);
184             // TODO: This is an IE-Fix, but does not work yet.
185             // final Node parent = node.getParentNode();
186             // if ((parent != null)
187             // && (Processor.NAMESPACE_HTML.equals(parent
188             // .getNamespaceURI()))
189             // && ("html".equals(parent.getLocalName()))
190             // && ("head".equals(node.getLocalName()))) {
191             // ((Element) parent).setAttribute("xmlns:svg",
192             // "http://www.w3.org/2000/svg");
193             // final Document ownerDoc = node.getOwnerDocument();
194             // final Element objectElement = ownerDoc
195             // .createElement("object");
196             // objectElement.setAttribute("id", "AdobeSVG");
197             // objectElement.setAttribute("classid",
198             // "clsid:78156a80-c6a1-4bbf-8e6a-3cd390eeb4e2");
199             // node.appendChild(objectElement);
200             // final ProcessingInstruction pi = ownerDoc
201             // .createProcessingInstruction("import",
202             // "namespace=\"svg\" implementation=\"#AdobeSVG\"");
203             // node.appendChild(pi);
204             // }
205         }
206     }
207 
208     private void safeReplaceChild(final Node parent, final Node oldChild,
209             final Node newChild) {
210         try {
211             final DOMSource source = new DOMSource(newChild);
212             final DOMResult result = new DOMResult(parent);
213 
214             this.transformer.transform(source, result);
215         } catch (final TransformerException e) {
216             Processor.LOGGER.warn("TranformerException: " + e.getMessage());
217         }
218         parent.removeChild(oldChild);
219     }
220 
221     private void processChildren(final Node node, final LayoutContext context) {
222         final NodeList childList = node.getChildNodes();
223         if (childList != null) {
224             for (int i = 0; i < childList.getLength(); i++) {
225                 final Node child = childList.item(i);
226                 this.processSubtree(child, context);
227             }
228         }
229     }
230 
231 }