001 /* 002 * Copyright 2002 - 2009 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: AbstractJEuclidElement.java,v 62d8defc665e 2009/09/25 14:22:59 max $ */ 018 019 package net.sourceforge.jeuclid.elements; 020 021 import java.awt.Color; 022 import java.awt.Font; 023 import java.awt.FontMetrics; 024 import java.awt.Graphics2D; 025 import java.util.HashMap; 026 import java.util.HashSet; 027 import java.util.List; 028 import java.util.Map; 029 import java.util.Set; 030 031 import net.sourceforge.jeuclid.LayoutContext; 032 import net.sourceforge.jeuclid.context.StyleAttributeLayoutContext; 033 import net.sourceforge.jeuclid.elements.presentation.token.Mo; 034 import net.sourceforge.jeuclid.elements.presentation.token.Mtext; 035 import net.sourceforge.jeuclid.elements.support.ElementListSupport; 036 import net.sourceforge.jeuclid.elements.support.GraphicsSupport; 037 import net.sourceforge.jeuclid.elements.support.attributes.AttributesHelper; 038 import net.sourceforge.jeuclid.elements.support.attributes.MathVariant; 039 import net.sourceforge.jeuclid.elements.support.text.TextContent; 040 import net.sourceforge.jeuclid.layout.LayoutInfo; 041 import net.sourceforge.jeuclid.layout.LayoutStage; 042 import net.sourceforge.jeuclid.layout.LayoutView; 043 import net.sourceforge.jeuclid.layout.LayoutableNode; 044 045 import org.apache.batik.dom.AbstractDocument; 046 import org.apache.batik.dom.GenericElementNS; 047 import org.apache.batik.dom.events.DOMMutationEvent; 048 import org.w3c.dom.Attr; 049 import org.w3c.dom.Node; 050 import org.w3c.dom.events.Event; 051 import org.w3c.dom.mathml.MathMLElement; 052 import org.w3c.dom.mathml.MathMLMathElement; 053 import org.w3c.dom.mathml.MathMLNodeList; 054 055 /** 056 * The basic class for all math elements. Every element class inherits from this 057 * class. It provides basic functionality for drawing. 058 * 059 * @version $Revision: 62d8defc665e $ 060 */ 061 // CHECKSTYLE:OFF 062 public abstract class AbstractJEuclidElement extends 063 // CHECKSTYLE:ON 064 GenericElementNS implements JEuclidElement { 065 066 /** Constant for mathvariant attribute. */ 067 public static final String ATTR_MATHVARIANT = "mathvariant"; 068 069 /** Constant for mathcolor attribute. */ 070 public static final String ATTR_MATHCOLOR = "mathcolor"; 071 072 /** Constant for mathsize attribute. */ 073 public static final String ATTR_MATHSIZE = "mathsize"; 074 075 /** Constant for fontfamily attribute. */ 076 public static final String ATTR_DEPRECATED_FONTFAMILY = "fontfamily"; 077 078 /** Constant for fontstyle attribute. */ 079 public static final String ATTR_DEPRECATED_FONTSTYLE = "fontstyle"; 080 081 /** Constant for fontweight attribute. */ 082 public static final String ATTR_DEPRECATED_FONTWEIGHT = "fontweight"; 083 084 /** Constant for fontsize attribute. */ 085 public static final String ATTR_DEPRECATED_FONTSIZE = "fontsize"; 086 087 /** Constant for color attribute. */ 088 public static final String ATTR_DEPRECATED_COLOR = "color"; 089 090 /** Constant for background attribute. */ 091 public static final String ATTR_DEPRECATED_BACKGROUND = "background"; 092 093 /** Constant for class attribute. */ 094 public static final String ATTR_CLASS = "class"; 095 096 /** Constant for style attribute. */ 097 public static final String ATTR_STYLE = "style"; 098 099 /** 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 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 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 super(AbstractJEuclidElement.URI, qname, odoc); 150 } 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 super(nsUri, qname, odoc); 165 } 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 final String content = this.getText(); 177 final char aChar; 178 if (content.length() > 0) { 179 aChar = content.charAt(0); 180 } else { 181 aChar = 'A'; 182 } 183 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 String setMv = this.getMathAttribute( 193 AbstractJEuclidElement.ATTR_MATHVARIANT, false); 194 195 JEuclidElement parent = this.getParent(); 196 while ((setMv == null) && (parent != null)) { 197 // element is not set, try to inherit 198 if (parent instanceof AbstractJEuclidElement) { 199 setMv = ((AbstractJEuclidElement) parent).getMathAttribute( 200 AbstractJEuclidElement.ATTR_MATHVARIANT, false); 201 } 202 parent = parent.getParent(); 203 } 204 if (setMv == null) { 205 setMv = this.defaultMathAttributes 206 .get(AbstractJEuclidElement.ATTR_MATHVARIANT); 207 } 208 MathVariant variant; 209 if (setMv == null) { 210 variant = MathVariant.NORMAL; 211 } else { 212 variant = MathVariant.stringToMathVariant(setMv); 213 if (variant == null) { 214 variant = MathVariant.NORMAL; 215 } 216 } 217 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 if (child != null) { 326 this.appendChild(child); 327 } 328 } 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 final List<Node> childList = ElementListSupport 342 .createListOfChildren(this); 343 int count = 0; 344 for (final Node n : childList) { 345 if (n instanceof JEuclidElement) { 346 if (count == index) { 347 return (JEuclidElement) n; 348 } 349 count++; 350 } 351 } 352 for (; count < index; count++) { 353 this.appendChild(this.ownerDocument.createElement(Mtext.ELEMENT)); 354 } 355 final JEuclidElement last = (JEuclidElement) this.ownerDocument 356 .createElement(Mtext.ELEMENT); 357 this.appendChild(last); 358 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 final org.w3c.dom.NodeList childList = this.getChildNodes(); 373 while (childList.getLength() < index) { 374 this.appendChild(this.getOwnerDocument().createTextNode("")); 375 } 376 if (childList.getLength() == index) { 377 this.addMathElement(newElement); 378 } else { 379 this.replaceChild(newElement, childList.item(index)); 380 } 381 } 382 383 /** {@inheritDoc} */ 384 public int getIndexOfMathElement(final JEuclidElement element) { 385 final org.w3c.dom.NodeList childList = this.getChildNodes(); 386 for (int i = 0; i < childList.getLength(); i++) { 387 if (childList.item(i).equals(element)) { 388 return i; 389 } 390 } 391 return -1; 392 } 393 394 /** {@inheritDoc} */ 395 public int getMathElementCount() { 396 final List<Node> childList = ElementListSupport 397 .createListOfChildren(this); 398 int count = 0; 399 for (final Node n : childList) { 400 if (n instanceof JEuclidElement) { 401 count++; 402 } 403 } 404 return count; 405 } 406 407 /** 408 * Returns the text content of this element. 409 * 410 * @return Text content. 411 */ 412 public String getText() { 413 return TextContent.getText(this); 414 } 415 416 /** {@inheritDoc} */ 417 public void setFakeParent(final JEuclidElement parent) { 418 this.fakeParent = parent; 419 } 420 421 private JEuclidNode getParentAsJEuclidNode() { 422 final Node parentNode = this.getParentNode(); 423 final JEuclidNode theParent; 424 if (parentNode instanceof JEuclidNode) { 425 theParent = (JEuclidNode) parentNode; 426 } else { 427 theParent = null; 428 } 429 if (theParent == null) { 430 return this.fakeParent; 431 } else { 432 return theParent; 433 } 434 435 } 436 437 /** {@inheritDoc} */ 438 public JEuclidElement getParent() { 439 final JEuclidNode parentNode = this.getParentAsJEuclidNode(); 440 if (parentNode instanceof JEuclidElement) { 441 return (JEuclidElement) parentNode; 442 } else { 443 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 this.setAttribute(AbstractJEuclidElement.ATTR_MATHVARIANT, mathvariant); 455 } 456 457 /** 458 * Returns value of mathvariant attribute (style of the element). 459 * 460 * @return Value of mathvariant. 461 */ 462 public String getMathvariant() { 463 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 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 this.setAttribute(AbstractJEuclidElement.ATTR_MATHCOLOR, mathcolor); 488 } 489 490 /** 491 * Returns value of mathcolor attribute. 492 * 493 * @return Color as string. 494 */ 495 public String getMathcolor() { 496 String color; 497 color = this.getMathAttribute(AbstractJEuclidElement.ATTR_MATHCOLOR); 498 if (color == null) { 499 color = this 500 .getMathAttribute(AbstractJEuclidElement.ATTR_DEPRECATED_COLOR); 501 } 502 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 size = this.getMathAttribute(AbstractJEuclidElement.ATTR_MATHSIZE); 513 if (size == null) { 514 size = this 515 .getMathAttribute(AbstractJEuclidElement.ATTR_DEPRECATED_FONTSIZE); 516 } 517 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 this.setAttribute(AbstractJEuclidElement.ATTR_MATHSIZE, mathsize); 529 } 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 this.defaultMathAttributes.put(key, value); 543 } 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 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 Attr attr = this.getAttributeNodeNS(AbstractJEuclidElement.URI, 573 attrName); 574 if (attr == null) { 575 attr = this.getAttributeNode(attrName); 576 } 577 if (attr == null) { 578 if (useDefault) { 579 attrValue = this.getDefaultMathAttribute(attrName); 580 } else { 581 attrValue = null; 582 } 583 } else { 584 attrValue = attr.getValue().trim(); 585 } 586 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 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 color = this 609 .getMathAttribute(AbstractJEuclidElement.ATTR_MATHBACKGROUND); 610 if (color == null) { 611 color = this 612 .getMathAttribute(AbstractJEuclidElement.ATTR_DEPRECATED_BACKGROUND); 613 } 614 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 this.setAttribute(AbstractJEuclidElement.ATTR_MATHBACKGROUND, 625 mathbackground); 626 } 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 return this.getFontMetrics(g, context).getAscent() 639 * AbstractJEuclidElement.MIDDLE_SHIFT; 640 } 641 642 /** {@inheritDoc} */ 643 public String getClassName() { 644 return this.getAttribute(AbstractJEuclidElement.ATTR_CLASS); 645 } 646 647 /** {@inheritDoc} */ 648 public void setClassName(final String className) { 649 this.setAttribute(AbstractJEuclidElement.ATTR_CLASS, className); 650 } 651 652 /** {@inheritDoc} */ 653 public String getMathElementStyle() { 654 return this.getAttribute(AbstractJEuclidElement.ATTR_STYLE); 655 } 656 657 /** {@inheritDoc} */ 658 public void setMathElementStyle(final String mathElementStyle) { 659 this.setAttribute(AbstractJEuclidElement.ATTR_STYLE, mathElementStyle); 660 } 661 662 /** {@inheritDoc} */ 663 @Override 664 public String getId() { 665 return this.getAttribute(AbstractJEuclidElement.ATTR_ID); 666 } 667 668 /** {@inheritDoc} */ 669 public void setId(final String id) { 670 this.setAttribute(AbstractJEuclidElement.ATTR_ID, id); 671 } 672 673 /** {@inheritDoc} */ 674 public String getXref() { 675 return this.getAttribute(AbstractJEuclidElement.ATTR_XREF); 676 } 677 678 /** {@inheritDoc} */ 679 public void setXref(final String xref) { 680 this.setAttribute(AbstractJEuclidElement.ATTR_XREF, xref); 681 } 682 683 /** {@inheritDoc} */ 684 public String getHref() { 685 return this.getAttribute(AbstractJEuclidElement.ATTR_HREF); 686 } 687 688 /** {@inheritDoc} */ 689 public void setHref(final String href) { 690 this.setAttribute(AbstractJEuclidElement.ATTR_HREF, href); 691 } 692 693 /** {@inheritDoc} */ 694 public MathMLMathElement getOwnerMathElement() { 695 JEuclidElement node = this.getParent(); 696 while (node != null) { 697 if (node instanceof MathMLMathElement) { 698 return (MathMLMathElement) node; 699 } 700 node = node.getParent(); 701 } 702 return null; 703 } 704 705 /** {@inheritDoc} */ 706 public boolean hasChildPrescripts(final JEuclidElement child) { 707 return false; 708 } 709 710 /** {@inheritDoc} */ 711 public boolean hasChildPostscripts(final JEuclidElement child, 712 final LayoutContext context) { 713 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 return (MathMLNodeList) this.getChildNodes(); 723 } 724 725 /** {@inheritDoc} */ 726 public LayoutContext getChildLayoutContext(final int childNum, 727 final LayoutContext context) { 728 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 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 LayoutContext retVal = applyTo; 756 757 // Variant is not inherited and therefore not part of the context. 758 759 final String msize = this.getMathsize(); 760 761 final Color foreground; 762 final String colorString = this.getMathcolor(); 763 if (colorString == null) { 764 foreground = null; 765 } else { 766 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 if ((msize != null) || (foreground != null)) { 774 retVal = new StyleAttributeLayoutContext(applyTo, msize, foreground); 775 } 776 777 return retVal; 778 } 779 780 /** {@inheritDoc} */ 781 public List<LayoutableNode> getChildrenToLayout() { 782 final List<LayoutableNode> l = ElementListSupport 783 .createListOfLayoutChildren(this); 784 return l; 785 } 786 787 /** {@inheritDoc} */ 788 public List<LayoutableNode> getChildrenToDraw() { 789 final List<LayoutableNode> l = ElementListSupport 790 .createListOfLayoutChildren(this); 791 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 ElementListSupport.layoutSequential(view, info, this 815 .getChildrenToLayout(), stage); 816 } 817 818 /** {@inheritDoc} */ 819 public void layoutStage1(final LayoutView view, final LayoutInfo info, 820 final LayoutStage childMinStage, final LayoutContext context) { 821 this.layoutStageInvariant(view, info, LayoutStage.STAGE1, context); 822 823 // TODO: This should be done in a better way. 824 if (this.getMathbackground() == null) { 825 info.setLayoutStage(childMinStage); 826 } else { 827 info.setLayoutStage(LayoutStage.STAGE1); 828 } 829 } 830 831 /** {@inheritDoc} */ 832 public void layoutStage2(final LayoutView view, final LayoutInfo info, 833 final LayoutContext context) { 834 this.layoutStageInvariant(view, info, LayoutStage.STAGE2, context); 835 836 // TODO: put in own function, ensure this is also called from 837 // subclasses. 838 final String background = this.getMathbackground(); 839 final Color backgroundColor = AttributesHelper.stringToColor( 840 background, null); 841 ElementListSupport.addBackground(backgroundColor, info, false); 842 info.setLayoutStage(LayoutStage.STAGE2); 843 } 844 845 static { 846 AbstractJEuclidElement.DEPRECATED_ATTRIBUTES 847 .add(AbstractJEuclidElement.ATTR_DEPRECATED_COLOR); 848 AbstractJEuclidElement.DEPRECATED_ATTRIBUTES 849 .add(AbstractJEuclidElement.ATTR_DEPRECATED_BACKGROUND); 850 AbstractJEuclidElement.DEPRECATED_ATTRIBUTES 851 .add(AbstractJEuclidElement.ATTR_DEPRECATED_FONTSIZE); 852 AbstractJEuclidElement.DEPRECATED_ATTRIBUTES 853 .add(AbstractJEuclidElement.ATTR_DEPRECATED_FONTWEIGHT); 854 AbstractJEuclidElement.DEPRECATED_ATTRIBUTES 855 .add(AbstractJEuclidElement.ATTR_DEPRECATED_FONTSTYLE); 856 AbstractJEuclidElement.DEPRECATED_ATTRIBUTES 857 .add(AbstractJEuclidElement.ATTR_DEPRECATED_FONTFAMILY); 858 859 AbstractJEuclidElement.DEPRECATED_ATTRIBUTES.add(Mo.ATTR_MOVEABLEWRONG); 860 } 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 } 869 870 /** {@inheritDoc} */ 871 @Override 872 public boolean dispatchEvent(final Event evt) { 873 if (evt instanceof DOMMutationEvent) { 874 this.changeHook(); 875 } 876 return super.dispatchEvent(evt); 877 } 878 }