MathBase.java :  » XML » Jaxe-3.3 » jaxe » equations » Java Open Source

Java Open Source » XML » Jaxe 3.3 
Jaxe 3.3 » jaxe » equations » MathBase.java
/*
Jaxe - Editeur XML en Java

Copyright (C) 2003 Observatoire de Paris-Meudon

Ce programme est un logiciel libre ; vous pouvez le redistribuer et/ou le modifier conformment aux dispositions de la Licence Publique Gnrale GNU, telle que publie par la Free Software Foundation ; version 2 de la licence, ou encore ( votre choix) toute version ultrieure.

Ce programme est distribu dans l'espoir qu'il sera utile, mais SANS AUCUNE GARANTIE ; sans mme la garantie implicite de COMMERCIALISATION ou D'ADAPTATION A UN OBJET PARTICULIER. Pour plus de dtail, voir la Licence Publique Gnrale GNU .

Vous devez avoir reu un exemplaire de la Licence Publique Gnrale GNU en mme temps que ce programme ; si ce n'est pas le cas, crivez  la Free Software Foundation Inc., 675 Mass Ave, Cambridge, MA 02139, Etats-Unis.
*/

package jaxe.equations;

import org.apache.log4j.Logger;

//import org.w3c.dom.*;
//import org.apache.xerces.parsers.*;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.font.GlyphVector;
import java.util.Vector;

import jaxe.equations.element.MathRootElement;

/**
 * The base for creating a MathElement tree
 *
 * @author <a href="mailto:stephan@vern.chem.tu-berlin.de">Stephan Michels</a>
 * @author <a href="mailto:sielaff@vern.chem.tu-berlin.de">Marco Sielaff</a>
 * @version %I%, %G%
 */
public class MathBase
{
    /**
     * Logger for this class
     */
    private static final Logger LOG = Logger.getLogger(MathBase.class);

    private String fontname = "Default";
    private int fontstyle = Font.PLAIN;

    private int inlinefontsize = 12;
    private int displayfontsize = 14;

    private final int minfontsize = 8;
    private final int maxfontsize = 60;

    private final Font[] fonts = new Font[maxfontsize];

    private FontMetrics[] fontmetrics = null;

    private final Font[] symbolFonts = new Font[maxfontsize];

    private FontMetrics[] symbolFontmetrics = null;

    private boolean debug = false;

    /** Inline mathematical expression */
    public final static int INLINE = 0;

    /** Non inline mathematical expression */
    public final static int DISPLAY = 1;

    private final int mode = INLINE;

    private MathRootElement rootElement;
    
    // mega-bug: Windows does not include any Unicode equivalence for its Symbol font: we have to do it by hand...
    public boolean windaube;
    private final char[] Symbol_chars = {'\u239B', '\u239C', '\u239D',
                    '\u239E', '\u239F', '\u23A0',
                    '\u23A1', '\u23A2', '\u23A3',
                    '\u23A4', '\u23A5', '\u23A6',
                    '\u23A7', '\u23A8', '\u23AA', '\u23A9',
                    '\u23AB', '\u23AC', '\u23AD',
                    '\u2320', '\u2321',
                    '\u2211', '\u220F'};
    
    private final int[] MS_Symbol_codes = {167, 168, 169,
                    183, 184, 185,
                    170, 171, 172,
                    186, 187, 188,
                    173, 174, 176, 175,
                    189, 190, 191,
                    180, 182,
                    166, 150};
    
    private final Vector<Font> goodFonts; // cache for findfont
    
    /**
     * Creates a MathBase
     *
     * @param element Root element of a math tree
     * @param fontname Name of the preferred font
     * @param fontstyle Style of the preferred font, see java.awt.Font
     * @param inlinefontsize Size of the preferred font used by inline equations
     * @param displayfontsize Size of the preferred font used by non inline equations
     * @param gcalc Graphics object to use to calculate character sizes (nothing will be painted on it)
     */
    public MathBase(final MathRootElement element, final String fontname, final int fontstyle,
                                    final int inlinefontsize, final int displayfontsize, final Graphics gcalc)
    {
        this(fontname, fontstyle, inlinefontsize, displayfontsize, gcalc);
        setRootElement(element);
    }

    /**
     * Creates a MathBase
     *
     * @param element Root element of a math tree
     * @param gcalc Graphics object to use to calculate character sizes (nothing will be painted on it)
     */
    public MathBase(final MathRootElement element, final Graphics gcalc)
    {
        this(element, "Default", Font.PLAIN, 12, 14, gcalc);
    }

