001/*
002 * Copyright 2002 - 2008 JEuclid, http://jeuclid.sf.net
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017/* $Id$ */
018
019package net.sourceforge.jeuclid.xmlgraphics;
020
021import java.io.IOException;
022import java.io.InputStream;
023
024import javax.xml.transform.Source;
025import javax.xml.transform.dom.DOMSource;
026import javax.xml.transform.stream.StreamSource;
027
028import net.sourceforge.jeuclid.Constants;
029import net.sourceforge.jeuclid.context.LayoutContextImpl;
030import net.sourceforge.jeuclid.elements.AbstractJEuclidElement;
031import net.sourceforge.jeuclid.elements.generic.MathImpl;
032import net.sourceforge.jeuclid.layout.JEuclidView;
033import net.sourceforge.jeuclid.parser.Parser;
034
035import org.apache.commons.logging.Log;
036import org.apache.commons.logging.LogFactory;
037import org.apache.fop.util.UnclosableInputStream;
038import org.apache.xmlgraphics.image.loader.ImageContext;
039import org.apache.xmlgraphics.image.loader.ImageException;
040import org.apache.xmlgraphics.image.loader.ImageInfo;
041import org.apache.xmlgraphics.image.loader.ImageSize;
042import org.apache.xmlgraphics.image.loader.impl.AbstractImagePreloader;
043import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
044import org.apache.xmlgraphics.image.loader.util.ImageUtil;
045import org.w3c.dom.Document;
046import org.w3c.dom.Element;
047import org.xml.sax.SAXException;
048
049/**
050 * @version $Revision$
051 */
052public class PreloaderMathML extends AbstractImagePreloader {
053    /**
054     * Convert from point to millipoint.
055     */
056    public static final float MPT_FACTOR = 1000.0f;
057
058    /**
059     * Logger for this class
060     */
061    private static final Log LOGGER = LogFactory
062            .getLog(PreloaderMathML.class);
063
064    /**
065     * Default Constructor.
066     */
067    public PreloaderMathML() {
068        // Empty on purpose
069    }
070
071    /** {@inheritDoc} */
072    public ImageInfo preloadImage(final String uri, final Source src,
073            final ImageContext context) throws ImageException, IOException {
074        final Document n = this.parseSource(src);
075        if (n != null) {
076            return this.createImageInfo(uri, context, n);
077        }
078
079        return null;
080    }
081
082    @SuppressWarnings("unchecked")
083    private ImageInfo createImageInfo(final String uri,
084            final ImageContext context, final Document n) {
085        final ImageInfo info = new ImageInfo(uri, Constants.MATHML_MIMETYPE);
086        final ImageSize size = new ImageSize();
087        final JEuclidView view = new JEuclidView(n, LayoutContextImpl
088                .getDefaultLayoutContext(), null);
089        final int descentMpt = (int) (view.getDescentHeight() * PreloaderMathML.MPT_FACTOR);
090        final int ascentMpt = (int) (view.getAscentHeight() * PreloaderMathML.MPT_FACTOR);
091
092        size.setSizeInMillipoints(
093                (int) (view.getWidth() * PreloaderMathML.MPT_FACTOR),
094                ascentMpt + descentMpt);
095        size.setBaselinePositionFromBottom(descentMpt);
096        // Set the resolution to that of the FOUserAgent
097        size.setResolution(context.getSourceResolution());
098        size.calcPixelsFromSize();
099        info.setSize(size);
100
101        // The whole image had to be loaded for this, so keep it
102        final ImageXMLDOM xmlImage = new ImageXMLDOM(info, n,
103                AbstractJEuclidElement.URI);
104        info.getCustomObjects().put(ImageInfo.ORIGINAL_IMAGE, xmlImage);
105        return info;
106    }
107
108    private Document parseSource(final Source src) {
109        Document n = null;
110        InputStream in = null;
111        try {
112            if (src instanceof DOMSource) {
113                final DOMSource domSrc = (DOMSource) src;
114                n = (Document) domSrc.getNode();
115            } else {
116                in = new UnclosableInputStream(ImageUtil.needInputStream(src));
117                final int length = in.available();
118                in.mark(length + 1);
119                n = Parser.getInstance().parseStreamSource(
120                        new StreamSource(in));
121            }
122            final Element rootNode = n.getDocumentElement();
123            if (!(AbstractJEuclidElement.URI.equals(rootNode
124                    .getNamespaceURI()) || MathImpl.ELEMENT.equals(rootNode
125                    .getNodeName()))) {
126                n = null;
127            }
128        } catch (final IOException e) {
129            n = null;
130        } catch (final SAXException e) {
131            n = null;
132        } catch (final IllegalArgumentException e) {
133            n = null;
134        } catch (final NullPointerException e) {
135            // Due to a bug in xmlgraphics-commons 1.3.1 which sometimes
136            // creates wrapper around null streams if files do not exist.
137            n = null;
138        }
139        try {
140            if (in != null) {
141                in.reset();
142            }
143        } catch (final IOException ioe) {
144            PreloaderMathML.LOGGER.warn("Should never happen: "
145                    + ioe.getMessage());
146        } catch (final NullPointerException e) {
147            // Due to a bug in xmlgraphics-commons 1.3.1 which sometimes
148            // creates wrapper around null streams if files do not exist.
149            n = null;
150        }
151        return n;
152    }
153}