Coverage Report - net.sourceforge.jeuclid.elements.AbstractJEuclidElement
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractJEuclidElement
81%
141/172
75%
51/68
1,765
 
 1  
 /*
 2  
  * Copyright 2002 - 2009 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: AbstractJEuclidElement.java,v 62d8defc665e 2009/09/25 14:22:59 max $ */
 18  
 
 19  
 package net.sourceforge.jeuclid.elements;
 20  
 
 21  
 import java.awt.Color;
 22  
 import java.awt.Font;
 23  
 import java.awt.FontMetrics;
 24  
 import java.awt.Graphics2D;
 25  
 import java.util.HashMap;
 26  
 import java.util.HashSet;
 27  
 import java.util.List;
 28  
 import java.util.Map;
 29  
 import java.util.Set;
 30  
 
 31  
 import net.sourceforge.jeuclid.LayoutContext;
 32  
 import net.sourceforge.jeuclid.context.StyleAttributeLayoutContext;
 33  
 import net.sourceforge.jeuclid.elements.presentation.token.Mo;
 34  
 import net.sourceforge.jeuclid.elements.presentation.token.Mtext;
 35  
 import net.sourceforge.jeuclid.elements.support.ElementListSupport;
 36  
 import net.sourceforge.jeuclid.elements.support.GraphicsSupport;
 37  
 import net.sourceforge.jeuclid.elements.support.attributes.AttributesHelper;
 38  
 import net.sourceforge.jeuclid.elements.support.attributes.MathVariant;
 39  
 import net.sourceforge.jeuclid.elements.support.text.TextContent;
 40  
 import net.sourceforge.jeuclid.layout.LayoutInfo;
 41  
 import net.sourceforge.jeuclid.layout.LayoutStage;
 42  
 import net.sourceforge.jeuclid.layout.LayoutView;
 43  
 import net.sourceforge.jeuclid.layout.LayoutableNode;
 44  
 
 45  
 import org.apache.batik.dom.AbstractDocument;
 46  
 import org.apache.batik.dom.GenericElementNS;
 47  
 import org.apache.batik.dom.events.DOMMutationEvent;
 48  
 import org.w3c.dom.Attr;
 49  
 import org.w3c.dom.Node;
 50  
 import org.w3c.dom.events.Event;
 51  
 import org.w3c.dom.mathml.MathMLElement;
 52  
 import org.w3c.dom.mathml.MathMLMathElement;
 53  
 import org.w3c.dom.mathml.MathMLNodeList;
 54  
 
 55  
 /**
 56  
  * The basic class for all math elements. Every element class inherits from this
 57  
  * class. It provides basic functionality for drawing.
 58  
  * 
 59  
  * @version $Revision: 62d8defc665e $
 60  
  */
 61  
 // CHECKSTYLE:OFF
 62  
 public abstract class AbstractJEuclidElement extends
 63  
 // CHECKSTYLE:ON
 64  
         GenericElementNS implements JEuclidElement {
 65  
 
 66  
     /** Constant for mathvariant attribute. */
 67  
     public static final String ATTR_MATHVARIANT = "mathvariant";
 68  
 
 69  
     /** Constant for mathcolor attribute. */
 70  
     public static final String ATTR_MATHCOLOR = "mathcolor";
 71  
 
 72  
     /** Constant for mathsize attribute. */
 73  
     public static final String ATTR_MATHSIZE = "mathsize";
 74  
 
 75  
     /** Constant for fontfamily attribute. */
 76  
     public static final String ATTR_DEPRECATED_FONTFAMILY = "fontfamily";
 77  
 
 78  
     /** Constant for fontstyle attribute. */
 79  
     public static final String ATTR_DEPRECATED_FONTSTYLE = "fontstyle";
 80  
 
 81  
     /** Constant for fontweight attribute. */
 82  
     public static final String ATTR_DEPRECATED_FONTWEIGHT = "fontweight";
 83  
 
 84  
     /** Constant for fontsize attribute. */
 85  
     public static final String ATTR_DEPRECATED_FONTSIZE = "fontsize";
 86  
 
 87  
     /** Constant for color attribute. */
 88  
     public static final String ATTR_DEPRECATED_COLOR = "color";
 89  
 
 90  
     /** Constant for background attribute. */
 91  
     public static final String ATTR_DEPRECATED_BACKGROUND = "background";
 92  
 
 93  
     /** Constant for class attribute. */
 94  
     public static final String ATTR_CLASS = "class";
 95  
 
 96  
     /** Constant for style attribute. */
 97  
     public static final String ATTR_STYLE = "style";
 98  
 
 99  
     /** Constant for id attribute. */
 100  
     public static final String ATTR_ID = "id";
 101  
 
 102  
     /** Constant for href attribute. */
 103  
     public static final String ATTR_HREF = "xlink:href";
 104  
 
 105  
     /** Constant for xref attribute. */
 106  
     public static final String ATTR_XREF = "xref";
 107  
 
 108  
     /** The mathbackground attribute. */
 109  
     public static final String ATTR_MATHBACKGROUND = "mathbackground";
 110  
 
 111  
     /**
 112  
      * largest value for all trivial spaces (= spaces that can be ignored /
 113  
      * shortened).
 114  
      */
 115  
     public static final int TRIVIAL_SPACE_MAX = 0x20;
 116  
 
 117  
     /**
 118  
      * The URI from MathML.
 119  
      */
 120  
     public static final String URI = "http://www.w3.org/1998/Math/MathML";
 121  
 
 122  
     private static final float MIDDLE_SHIFT = 0.38f;
 123  
 
 124  
     // /**
 125  
     // * Logger for this class
 126  
     // */
 127  
     // private static final Log LOGGER = LogFactory
 128  
     // .getLog(AbstractJEuclidElement.class);
 129  
 
 130  209
     private static final Set<String> DEPRECATED_ATTRIBUTES = new HashSet<String>();
 131  
 
 132  
     /**
 133  
      * Reference to the element acting as parent if there is no parent.
 134  
      */
 135  
     private JEuclidElement fakeParent;
 136  
 
 137  232112
     private final Map<String, String> defaultMathAttributes = new HashMap<String, String>();
 138  
 
 139  
     /**
 140  
      * Default constructor. Sets MathML Namespace.
 141  
      * 
 142  
      * @param qname
 143  
      *            Qualified name.
 144  
      * @param odoc
 145  
      *            Owner Document.
 146  
      */
 147  
     public AbstractJEuclidElement(final String qname,
 148  
             final AbstractDocument odoc) {
 149  228431
         super(AbstractJEuclidElement.URI, qname, odoc);
 150  228431
     }
 151  
 
 152  
     /**
 153  
      * Constructor to explicitly set the namespace.
 154  
      * 
 155  
      * @param nsUri
 156  
      *            Namespace URI.
 157  
      * @param qname
 158  
      *            Qualified name.
 159  
      * @param odoc
 160  
      *            Owner Document.
 161  
      */
 162  
     public AbstractJEuclidElement(final String nsUri, final String qname,
 163  
             final AbstractDocument odoc) {
 164  3681
         super(nsUri, qname, odoc);
 165  3681
     }
 166  
 
 167  
     /**
 168  
      * Gets the used font. Everything regardes font, processed by MathBase
 169  
      * object.
 170  
      * 
 171  
      * @param context
 172  
      *            LayoutContext to use.
 173  
      * @return Font Font object.
 174  
      */
 175  
     public Font getFont(final LayoutContext context) {
 176  11286
         final String content = this.getText();
 177  
         final char aChar;
 178  11286
         if (content.length() > 0) {
 179  11286
             aChar = content.charAt(0);
 180  
         } else {
 181  0
             aChar = 'A';
 182  
         }
 183  11286
         return this.getMathvariantAsVariant().createFont(
 184  
                 GraphicsSupport.getFontsizeInPoint(context), aChar,
 185  
                 this.applyLocalAttributesToContext(context), true);
 186  
 
 187  
     }
 188  
 
 189  
     /** {@inheritDoc} */
 190  
     public MathVariant getMathvariantAsVariant() {
 191  
         // TODO: Support deprecated variant names
 192  61245
         String setMv = this.getMathAttribute(
 193  
                 AbstractJEuclidElement.ATTR_MATHVARIANT, false);
 194  
 
 195  61245
         JEuclidElement parent = this.getParent();
 196  328146
         while ((setMv == null) && (parent != null)) {
 197  
             // element is not set, try to inherit
 198  266901
             if (parent instanceof AbstractJEuclidElement) {
 199  266901
                 setMv = ((AbstractJEuclidElement) parent).getMathAttribute(
 200  
                         AbstractJEuclidElement.ATTR_MATHVARIANT, false);
 201  
             }
 202  266901
             parent = parent.getParent();
 203  
         }
 204  61245
         if (setMv == null) {
 205  61245
             setMv = this.defaultMathAttributes
 206  
                     .get(AbstractJEuclidElement.ATTR_MATHVARIANT);
 207  
         }
 208  
         MathVariant variant;
 209  61245
         if (setMv == null) {
 210  43263
             variant = MathVariant.NORMAL;
 211  
         } else {
 212  17982
             variant = MathVariant.stringToMathVariant(setMv);
 213  17982
             if (variant == null) {
 214  0
                 variant = MathVariant.NORMAL;
 215  
             }
 216  
         }
 217  61245
         return variant;
 218  
     }
 219  
 
 220  
     // /**
 221  
     // * Setting size of child of the element.
 222  
     // *
 223  
     // * @param child
 224  
     // * Child element
 225  
     // * @param childpos
 226  
     // * Position of the child element
 227  
     // */
 228  
     //
 229  
     // private void setChildSize(AbstractMathElement child, int childpos) {
 230  
     //
 231  
     // float childSize = (float) Math.pow(getScriptSizeMultiplier(), child
 232  
     // .getAbsoluteScriptLevel());
 233  
     //
 234  
     // child.multipleFont(m_font, (float) Math.pow(getScriptSizeMultiplier(),
 235  
     // child.getAbsoluteScriptLevel()));
 236  
     // System.out.println(child.toString() + " "
 237  
     // + child.getAbsoluteScriptLevel() + " "
 238  
     // + getScriptSizeMultiplier() + " " + childSize);
 239  
     //
 240  
     // child.setScriptSizeMultiplier(getScriptSizeMultiplier());
 241  
     //
 242  
     // if (this instanceof MathMultiScripts) {
 243  
     // if (childpos > 0) {
 244  
     // child.multipleFont(m_font, getScriptSizeMultiplier());
 245  
     // child.setDisplayStyle(false);
 246  
     // child.setInheritSisplayStyle(false);
 247  
     // }
 248  
     // } else if (this instanceof MathOver) {
 249  
     // if (childpos == 1) {
 250  
     // if (((getMathElement(0) instanceof MathOperator) && ((MathOperator)
 251  
     // getMathElement(0))
 252  
     // .getMoveableLimits())
 253  
     // || (!((MathOver) this).getAccent())) {
 254  
     // child.multipleFont(m_font, getScriptSizeMultiplier());
 255  
     // child.setDisplayStyle(false);
 256  
     // child.setInheritSisplayStyle(false);
 257  
     // }
 258  
     // }
 259  
     // } else if (this instanceof MathUnder) {
 260  
     // if (childpos == 1) {
 261  
     // if (((getMathElement(0) instanceof MathOperator) && ((MathOperator)
 262  
     // getMathElement(0))
 263  
     // .getMoveableLimits())
 264  
     // || (!((MathUnder) this).getAccentUnder())) {
 265  
     // child.multipleFont(m_font, getScriptSizeMultiplier());
 266  
     // child.setDisplayStyle(false);
 267  
     // child.setInheritSisplayStyle(false);
 268  
     // }
 269  
     // }
 270  
     // } else if (this instanceof MathUnderOver) {
 271  
     // if (childpos > 0) {
 272  
     // if (((getMathElement(0) instanceof MathOperator) && ((MathOperator)
 273  
     // getMathElement(0))
 274  
     // .getMoveableLimits())
 275  
     // || ((childpos == 1) && (!((MathUnderOver) this)
 276  
     // .getAccentUnder()))
 277  
     // || ((childpos == 2) && (!((MathUnderOver) this)
 278  
     // .getAccent()))) {
 279  
     // child.multipleFont(m_font, getScriptSizeMultiplier());
 280  
     // child.setDisplayStyle(false);
 281  
     // child.setInheritSisplayStyle(false);
 282  
     // }
 283  
     // }
 284  
     // } else if (this instanceof MathRoot) {
 285  
     // if (childpos == 1) {
 286  
     // child.multipleFont(m_font, (float) Math.pow(
 287  
     // getScriptSizeMultiplier(), 2));
 288  
     // child.setDisplayStyle(false);
 289  
     // child.setInheritSisplayStyle(false);
 290  
     // }
 291  
     // } else if (this instanceof MathSub) {
 292  
     // if (childpos == 1) {
 293  
     // child.multipleFont(m_font, getScriptSizeMultiplier());
 294  
     // child.setDisplayStyle(false);
 295  
     // child.setInheritSisplayStyle(false);
 296  
     // }
 297  
     // } else if (this instanceof MathSup) {
 298  
     // if (childpos == 1) {
 299  
     // child.multipleFont(m_font, getScriptSizeMultiplier());
 300  
     // child.setDisplayStyle(false);
 301  
     // child.setInheritSisplayStyle(false);
 302  
     // }
 303  
     // } else if (this instanceof MathSubSup) {
 304  
     // if (childpos > 0) {
 305  
     // child.multipleFont(m_font, getScriptSizeMultiplier());
 306  
     // child.setDisplayStyle(false);
 307  
     // child.setInheritSisplayStyle(false);
 308  
     // }
 309  
     // } else if (this instanceof MathStyle) {
 310  
     // // child.multipleFont(m_font, (float) Math.pow(
 311  
     // // getScriptSizeMultiplier(), ((MathStyle) this)
 312  
     // // .getScriptlevel()));
 313  
     // } else {
 314  
     // child.setFont(m_font);
 315  
     // }
 316  
     // }
 317  
 
 318  
     /**
 319  
      * Add a math element as a child.
 320  
      * 
 321  
      * @param child
 322  
      *            Math element object.
 323  
      */
 324  
     public final void addMathElement(final MathMLElement child) {
 325  5434
         if (child != null) {
 326  5434
             this.appendChild(child);
 327  
         }
 328  5434
     }
 329  
 
 330  
     /**
 331  
      * Gets a child from this element.
 332  
      * <p>
 333  
      * Please note, that unlike the MathML DOM model functions this function
 334  
      * uses a 0-based index.
 335  
      * 
 336  
      * @param index
 337  
      *            Index of the child (0-based).
 338  
      * @return The child MathElement object.
 339  
      */
 340  
     protected JEuclidElement getMathElement(final int index) {
 341  68343
         final List<Node> childList = ElementListSupport
 342  
                 .createListOfChildren(this);
 343  68343
         int count = 0;
 344  68343
         for (final Node n : childList) {
 345  180576
             if (n instanceof JEuclidElement) {
 346  121220
                 if (count == index) {
 347  67716
                     return (JEuclidElement) n;
 348  
                 }
 349  53504
                 count++;
 350  
             }
 351  
         }
 352  2299
         for (; count < index; count++) {
 353  836
             this.appendChild(this.ownerDocument.createElement(Mtext.ELEMENT));
 354  
         }
 355  627
         final JEuclidElement last = (JEuclidElement) this.ownerDocument
 356  
                 .createElement(Mtext.ELEMENT);
 357  627
         this.appendChild(last);
 358  627
         return last;
 359  
     }
 360  
 
 361  
     /**
 362  
      * Sets a specific child to the newElement, creating other subelements as
 363  
      * necessary.
 364  
      * 
 365  
      * @param index
 366  
      *            the index to set (0=the first child)
 367  
      * @param newElement
 368  
      *            new element to be set as child.
 369  
      */
 370  
     protected void setMathElement(final int index,
 371  
             final MathMLElement newElement) {
 372  1045
         final org.w3c.dom.NodeList childList = this.getChildNodes();
 373  1463
         while (childList.getLength() < index) {
 374  418
             this.appendChild(this.getOwnerDocument().createTextNode(""));
 375  
         }
 376  1045
         if (childList.getLength() == index) {
 377  418
             this.addMathElement(newElement);
 378  
         } else {
 379  627
             this.replaceChild(newElement, childList.item(index));
 380  
         }
 381  1045
     }
 382  
 
 383  
     /** {@inheritDoc} */
 384  
     public int getIndexOfMathElement(final JEuclidElement element) {
 385  2558399
         final org.w3c.dom.NodeList childList = this.getChildNodes();
 386  7921160
         for (int i = 0; i < childList.getLength(); i++) {
 387  7921160
             if (childList.item(i).equals(element)) {
 388  2558399
                 return i;
 389  
             }
 390  
         }
 391  0
         return -1;
 392  
     }
 393  
 
 394  
     /** {@inheritDoc} */
 395  
     public int getMathElementCount() {
 396  7117039
         final List<Node> childList = ElementListSupport
 397  
                 .createListOfChildren(this);
 398  7117039
         int count = 0;
 399  7117039
         for (final Node n : childList) {
 400  39503688
             if (n instanceof JEuclidElement) {
 401  19204145
                 count++;
 402  
             }
 403  
         }
 404  7117039
         return count;
 405  
     }
 406  
 
 407  
     /**
 408  
      * Returns the text content of this element.
 409  
      * 
 410  
      * @return Text content.
 411  
      */
 412  
     public String getText() {
 413  22088907
         return TextContent.getText(this);
 414  
     }
 415  
 
 416  
     /** {@inheritDoc} */
 417  
     public void setFakeParent(final JEuclidElement parent) {
 418  627
         this.fakeParent = parent;
 419  627
     }
 420  
 
 421  
     private JEuclidNode getParentAsJEuclidNode() {
 422  8035081
         final Node parentNode = this.getParentNode();
 423  
         final JEuclidNode theParent;
 424  8035081
         if (parentNode instanceof JEuclidNode) {
 425  7876659
             theParent = (JEuclidNode) parentNode;
 426  
         } else {
 427  158422
             theParent = null;
 428  
         }
 429  8035081
         if (theParent == null) {
 430  158422
             return this.fakeParent;
 431  
         } else {
 432  7876659
             return theParent;
 433  
         }
 434  
 
 435  
     }
 436  
 
 437  
     /** {@inheritDoc} */
 438  
     public JEuclidElement getParent() {
 439  8035081
         final JEuclidNode parentNode = this.getParentAsJEuclidNode();
 440  8035081
         if (parentNode instanceof JEuclidElement) {
 441  7669532
             return (JEuclidElement) parentNode;
 442  
         } else {
 443  365549
             return null;
 444  
         }
 445  
     }
 446  
 
 447  
     /**
 448  
      * Sets value of mathvariant attribute (style of the element).
 449  
      * 
 450  
      * @param mathvariant
 451  
      *            Value of mathvariant.
 452  
      */
 453  
     public void setMathvariant(final String mathvariant) {
 454  0
         this.setAttribute(AbstractJEuclidElement.ATTR_MATHVARIANT, mathvariant);
 455  0
     }
 456  
 
 457  
     /**
 458  
      * Returns value of mathvariant attribute (style of the element).
 459  
      * 
 460  
      * @return Value of mathvariant.
 461  
      */
 462  
     public String getMathvariant() {
 463  33
         return this.getMathAttribute(AbstractJEuclidElement.ATTR_MATHVARIANT);
 464  
     }
 465  
 
 466  
     /**
 467  
      * Gets the font metrics of the used font.
 468  
      * 
 469  
      * @return Font metrics.
 470  
      * @param context
 471  
      *            LayoutContext to use.
 472  
      * @param g
 473  
      *            Graphics2D context to use.
 474  
      */
 475  
     public FontMetrics getFontMetrics(final Graphics2D g,
 476  
             final LayoutContext context) {
 477  11286
         return g.getFontMetrics(this.getFont(context));
 478  
     }
 479  
 
 480  
     /**
 481  
      * Sets value of math color attribute.
 482  
      * 
 483  
      * @param mathcolor
 484  
      *            Color object.
 485  
      */
 486  
     public void setMathcolor(final String mathcolor) {
 487  0
         this.setAttribute(AbstractJEuclidElement.ATTR_MATHCOLOR, mathcolor);
 488  0
     }
 489  
 
 490  
     /**
 491  
      * Returns value of mathcolor attribute.
 492  
      * 
 493  
      * @return Color as string.
 494  
      */
 495  
     public String getMathcolor() {
 496  
         String color;
 497  926585
         color = this.getMathAttribute(AbstractJEuclidElement.ATTR_MATHCOLOR);
 498  926585
         if (color == null) {
 499  926585
             color = this
 500  
                     .getMathAttribute(AbstractJEuclidElement.ATTR_DEPRECATED_COLOR);
 501  
         }
 502  926585
         return color;
 503  
     }
 504  
 
 505  
     /**
 506  
      * Retrieve the mathsize attribute.
 507  
      * 
 508  
      * @return the mathsize attribute.
 509  
      */
 510  
     public String getMathsize() {
 511  
         String size;
 512  926585
         size = this.getMathAttribute(AbstractJEuclidElement.ATTR_MATHSIZE);
 513  926585
         if (size == null) {
 514  926585
             size = this
 515  
                     .getMathAttribute(AbstractJEuclidElement.ATTR_DEPRECATED_FONTSIZE);
 516  
         }
 517  926585
         return size;
 518  
 
 519  
     }
 520  
 
 521  
     /**
 522  
      * Sets mathsize to a new value.
 523  
      * 
 524  
      * @param mathsize
 525  
      *            value of mathsize.
 526  
      */
 527  
     public void setMathsize(final String mathsize) {
 528  0
         this.setAttribute(AbstractJEuclidElement.ATTR_MATHSIZE, mathsize);
 529  0
     }
 530  
 
 531  
     /**
 532  
      * Sets default values for math attributes. Default values are returned
 533  
      * through getMathAttribute, but not stored in the actual DOM tree. This is
 534  
      * necessary to support proper serialization.
 535  
      * 
 536  
      * @param key
 537  
      *            the attribute to set.
 538  
      * @param value
 539  
      *            value of the attribute.
 540  
      */
 541  
     protected void setDefaultMathAttribute(final String key, final String value) {
 542  27778476
         this.defaultMathAttributes.put(key, value);
 543  27778476
     }
 544  
 
 545  
     /**
 546  
      * retrieve an attribute from the MathML or default name space, returning
 547  
      * the default value if the attribute is not set.
 548  
      * 
 549  
      * @param attrName
 550  
      *            the name of the attribute
 551  
      * @return attribute value or null if not set.
 552  
      * @see #getMathAttribute(String, boolean)
 553  
      */
 554  
     protected String getMathAttribute(final String attrName) {
 555  29066078
         return this.getMathAttribute(attrName, true);
 556  
     }
 557  
 
 558  
     /**
 559  
      * retrieve an attribute from the MathML or default name space.
 560  
      * 
 561  
      * @param attrName
 562  
      *            the name of the attribute
 563  
      * @param useDefault
 564  
      *            is true, the default value is used if the attribute is not
 565  
      *            set.
 566  
      * @return attribute value or null if not set.
 567  
      * @see #getMathAttribute(String)
 568  
      */
 569  
     protected String getMathAttribute(final String attrName,
 570  
             final boolean useDefault) {
 571  
         final String attrValue;
 572  29404256
         Attr attr = this.getAttributeNodeNS(AbstractJEuclidElement.URI,
 573  
                 attrName);
 574  29404256
         if (attr == null) {
 575  29404256
             attr = this.getAttributeNode(attrName);
 576  
         }
 577  29404256
         if (attr == null) {
 578  29369980
             if (useDefault) {
 579  29031802
                 attrValue = this.getDefaultMathAttribute(attrName);
 580  
             } else {
 581  338178
                 attrValue = null;
 582  
             }
 583  
         } else {
 584  34276
             attrValue = attr.getValue().trim();
 585  
         }
 586  29404256
         return attrValue;
 587  
     }
 588  
 
 589  
     /**
 590  
      * Retrieves the previously stored default value for this attribute.
 591  
      * 
 592  
      * @param attrName
 593  
      *            name of the Attribute
 594  
      * @return value set by {@link #setDefaultMathAttribute(String, String)} or
 595  
      *         null if not set.
 596  
      */
 597  
     private String getDefaultMathAttribute(final String attrName) {
 598  29031802
         return this.defaultMathAttributes.get(attrName);
 599  
     }
 600  
 
 601  
     /**
 602  
      * Returns value of mathbackground attribute.
 603  
      * 
 604  
      * @return Color as string.
 605  
      */
 606  
     public String getMathbackground() {
 607  
         String color;
 608  78182
         color = this
 609  
                 .getMathAttribute(AbstractJEuclidElement.ATTR_MATHBACKGROUND);
 610  78182
         if (color == null) {
 611  78182
             color = this
 612  
                     .getMathAttribute(AbstractJEuclidElement.ATTR_DEPRECATED_BACKGROUND);
 613  
         }
 614  78182
         return color;
 615  
     }
 616  
 
 617  
     /**
 618  
      * Sets the value of the machbackground attribute.
 619  
      * 
 620  
      * @param mathbackground
 621  
      *            a string to be used as background color.
 622  
      */
 623  
     public void setMathbackground(final String mathbackground) {
 624  0
         this.setAttribute(AbstractJEuclidElement.ATTR_MATHBACKGROUND,
 625  
                 mathbackground);
 626  0
     }
 627  
 
 628  
     /**
 629  
      * Returns the distance of the baseline and the middleline.
 630  
      * 
 631  
      * @return Distance baseline - middleline.
 632  
      * @param context
 633  
      *            Layout Context to use
 634  
      * @param g
 635  
      *            Graphics2D context to use.
 636  
      */
 637  
     public float getMiddleShift(final Graphics2D g, final LayoutContext context) {
 638  11286
         return this.getFontMetrics(g, context).getAscent()
 639  
                 * AbstractJEuclidElement.MIDDLE_SHIFT;
 640  
     }
 641  
 
 642  
     /** {@inheritDoc} */
 643  
     public String getClassName() {
 644  0
         return this.getAttribute(AbstractJEuclidElement.ATTR_CLASS);
 645  
     }
 646  
 
 647  
     /** {@inheritDoc} */
 648  
     public void setClassName(final String className) {
 649  0
         this.setAttribute(AbstractJEuclidElement.ATTR_CLASS, className);
 650  0
     }
 651  
 
 652  
     /** {@inheritDoc} */
 653  
     public String getMathElementStyle() {
 654  0
         return this.getAttribute(AbstractJEuclidElement.ATTR_STYLE);
 655  
     }
 656  
 
 657  
     /** {@inheritDoc} */
 658  
     public void setMathElementStyle(final String mathElementStyle) {
 659  0
         this.setAttribute(AbstractJEuclidElement.ATTR_STYLE, mathElementStyle);
 660  0
     }
 661  
 
 662  
     /** {@inheritDoc} */
 663  
     @Override
 664  
     public String getId() {
 665  209
         return this.getAttribute(AbstractJEuclidElement.ATTR_ID);
 666  
     }
 667  
 
 668  
     /** {@inheritDoc} */
 669  
     public void setId(final String id) {
 670  0
         this.setAttribute(AbstractJEuclidElement.ATTR_ID, id);
 671  0
     }
 672  
 
 673  
     /** {@inheritDoc} */
 674  
     public String getXref() {
 675  0
         return this.getAttribute(AbstractJEuclidElement.ATTR_XREF);
 676  
     }
 677  
 
 678  
     /** {@inheritDoc} */
 679  
     public void setXref(final String xref) {
 680  0
         this.setAttribute(AbstractJEuclidElement.ATTR_XREF, xref);
 681  0
     }
 682  
 
 683  
     /** {@inheritDoc} */
 684  
     public String getHref() {
 685  0
         return this.getAttribute(AbstractJEuclidElement.ATTR_HREF);
 686  
     }
 687  
 
 688  
     /** {@inheritDoc} */
 689  
     public void setHref(final String href) {
 690  0
         this.setAttribute(AbstractJEuclidElement.ATTR_HREF, href);
 691  0
     }
 692  
 
 693  
     /** {@inheritDoc} */
 694  
     public MathMLMathElement getOwnerMathElement() {
 695  418
         JEuclidElement node = this.getParent();
 696  418
         while (node != null) {
 697  418
             if (node instanceof MathMLMathElement) {
 698  418
                 return (MathMLMathElement) node;
 699  
             }
 700  0
             node = node.getParent();
 701  
         }
 702  0
         return null;
 703  
     }
 704  
 
 705  
     /** {@inheritDoc} */
 706  
     public boolean hasChildPrescripts(final JEuclidElement child) {
 707  15257
         return false;
 708  
     }
 709  
 
 710  
     /** {@inheritDoc} */
 711  
     public boolean hasChildPostscripts(final JEuclidElement child,
 712  
             final LayoutContext context) {
 713  12331
         return false;
 714  
     }
 715  
 
 716  
     /**
 717  
      * Returns the children as a MathML NodeList.
 718  
      * 
 719  
      * @return a list of children
 720  
      */
 721  
     public MathMLNodeList getContents() {
 722  0
         return (MathMLNodeList) this.getChildNodes();
 723  
     }
 724  
 
 725  
     /** {@inheritDoc} */
 726  
     public LayoutContext getChildLayoutContext(final int childNum,
 727  
             final LayoutContext context) {
 728  65417
         return this.applyLocalAttributesToContext(context);
 729  
     }
 730  
 
 731  
     /**
 732  
      * Retrieve the LayoutContext valid for the current node.
 733  
      * 
 734  
      * @param context
 735  
      *            external context.
 736  
      * @return the current layout context.
 737  
      */
 738  
     public LayoutContext applyLocalAttributesToContext(
 739  
             final LayoutContext context) {
 740  
         // TODO: Theoretically this only applies all to presentation token
 741  
         // elements except mspace and mglyph, and on no other elements except
 742  
         // mstyle 3.2.2
 743  926585
         return this.applyStyleAttributes(context);
 744  
     }
 745  
 
 746  
     /**
 747  
      * Apply Style attributed specified in 3.2.2 to a layout context.
 748  
      * 
 749  
      * @param applyTo
 750  
      *            the context to apply to
 751  
      * @return a context which has the style attributes changed accordingly. May
 752  
      *         be the original context if nothing has changed.
 753  
      */
 754  
     private LayoutContext applyStyleAttributes(final LayoutContext applyTo) {
 755  926585
         LayoutContext retVal = applyTo;
 756  
 
 757  
         // Variant is not inherited and therefore not part of the context.
 758  
 
 759  926585
         final String msize = this.getMathsize();
 760  
 
 761  
         final Color foreground;
 762  926585
         final String colorString = this.getMathcolor();
 763  926585
         if (colorString == null) {
 764  926585
             foreground = null;
 765  
         } else {
 766  0
             foreground = AttributesHelper.stringToColor(colorString,
 767  
                     Color.BLACK);
 768  
         }
 769  
 
 770  
         // Background is handled differently and does not need to go into
 771  
         // context.
 772  
 
 773  926585
         if ((msize != null) || (foreground != null)) {
 774  0
             retVal = new StyleAttributeLayoutContext(applyTo, msize, foreground);
 775  
         }
 776  
 
 777  926585
         return retVal;
 778  
     }
 779  
 
 780  
     /** {@inheritDoc} */
 781  
     public List<LayoutableNode> getChildrenToLayout() {
 782  119773
         final List<LayoutableNode> l = ElementListSupport
 783  
                 .createListOfLayoutChildren(this);
 784  119773
         return l;
 785  
     }
 786  
 
 787  
     /** {@inheritDoc} */
 788  
     public List<LayoutableNode> getChildrenToDraw() {
 789  47025
         final List<LayoutableNode> l = ElementListSupport
 790  
                 .createListOfLayoutChildren(this);
 791  47025
         return l;
 792  
     }
 793  
 
 794  
     /**
 795  
      * Layout for elements which are stage independent.
 796  
      * <p>
 797  
      * This function will layout an element which is layed out the same no
 798  
      * matter what stage it is in. This is the case for most elements.
 799  
      * <p>
 800  
      * Notable exceptions are mo and tables.
 801  
      * 
 802  
      * @param view
 803  
      *            View Object for this layout.
 804  
      * @param info
 805  
      *            An info object which will be filled during layout.
 806  
      * @param stage
 807  
      *            current layout stage.
 808  
      * @param context
 809  
      *            current LayoutContext.
 810  
      */
 811  
     protected void layoutStageInvariant(final LayoutView view,
 812  
             final LayoutInfo info, final LayoutStage stage,
 813  
             final LayoutContext context) {
 814  38255
         ElementListSupport.layoutSequential(view, info, this
 815  
                 .getChildrenToLayout(), stage);
 816  38255
     }
 817  
 
 818  
     /** {@inheritDoc} */
 819  
     public void layoutStage1(final LayoutView view, final LayoutInfo info,
 820  
             final LayoutStage childMinStage, final LayoutContext context) {
 821  60835
         this.layoutStageInvariant(view, info, LayoutStage.STAGE1, context);
 822  
 
 823  
         // TODO: This should be done in a better way.
 824  60835
         if (this.getMathbackground() == null) {
 825  60835
             info.setLayoutStage(childMinStage);
 826  
         } else {
 827  0
             info.setLayoutStage(LayoutStage.STAGE1);
 828  
         }
 829  60835
     }
 830  
 
 831  
     /** {@inheritDoc} */
 832  
     public void layoutStage2(final LayoutView view, final LayoutInfo info,
 833  
             final LayoutContext context) {
 834  17347
         this.layoutStageInvariant(view, info, LayoutStage.STAGE2, context);
 835  
 
 836  
         // TODO: put in own function, ensure this is also called from
 837  
         // subclasses.
 838  17347
         final String background = this.getMathbackground();
 839  17347
         final Color backgroundColor = AttributesHelper.stringToColor(
 840  
                 background, null);
 841  17347
         ElementListSupport.addBackground(backgroundColor, info, false);
 842  17347
         info.setLayoutStage(LayoutStage.STAGE2);
 843  17347
     }
 844  
 
 845  
     static {
 846  209
         AbstractJEuclidElement.DEPRECATED_ATTRIBUTES
 847  
                 .add(AbstractJEuclidElement.ATTR_DEPRECATED_COLOR);
 848  209
         AbstractJEuclidElement.DEPRECATED_ATTRIBUTES
 849  
                 .add(AbstractJEuclidElement.ATTR_DEPRECATED_BACKGROUND);
 850  209
         AbstractJEuclidElement.DEPRECATED_ATTRIBUTES
 851  
                 .add(AbstractJEuclidElement.ATTR_DEPRECATED_FONTSIZE);
 852  209
         AbstractJEuclidElement.DEPRECATED_ATTRIBUTES
 853  
                 .add(AbstractJEuclidElement.ATTR_DEPRECATED_FONTWEIGHT);
 854  209
         AbstractJEuclidElement.DEPRECATED_ATTRIBUTES
 855  
                 .add(AbstractJEuclidElement.ATTR_DEPRECATED_FONTSTYLE);
 856  209
         AbstractJEuclidElement.DEPRECATED_ATTRIBUTES
 857  
                 .add(AbstractJEuclidElement.ATTR_DEPRECATED_FONTFAMILY);
 858  
 
 859  209
         AbstractJEuclidElement.DEPRECATED_ATTRIBUTES.add(Mo.ATTR_MOVEABLEWRONG);
 860  209
     }
 861  
 
 862  
     /**
 863  
      * Override this function to get notified whenever the contents of this
 864  
      * element have changed.
 865  
      */
 866  
     protected void changeHook() {
 867  
         // Override me!
 868  4318417
     }
 869  
 
 870  
     /** {@inheritDoc} */
 871  
     @Override
 872  
     public boolean dispatchEvent(final Event evt) {
 873  4522384
         if (evt instanceof DOMMutationEvent) {
 874  1405328
             this.changeHook();
 875  
         }
 876  4522384
         return super.dispatchEvent(evt);
 877  
     }
 878  
 }