    /**
     * Creates a MathBase
     *
     * @param fontname Name of the preferred font
     * @param fontstyle Style of the preferred font, see java.awt.Font
     * @param inlinefontsize Size of the preferred font used by inline equations
     * @param displayfontsize Size of the preferred font used by non inline equations
     * @param gcalc Graphics object to use to calculate character sizes (nothing will be painted on it)
     */
    public MathBase(final String fontname, final int fontstyle, final int inlinefontsize,
                                    final int displayfontsize, final Graphics gcalc)
    {
        this.fontname = fontname;
        this.fontstyle = fontstyle;
        this.inlinefontsize = inlinefontsize;
        this.displayfontsize = displayfontsize;
        
        windaube = System.getProperty("os.name").startsWith("Windows");
        
        for (int i = 0; i < maxfontsize; i++)
            fonts[i] = new Font(fontname, fontstyle, i);
        
        goodFonts = new Vector<Font>();
        String symbolFontName = "Symbol";
        if (!windaube) {
            // check if Symbol has all the glyphs we use
            Font testfont = new Font("Symbol", fontstyle, displayfontsize);
            boolean testok = true;
            for (final char element : Symbol_chars)
                if (!testfont.canDisplay(element)) {
                    testok = false;
                    break;
                }
            if (!testok) {
                LOG.error("MathBase(String, int, int, int) - Warning: Symbol does not have all the necessary glyphs");
                final Font[] allfonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
                Font perfectfont = null;
                Font bestfont = null;
                int bestscore = 1000;
                int score;
                for (int i=0; i<allfonts.length && perfectfont == null; i++) {
                    testfont = allfonts[i];
                    score = 0;
                    for (final char element : Symbol_chars)
                        if (!testfont.canDisplay(element))
                            score++;
                    if (score == 0)
                        perfectfont = testfont;
                    if (score < bestscore) {
                        bestfont = testfont;
                        bestscore = score;
                    }
                }
                if (perfectfont == null) {
                    LOG
                            .error(
                                    "MathBase(String, int, int, int) - Error: no font on this system has all the necessary glyphs");
                    symbolFontName = bestfont.getName();
                } else
                    symbolFontName = perfectfont.getName();
                LOG.error("MathBase(String, int, int, int) - Using a different font: " + symbolFontName);
            }
        }
        goodFonts.add(new Font(symbolFontName, Font.PLAIN, displayfontsize));
        
        for (int i = 0; i < maxfontsize; i++)
            symbolFonts[i] = new Font(symbolFontName, fontstyle, i);
        
        if (gcalc != null)
            setupFontMetrics(gcalc);

        /*System.out.println("fontname="+fonts[10].getFontName()+" name="+fonts[10].getName()+
                                                                                                                                                                                                                                                                                                                                        " family="+fonts[10].getFamily());

        String[] names = Toolkit.getDefaultToolkit().getFontList();//getAvailableFontFamilyNames()
        System.out.print("Available fonts: ");
        for(int i=0; i<names.length; i++)
                                                                        System.out.print(names[i]+" ");
        System.out.println();*/

        /*Font[] fontlist= GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
        System.out.println("Available fonts: ");
        for(int i=0; i<fontlist.length; i++)
                                                                        System.out.println("fontname="+fontlist[i].getFontName()+" name="+fontlist[i].getName()+
                                                                                                                                                                                                                                                                                                                                        " family="+fontlist[i].getFamily());
        System.out.println();*/
    }
    
    private void setupFontMetrics(final Graphics gcalc) {
        fontmetrics = new FontMetrics[maxfontsize];
        for (int i = 0; i < maxfontsize; i++)
            fontmetrics[i] = gcalc.getFontMetrics(fonts[i]);
        
        symbolFontmetrics = new FontMetrics[maxfontsize];
        for (int i = 0; i < maxfontsize; i++)
            symbolFontmetrics[i] = gcalc.getFontMetrics(symbolFonts[i]);
    }
    
    /**
     * Set the root element of a math tree
     *
     * @param element Root element of a math tree
     */
    public void setRootElement(final MathRootElement element)
    {
        if (element == null)
            return;
        
        rootElement = element;
        
        rootElement.setMathBase(this);
        
        if (element.getMode() == MathRootElement.DISPLAY)
            rootElement.setFontSize(displayfontsize);
        else
            rootElement.setFontSize(inlinefontsize);
        
        rootElement.setDebug(isDebug());
    }

    /**
     * Enables, or disables the debug mode
     *
     * @param debug Debug mode
     */
    public void setDebug(final boolean debug)
    {
        this.debug = debug;
    if (rootElement!=null)
      rootElement.setDebug(debug);
    }

    /**
     * Indicates, if the debug mode is enabled
     *
     * @return True, if the debug mode is enabled
     */
    public boolean isDebug()
    {
        return debug;
    }

    /**
     * Sets the default font size, which used for the root element
     *
     * @param fontsize Font size
     */
    public void setDefaultFontSize(final int fontsize)
    {
        if (fontsize >= minfontsize || fontsize < maxfontsize)
            this.inlinefontsize = fontsize;
    }

    /**
     * Get the default font size
     *
     * @return Default font size
     */
    public int getDefaultInlineFontSize()
    {
        return inlinefontsize;
    }

    /**
     * Sets the default font size for non inline equations
     *
     * @param fontsize Default font size
     */
    public void setDefaultDisplayFontSize(final int fontsize)
    {
        if (fontsize >= minfontsize || fontsize < maxfontsize)
            this.displayfontsize = fontsize;
    }

    /**
     * Get the default font size for non inline equations
     *
     * @return Default display font size
     */
    public int getDefaultDisplayFontSize()
    {
        return displayfontsize;
    }

