001 /*
002 * Copyright 2002 - 2007 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: MathBase.java 571 2007-12-12 14:11:46Z maxberger $ */
018
019 package net.sourceforge.jeuclid;
020
021 import java.awt.Graphics2D;
022 import java.awt.RenderingHints;
023 import java.util.HashMap;
024 import java.util.Map;
025
026 import net.sourceforge.jeuclid.elements.generic.DocumentElement;
027
028 /**
029 * Keeps a MathML Tree and its Rendering attributes.
030 * <p>
031 * This is the main class for MathML handling. It stores a MathML Tree and its
032 * rendering attributes.
033 * <p>
034 * To obtain a renderable MathML tree, create an instance of this class, and
035 * fill its tree with the help of {@link DOMBuilder}.
036 *
037 * @author Max Berger
038 * @author <a href="mailto:stephan@vern.chem.tu-berlin.de">Stephan Michels</a>
039 * @author <a href="mailto:sielaff@vern.chem.tu-berlin.de">Marco Sielaff</a>
040 * @version $Revision: 571 $
041 */
042 public class MathBase {
043 /**
044 * Logger for this class. unused.
045 */
046 // private static final Log LOGGER = LogFactory.getLog(MathBase.class);
047 /**
048 * Inline mathematical expression.
049 */
050 public static final int INLINE = 0;
051
052 /**
053 * Non inline mathematical expression.
054 */
055 public static final int DISPLAY = 1;
056
057 /**
058 * Default font size.
059 */
060 public static final float DEFAULT_FONTSIZE = 12.0f;
061
062 /** Constant for string "true". */
063 public static final String TRUE = Boolean.TRUE.toString();
064
065 /** Constant for string "false". */
066 public static final String FALSE = Boolean.FALSE.toString();
067
068 /** Constant for zero-value (0). */
069 public static final String VALUE_ZERO = "0";
070
071 /**
072 * Reference to the root element of mathelements tree.
073 */
074 private DocumentElement rootElement;
075
076 private final Map<ParameterKey, String> renderParams;
077
078 /**
079 * Default constructor.
080 * <p>
081 * Allocates a new MathBase with the given rendering parameters. You may
082 * use {@link #getDefaultParameters()} to obtain a default set of
083 * rendering parameters.
084 * <p>
085 * The root element will initially be empty. You may use
086 * {@link DOMBuilder} or {@link SAXBuilder} to fill it.
087 *
088 * @param params
089 * Rendering parameters.
090 * @see ParameterKey
091 * @see #getDefaultParameters()
092 */
093 public MathBase(final Map<ParameterKey, String> params) {
094 this.renderParams = MathBase.getDefaultParameters();
095 if (params != null) {
096 this.renderParams.putAll(params);
097 }
098 this.rootElement = new DocumentElement(this);
099 }
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 }