View Javadoc

1   /*
2    * Copyright 2002 - 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: MathBase.java 571 2007-12-12 14:11:46Z maxberger $ */
18  
19  package net.sourceforge.jeuclid;
20  
21  import java.awt.Graphics2D;
22  import java.awt.RenderingHints;
23  import java.util.HashMap;
24  import java.util.Map;
25  
26  import net.sourceforge.jeuclid.elements.generic.DocumentElement;
27  
28  /**
29   * Keeps a MathML Tree and its Rendering attributes.
30   * <p>
31   * This is the main class for MathML handling. It stores a MathML Tree and its
32   * rendering attributes.
33   * <p>
34   * To obtain a renderable MathML tree, create an instance of this class, and
35   * fill its tree with the help of {@link DOMBuilder}.
36   * 
37   * @author Max Berger
38   * @author <a href="mailto:stephan@vern.chem.tu-berlin.de">Stephan Michels</a>
39   * @author <a href="mailto:sielaff@vern.chem.tu-berlin.de">Marco Sielaff</a>
40   * @version $Revision: 571 $
41   */
42  public class MathBase {
43      /**
44       * Logger for this class. unused.
45       */
46      // private static final Log LOGGER = LogFactory.getLog(MathBase.class);
47      /**
48       * Inline mathematical expression.
49       */
50      public static final int INLINE = 0;
51  
52      /**
53       * Non inline mathematical expression.
54       */
55      public static final int DISPLAY = 1;
56  
57      /**
58       * Default font size.
59       */
60      public static final float DEFAULT_FONTSIZE = 12.0f;
61  
62      /** Constant for string "true". */
63      public static final String TRUE = Boolean.TRUE.toString();
64  
65      /** Constant for string "false". */
66      public static final String FALSE = Boolean.FALSE.toString();
67  
68      /** Constant for zero-value (0). */
69      public static final String VALUE_ZERO = "0";
70  
71      /**
72       * Reference to the root element of mathelements tree.
73       */
74      private DocumentElement rootElement;
75  
76      private final Map<ParameterKey, String> renderParams;
77  
78      /**
79       * Default constructor.
80       * <p>
81       * Allocates a new MathBase with the given rendering parameters. You may
82       * use {@link #getDefaultParameters()} to obtain a default set of
83       * rendering parameters.
84       * <p>
85       * The root element will initially be empty. You may use
86       * {@link DOMBuilder} or {@link SAXBuilder} to fill it.
87       * 
88       * @param params
89       *            Rendering parameters.
90       * @see ParameterKey
91       * @see #getDefaultParameters()
92       */
93      public MathBase(final Map<ParameterKey, String> params) {
94          this.renderParams = MathBase.getDefaultParameters();
95          if (params != null) {
96              this.renderParams.putAll(params);
97          }
98          this.rootElement = new DocumentElement(this);
99      }
100 
101     /**
102      * Gets the height of the ascender.
103      * 
104      * @return Ascent height
105      * @param g
106      *            Graphics2D context to use.
107      */
108     public float getAscender(final Graphics2D g) {
109         return (float) Math.ceil(this.rootElement.getAscentHeight(g));
110     }
111 
112     /**
113      * Returns the height of the descender.
114      * 
115      * @return Descent height
116      * @param g
117      *            Graphics2D context to use.
118      */
119     public float getDescender(final Graphics2D g) {
120         return (float) Math.ceil(this.rootElement.getDescentHeight(g));
121     }
122 
123     /**
124      * Set the root element of a math tree.
125      * 
126      * @param element
127      *            Root element of a math tree
128      */
129     public void setRootElement(final DocumentElement element) {
130         if (element == null) {
131             return;
132         }
133         this.rootElement = element;
134         this.rootElement.setMathBase(this);
135     }
136 
137     /**
138      * @return the Document element associated with this mathbase.
139      */
140     public DocumentElement getRootElement() {
141         return this.rootElement;
142     }
143 
144     /**
145      * Enables, or disables the debug mode.
146      * 
147      * @param debug
148      *            Debug mode flag.
149      */
150     public void setDebug(final boolean debug) {
151         this.renderParams
152                 .put(ParameterKey.DebugMode, Boolean.toString(debug));
153     }
154 
155     /**
156      * Indicates, weither the debug mode is enabled.
157      * 
158      * @return True, if the debug mode is enabled
159      */
160     public boolean isDebug() {
161         return Boolean.parseBoolean(this.renderParams
162                 .get(ParameterKey.DebugMode));
163     }
164 
165     /**
166      * Paints this component and all of its elements.
167      * 
168      * @param g
169      *            The graphics context to use for painting.
170      * @param x
171      *            x-offset
172      * @param y
173      *            y-offset
174      */
175     public void paint(final Graphics2D g, final float x, final float y) {
176         if (this.rootElement != null) {
177             final RenderingHints hints = g.getRenderingHints();
178             if (Boolean.parseBoolean(this.renderParams
179                     .get(ParameterKey.AntiAlias))) {
180                 hints.add(new RenderingHints(RenderingHints.KEY_ANTIALIASING,
181                         RenderingHints.VALUE_ANTIALIAS_ON));
182             }
183             hints.add(new RenderingHints(RenderingHints.KEY_STROKE_CONTROL,
184                     RenderingHints.VALUE_STROKE_NORMALIZE));
185             hints.add(new RenderingHints(RenderingHints.KEY_RENDERING,
186                     RenderingHints.VALUE_RENDER_QUALITY));
187             g.setRenderingHints(hints);
188             this.rootElement.paint(g, x, y
189                     + (float) Math.ceil(this.rootElement.getAscentHeight(g)));
190         }
191     }
192 
193     /**
194      * Paints the componet and all of its elements into the top-right corner.
195      * 
196      * @param g
197      *            The graphics context to use for painting.
198      * @see #paint(Graphics2D, float, float)
199      */
200     public void paint(final Graphics2D g) {
201         this.paint(g, 0, 0);
202     }
203 
204     /**
205      * Return the current width of this component.
206      * 
207      * @return Width
208      * @param g
209      *            Graphics2D context to use.
210      */
211     public float getWidth(final Graphics2D g) {
212         final float realWidth;
213         if (this.rootElement != null) {
214             realWidth = this.rootElement.getWidth(g);
215         } else {
216             realWidth = 0f;
217         }
218         return Math.max(1.0f, realWidth);
219     }
220 
221     /**
222      * Return the current height of this component.
223      * 
224      * @return Height
225      * @param g
226      *            Graphics2D context to use.
227      */
228     public float getHeight(final Graphics2D g) {
229         final float realHeight;
230         if (this.rootElement != null) {
231             realHeight = (float) (Math.ceil(this.rootElement
232                     .getAscentHeight(g)) + Math.ceil(this.rootElement
233                     .getDescentHeight(g)));
234         } else {
235             realHeight = 0f;
236         }
237         return Math.max(1.0f, realHeight);
238     }
239 
240     /**
241      * @return the fontSize
242      */
243     public float getFontSize() {
244         return Float.parseFloat(this.getParams().get(ParameterKey.FontSize));
245     }
246 
247     /**
248      * Retrieves the current set of parametes.
249      * <p>
250      * Please note that it is not recommended to change any of these
251      * parameters, but rather to use {@link #setParam(ParameterKey, String)}
252      * instead.
253      * 
254      * @return The current set of rendering parameters.
255      */
256     public Map<ParameterKey, String> getParams() {
257         return this.renderParams;
258     }
259 
260     /**
261      * Sets a rendering parameter.
262      * 
263      * @param key
264      *            Key of the rendering parameter.
265      * @param value
266      *            new value.
267      */
268     public void setParam(final ParameterKey key, final String value) {
269         this.renderParams.put(key, value);
270         this.rootElement.fireChangeForSubTree();
271     }
272 
273     /**
274      * Provides a reasonable set of default parameters.
275      * 
276      * @return a set that can be used in {@link #MathBase(Map)}
277      */
278     public static Map<ParameterKey, String> getDefaultParameters() {
279         final Map<ParameterKey, String> params = new HashMap<ParameterKey, String>();
280         params.put(ParameterKey.FontSize, Float
281                 .toString(MathBase.DEFAULT_FONTSIZE));
282         params.put(ParameterKey.DebugMode, MathBase.FALSE);
283         params.put(ParameterKey.OutFileType, "image/png");
284         params.put(ParameterKey.AntiAlias, MathBase.TRUE);
285         params.put(ParameterKey.ForegroundColor, "black");
286         params.put(ParameterKey.BackgroundColor, "transparent");
287 
288         // CHECKSTYLE:OFF
289         final String symbolCatchFonts = "OpenSymbol," + "Standard Symbols L,"
290                 + "Symbol," + "Webdings," + "Wingdings," + "Wingdings 2,"
291                 + "Wingdings 3," + "Arial Unicode MS," + "DejaVu Sans"
292                 + "Cambria Math" + "STIXGeneral";
293         params.put(ParameterKey.FontsSanserif, "Verdana," + "Helvetica,"
294                 + "Arial," + "Arial Unicode MS," + "Lucida Sans Unicode,"
295                 + "Lucida Sans," + "Lucida Grande," + "DejaVu Sans,"
296                 + "Bitstream Vera Sans," + "Luxi Sans," + "FreeSans,"
297                 + "sansserif," + symbolCatchFonts);
298         params.put(ParameterKey.FontsSerif, "Constantina," + "Times,"
299                 + "Times New Roman," + "Lucida Bright," + "DejaVu Serif,"
300                 + "Bitstream Vera Serif," + "Luxi Serif," + "FreeSerif,"
301                 + "serif," + symbolCatchFonts);
302         params.put(ParameterKey.FontsMonospaced, "Andale Mono," + "Courier,"
303                 + "Courier Mono," + "Courier New,"
304                 + "Lucida Sans Typewriter," + "DejaVu Sans Mono,"
305                 + "Bitstream Vera Sans Mono," + "Luxi Mono," + "FreeMono,"
306                 + "monospaced," + symbolCatchFonts);
307         params.put(ParameterKey.FontsScript, "Savoye LET,"
308                 + "Brush Script MT," + "Zapfino," + "Apple Chancery,"
309                 + "Edwardian Script ITC," + "Lucida Handwriting,"
310                 + "Monotype Corsiva," + "Santa Fe LET," + symbolCatchFonts);
311         params
312                 .put(ParameterKey.FontsFraktur, "FetteFraktur,"
313                         + "Fette Fraktur," + "Euclid Fraktur,"
314                         + "Lucida Blackletter," + "Blackmoor LET,"
315                         + symbolCatchFonts);
316         params.put(ParameterKey.FontsDoublestruck, "Caslon Open Face,"
317                 + "Caslon Openface," + "Cloister Open Face,"
318                 + "Academy Engraved LET," + "Colonna MT,"
319                 + "Imprint MT Shadow," + symbolCatchFonts);
320         // CHECKSTYLE:ON
321         return params;
322     }
323 }