    /**
     * Get a font specified by the font size
     *
     * @param fontsize Font size
     *
     * @return Font
     */
    public Font getFont(final int fontsize)
    {
        if (fontsize < minfontsize)
            return fonts[minfontsize];
        if (fontsize > maxfontsize)
            return fonts[maxfontsize - 1];
        return fonts[fontsize];
    }

    /**
     * Get a symbol font specified by the font size
     *
     * @param fontsize Font Size
     *
     * @return Font
     */
    public Font getSymbolFont(final int fontsize)
    {
        if (fontsize < minfontsize)
            return symbolFonts[minfontsize];
        if (fontsize > maxfontsize)
            return symbolFonts[maxfontsize - 1];
        return symbolFonts[fontsize];
    }
    
    public String findFont(final String s, final Font defaultFont) {
        if (goodFonts != null) {
            for (final Font f : goodFonts) {
                final int upto = f.canDisplayUpTo(s);
                if (upto == -1 || upto == s.length())
                    return f.getName();
            }
        }
        final Font[] allfonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
        for (final Font f : allfonts) {
            final int upto = f.canDisplayUpTo(s);
            if (upto == -1 || upto == s.length()) {
                goodFonts.add(f);
                return f.getName();
            }
        }
        return defaultFont.getName();
    }
    
    /**
     * Get the font metrics specified by the font size
     *
     * @param fontsize Font size
     *
     * @return Font metrics
     */
    public FontMetrics getFontMetrics(final int fontsize)
    {
        if (fontsize < minfontsize)
            return fontmetrics[minfontsize];
        if (fontsize > maxfontsize)
            return fontmetrics[maxfontsize - 1];
        return fontmetrics[fontsize];
    }

    /**
     * Get the font metrics of the symbol font specified by the font size
     *
     * @param fontsize Font size
     *
     * @return Font metrics
     */
    public FontMetrics getSymbolFontMetrics(final int fontsize)
    {
        if (fontsize < minfontsize)
            return symbolFontmetrics[minfontsize];
        if (fontsize > maxfontsize)
            return symbolFontmetrics[maxfontsize - 1];
        return symbolFontmetrics[fontsize];
    }

    /**
     * Get a glyph vector of the symbol font
     *
     * @param g2d The graphic context presented by a Graphics2D
     * @param fontsize Font size
     * @param index Index of the glyph vector
     *
     * @return Glyph vector
     */
    public GlyphVector getSymbolGlyphVector(final Graphics2D g2d, int fontsize, final char c)
    {
        if (windaube) {
            int code = 0;
            for (int i=0; i<Symbol_chars.length; i++)
                if (Symbol_chars[i] == c) {
                    code = MS_Symbol_codes[i];
                    break;
                }
            if (code == 0) {
                if (fontsize < minfontsize)
                    return symbolFonts[minfontsize].createGlyphVector(g2d.getFontRenderContext(),
                                    new char[]{ c });
                if (fontsize > maxfontsize)
                    return symbolFonts[maxfontsize - 1].createGlyphVector(g2d.getFontRenderContext(),
                                    new char[]{ c });
                return symbolFonts[fontsize].createGlyphVector(g2d.getFontRenderContext(),
                                new char[]{ c });
            }
            if (fontsize < minfontsize)
                return symbolFonts[minfontsize].createGlyphVector(g2d.getFontRenderContext(),
                                new int[]{ code });
            if (fontsize > maxfontsize)
                return symbolFonts[maxfontsize - 1].createGlyphVector(g2d.getFontRenderContext(),
                                new int[]{ code });
            return symbolFonts[fontsize].createGlyphVector(g2d.getFontRenderContext(),
                            new int[]{ code });
        }
        if (fontsize < minfontsize)
            fontsize = minfontsize;
        else if (fontsize > maxfontsize)
            fontsize = maxfontsize - 1;
        Font font = symbolFonts[fontsize];
        if (!font.canDisplay(c)) {
            final String fontname = findFont(Character.toString(c), font);
            if (!fontname.equals(font.getName()))
                font = new Font(fontname, Font.PLAIN, fontsize);
        }
        return font.createGlyphVector(g2d.getFontRenderContext(), new char[]{ c });
    }

    /**
     * Paints this component and all of its elements
     *
     * @param g The graphics context to use for painting
     */
    public void paint(final Graphics g) {
        if (fontmetrics == null)
            setupFontMetrics(g);
        
        final Graphics2D g2d = (Graphics2D)g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
            RenderingHints.VALUE_TEXT_ANTIALIAS_ON); // looks much better !
        // note: RenderingHints on MacOS X with Java 1.3.1 works only with hardware acceleration off !
        // com.apple.hwaccel = false
        
        if (rootElement != null)
            rootElement.paint(g);
    }

    /**
     * Return the current width of this component
     *
     * @return Width
     */
    public int getWidth()
    {
        if (rootElement != null)
          return rootElement.getWidth();
        return 0;
    }

    /**
     * Return the current height of this component
     *
     * @return Height
     */
    public int getHeight()
    {
        if (rootElement != null)
            return rootElement.getHeight();
        return 0;
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.