Move setting of some layout bits to RenderElement
[WebKit-https.git] / Source / WebCore / rendering / mathml / RenderMathMLScripts.cpp
1 /*
2  * Copyright (C) 2010 Alex Milowski (alex@milowski.com). All rights reserved.
3  * Copyright (C) 2013 The MathJax Consortium.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28
29 #if ENABLE(MATHML)
30
31 #include "RenderMathMLScripts.h"
32
33 #include "MathMLNames.h"
34
35 namespace WebCore {
36     
37 using namespace MathMLNames;
38
39 // RenderMathMLScripts implements various MathML elements drawing scripts attached to a base. For valid MathML elements, the structure of the render tree should be:
40 //
41 // - msub, msup, msubsup: BaseWrapper SubSupPairWrapper
42 // - mmultiscripts: BaseWrapper SubSupPairWrapper* (mprescripts SubSupPairWrapper*)*
43 //
44 // where BaseWrapper and SubSupPairWrapper do not contain any <mprescripts/> children. In addition, BaseWrapper must have one child and SubSupPairWrapper must have either one child (msub, msup) or two children (msubsup, mmultiscripts).
45 //
46 // In order to accept invalid markup and to handle the script elements consistently and uniformly, we will use a more general structure that encompasses both valid and invalid elements:
47 //
48 // BaseWrapper SubSupPairWrapper* (mprescripts SubSupPairWrapper*)*
49 //
50 // where BaseWrapper can now be empty and SubSupPairWrapper can now have one or two elements.
51 //
52
53 static bool isPrescript(RenderObject* renderObject)
54 {
55     ASSERT(renderObject);
56     return renderObject->node() && renderObject->node()->hasTagName(MathMLNames::mprescriptsTag);
57 }
58
59 RenderMathMLScripts::RenderMathMLScripts(Element* element)
60     : RenderMathMLBlock(element)
61     , m_baseWrapper(0)
62 {
63     // Determine what kind of sub/sup expression we have by element name
64     if (element->hasLocalName(MathMLNames::msubTag))
65         m_kind = Sub;
66     else if (element->hasLocalName(MathMLNames::msupTag))
67         m_kind = Super;
68     else if (element->hasLocalName(MathMLNames::msubsupTag))
69         m_kind = SubSup;
70     else {
71         ASSERT(element->hasLocalName(MathMLNames::mmultiscriptsTag));
72         m_kind = Multiscripts;
73     }
74 }
75
76 RenderBoxModelObject* RenderMathMLScripts::base() const
77 {
78     if (!m_baseWrapper)
79         return 0;
80     RenderObject* base = m_baseWrapper->firstChild();
81     if (!base || !base->isBoxModelObject())
82         return 0;
83     return toRenderBoxModelObject(base);
84 }
85
86 void RenderMathMLScripts::fixAnonymousStyleForSubSupPair(RenderObject* subSupPair, bool isPostScript)
87 {
88     ASSERT(subSupPair && subSupPair->style()->refCount() == 1);
89     RenderStyle* scriptsStyle = subSupPair->style();
90
91     // subSup pairs are drawn in column from bottom (subscript) to top (superscript).
92     scriptsStyle->setFlexDirection(FlowColumnReverse);
93
94     // The MathML specification does not specify horizontal alignment of
95     // scripts. We align the bottom (respectively top) edge of the subscript
96     // (respectively superscript) with the bottom (respectively top) edge of
97     // the flex container. Note that for valid <msub> and <msup> elements, the
98     // subSupPair should actually have only one script.
99     scriptsStyle->setJustifyContent(m_kind == Sub ? JustifyFlexStart : m_kind == Super ? JustifyFlexEnd : JustifySpaceBetween);
100
101     // The MathML specification does not specify vertical alignment of scripts.
102     // Let's right align prescripts and left align postscripts.
103     // See http://lists.w3.org/Archives/Public/www-math/2012Aug/0006.html
104     scriptsStyle->setAlignItems(isPostScript ? AlignFlexStart : AlignFlexEnd);
105
106     // We set the order property so that the prescripts are drawn before the base.
107     scriptsStyle->setOrder(isPostScript ? 0 : -1);
108
109     // We set this wrapper's font-size for its line-height.
110     LayoutUnit scriptSize = static_cast<int>(0.75 * style()->fontSize());
111     scriptsStyle->setFontSize(scriptSize);
112 }
113
114 void RenderMathMLScripts::fixAnonymousStyles()
115 {
116     // We set the base wrapper's style so that baseHeight in layout() will be an unstretched height.
117     ASSERT(m_baseWrapper && m_baseWrapper->style()->hasOneRef());
118     m_baseWrapper->style()->setAlignSelf(AlignFlexStart);
119
120     // This sets the style for postscript pairs.
121     RenderObject* subSupPair = m_baseWrapper;
122     for (subSupPair = subSupPair->nextSibling(); subSupPair && !isPrescript(subSupPair); subSupPair = subSupPair->nextSibling())
123         fixAnonymousStyleForSubSupPair(subSupPair, true);
124
125     if (subSupPair && m_kind == Multiscripts) {
126         // This sets the style for prescript pairs.
127         for (subSupPair = subSupPair->nextSibling(); subSupPair && !isPrescript(subSupPair); subSupPair = subSupPair->nextSibling())
128             fixAnonymousStyleForSubSupPair(subSupPair, false);
129     }
130
131     // This resets style for extra subSup pairs.
132     for (; subSupPair; subSupPair = subSupPair->nextSibling()) {
133         if (!isPrescript(subSupPair)) {
134             ASSERT(subSupPair && subSupPair->style()->refCount() == 1);
135             RenderStyle* scriptsStyle = subSupPair->style();
136             scriptsStyle->setFlexDirection(FlowRow);
137             scriptsStyle->setJustifyContent(JustifyFlexStart);
138             scriptsStyle->setAlignItems(AlignCenter);
139             scriptsStyle->setOrder(0);
140             scriptsStyle->setFontSize(style()->fontSize());
141         }
142     }
143 }
144
145 void RenderMathMLScripts::addChildInternal(bool doNotRestructure, RenderObject* child, RenderObject* beforeChild)
146 {
147     if (doNotRestructure) {
148         RenderMathMLBlock::addChild(child, beforeChild);
149         return;
150     }
151
152     if (beforeChild) {
153         // beforeChild may be a grandchild, so we call the addChild function of the corresponding wrapper instead.
154         RenderObject* parent = beforeChild->parent();
155         if (parent != this) {
156             RenderMathMLScriptsWrapper* wrapper = toRenderMathMLScriptsWrapper(parent);
157             wrapper->addChildInternal(false, child, beforeChild);
158             return;
159         }
160     }
161
162     if (beforeChild == m_baseWrapper) {
163         // This is like inserting the child at the beginning of the base wrapper.
164         m_baseWrapper->addChildInternal(false, child, m_baseWrapper->firstChild());
165         return;
166     }
167     
168     if (isPrescript(child)) {
169         // The new child becomes an <mprescripts/> separator.
170         RenderMathMLBlock::addChild(child, beforeChild);
171         return;
172     }
173
174     if (!beforeChild || isPrescript(beforeChild)) {
175         // We are at the end of a sequence of subSup pairs.
176         RenderMathMLBlock* previousSibling = toRenderMathMLBlock(beforeChild ? beforeChild->previousSibling() : lastChild());
177         if (previousSibling && previousSibling->isRenderMathMLScriptsWrapper()) {
178             RenderMathMLScriptsWrapper* wrapper = toRenderMathMLScriptsWrapper(previousSibling);
179             if ((wrapper->m_kind == RenderMathMLScriptsWrapper::Base && wrapper->isEmpty()) || (wrapper->m_kind == RenderMathMLScriptsWrapper::SubSupPair && !wrapper->firstChild()->nextSibling())) {
180                 // The previous sibling is either an empty base or a SubSup pair with a single child so we can insert the new child into that wrapper.
181                 wrapper->addChildInternal(true, child);
182                 return;
183             }
184         }
185         // Otherwise we create a new subSupPair to store the new child.
186         RenderMathMLScriptsWrapper* subSupPair = RenderMathMLScriptsWrapper::createAnonymousWrapper(this, RenderMathMLScriptsWrapper::SubSupPair);
187         subSupPair->addChildInternal(true, child);
188         RenderMathMLBlock::addChild(subSupPair, beforeChild);
189         return;
190     }
191
192     // beforeChild is a subSup pair. This is like inserting the new child at the beginning of the subSup wrapper.
193     RenderMathMLScriptsWrapper* wrapper = toRenderMathMLScriptsWrapper(beforeChild);
194     ASSERT(wrapper->m_kind == RenderMathMLScriptsWrapper::SubSupPair);
195     ASSERT(!(m_baseWrapper->isEmpty() && m_baseWrapper->nextSibling() == beforeChild));
196     wrapper->addChildInternal(false, child, wrapper->firstChild());
197 }
198
199 void RenderMathMLScripts::removeChildInternal(bool doNotRestructure, RenderObject* child)
200 {
201     if (doNotRestructure) {
202         RenderMathMLBlock::removeChild(child);
203         return;
204     }
205
206     ASSERT(isPrescript(child));
207
208     RenderObject* previousSibling = child->previousSibling();
209     RenderObject* nextSibling = child->nextSibling();
210     ASSERT(previousSibling);
211
212     if (nextSibling && !isPrescript(previousSibling) && !isPrescript(nextSibling)) {
213         RenderMathMLScriptsWrapper* previousWrapper = toRenderMathMLScriptsWrapper(previousSibling);
214         RenderMathMLScriptsWrapper* nextWrapper = toRenderMathMLScriptsWrapper(nextSibling);
215         ASSERT(nextWrapper->m_kind == RenderMathMLScriptsWrapper::SubSupPair && !nextWrapper->isEmpty());
216         if ((previousWrapper->m_kind == RenderMathMLScriptsWrapper::Base && previousWrapper->isEmpty()) || (previousWrapper->m_kind == RenderMathMLScriptsWrapper::SubSupPair && !previousWrapper->firstChild()->nextSibling())) {
217             RenderObject* script = nextWrapper->firstChild();
218             nextWrapper->removeChildInternal(false, script);
219             previousWrapper->addChildInternal(true, script);
220         }
221     }
222
223     RenderMathMLBlock::removeChild(child);
224 }
225
226 void RenderMathMLScripts::addChild(RenderObject* child, RenderObject* beforeChild)
227 {
228     if (isEmpty()) {
229         m_baseWrapper = RenderMathMLScriptsWrapper::createAnonymousWrapper(this, RenderMathMLScriptsWrapper::Base);
230         RenderMathMLBlock::addChild(m_baseWrapper);
231     }
232
233     addChildInternal(false, child, beforeChild);
234
235     fixAnonymousStyles();
236 }
237
238 void RenderMathMLScripts::removeChild(RenderObject* child)
239 {
240     if (beingDestroyed() || documentBeingDestroyed()) {
241         // The renderer is being destroyed so we remove the child normally.
242         RenderMathMLBlock::removeChild(child);
243         return;
244     }
245
246     removeChildInternal(false, child);
247     
248     fixAnonymousStyles();
249 }
250
251 void RenderMathMLScripts::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
252 {
253     RenderMathMLBlock::styleDidChange(diff, oldStyle);
254     
255     if (!isEmpty())
256         fixAnonymousStyles();
257 }
258
259 RenderMathMLOperator* RenderMathMLScripts::unembellishedOperator()
260 {
261     RenderBoxModelObject* base = this->base();
262     if (!base || !base->isRenderMathMLBlock())
263         return 0;
264     return toRenderMathMLBlock(base)->unembellishedOperator();
265 }
266
267 void RenderMathMLScripts::layout()
268 {
269     RenderMathMLBlock::layout();
270
271     if (!m_baseWrapper)
272         return;
273     RenderBox* base = m_baseWrapper->firstChildBox();
274     if (!base)
275         return;
276
277     // Our layout rules include: Don't let the superscript go below the "axis" (half x-height above the
278     // baseline), or the subscript above the axis. Also, don't let the superscript's top edge be
279     // below the base's top edge, or the subscript's bottom edge above the base's bottom edge.
280
281     LayoutUnit baseHeight = base->logicalHeight();
282     LayoutUnit baseBaseline = base->firstLineBoxBaseline();
283     if (baseBaseline == -1)
284         baseBaseline = baseHeight;
285     LayoutUnit axis = style()->fontMetrics().xHeight() / 2;
286     int fontSize = style()->fontSize();
287
288     ASSERT(m_baseWrapper->style()->hasOneRef());
289     bool needsSecondLayout = false;
290
291     LayoutUnit topPadding = 0;
292     LayoutUnit bottomPadding = 0;
293
294     Element* scriptElement = element();
295     LayoutUnit superscriptShiftValue = 0;
296     LayoutUnit subscriptShiftValue = 0;
297     if (m_kind == Sub || m_kind == SubSup || m_kind == Multiscripts)
298         parseMathMLLength(scriptElement->fastGetAttribute(MathMLNames::subscriptshiftAttr), subscriptShiftValue, style(), false);
299     if (m_kind == Super || m_kind == SubSup || m_kind == Multiscripts)
300         parseMathMLLength(scriptElement->fastGetAttribute(MathMLNames::superscriptshiftAttr), superscriptShiftValue, style(), false);
301
302     bool isPostScript = true;
303     RenderMathMLBlock* subSupPair = toRenderMathMLBlock(m_baseWrapper->nextSibling());
304     for (; subSupPair; subSupPair = toRenderMathMLBlock(subSupPair->nextSibling())) {
305
306         // We skip the base and <mprescripts/> elements.
307         if (isPrescript(subSupPair)) {
308             if (!isPostScript)
309                 break;
310             isPostScript = false;
311             continue;
312         }
313
314         if (RenderBox* superscript = m_kind == Sub ? 0 : subSupPair->lastChildBox()) {
315             LayoutUnit superscriptHeight = superscript->logicalHeight();
316             LayoutUnit superscriptBaseline = superscript->firstLineBoxBaseline();
317             if (superscriptBaseline == -1)
318                 superscriptBaseline = superscriptHeight;
319             LayoutUnit minBaseline = max<LayoutUnit>(fontSize / 3 + 1 + superscriptBaseline, superscriptHeight + axis + superscriptShiftValue);
320
321             topPadding = max<LayoutUnit>(topPadding, minBaseline - baseBaseline);
322         }
323
324         if (RenderBox* subscript = m_kind == Super ? 0 : subSupPair->firstChildBox()) {
325             LayoutUnit subscriptHeight = subscript->logicalHeight();
326             LayoutUnit subscriptBaseline = subscript->firstLineBoxBaseline();
327             if (subscriptBaseline == -1)
328                 subscriptBaseline = subscriptHeight;
329             LayoutUnit baseExtendUnderBaseline = baseHeight - baseBaseline;
330             LayoutUnit subscriptUnderItsBaseline = subscriptHeight - subscriptBaseline;
331             LayoutUnit minExtendUnderBaseline = max<LayoutUnit>(fontSize / 5 + 1 + subscriptUnderItsBaseline, subscriptHeight + subscriptShiftValue - axis);
332
333             bottomPadding = max<LayoutUnit>(bottomPadding, minExtendUnderBaseline - baseExtendUnderBaseline);
334         }
335     }
336
337     Length newPadding(topPadding, Fixed);
338     if (newPadding != m_baseWrapper->style()->paddingTop()) {
339         m_baseWrapper->style()->setPaddingTop(newPadding);
340         needsSecondLayout = true;
341     }
342
343     newPadding = Length(bottomPadding, Fixed);
344     if (newPadding != m_baseWrapper->style()->paddingBottom()) {
345         m_baseWrapper->style()->setPaddingBottom(newPadding);
346         needsSecondLayout = true;
347     }
348
349     if (!needsSecondLayout)
350         return;
351
352     setNeedsLayout(MarkOnlyThis);
353     m_baseWrapper->setChildNeedsLayout(MarkOnlyThis);
354
355     RenderMathMLBlock::layout();
356 }
357
358 int RenderMathMLScripts::firstLineBoxBaseline() const
359 {
360     if (m_baseWrapper) {
361         LayoutUnit baseline = m_baseWrapper->firstLineBoxBaseline();
362         if (baseline != -1)
363             return baseline;
364     }
365     return RenderMathMLBlock::firstLineBoxBaseline();
366 }
367
368 RenderMathMLScriptsWrapper* RenderMathMLScriptsWrapper::createAnonymousWrapper(RenderMathMLScripts* renderObject, WrapperType type)
369 {
370     RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(renderObject->style(), FLEX);
371     RenderMathMLScriptsWrapper* newBlock = new (renderObject->renderArena()) RenderMathMLScriptsWrapper(0, type);
372     newBlock->setDocumentForAnonymous(renderObject->document());
373     newBlock->setStyle(newStyle.release());
374     return newBlock;
375 }
376
377 void RenderMathMLScriptsWrapper::addChildInternal(bool doNotRestructure, RenderObject* child, RenderObject* beforeChild)
378 {
379     if (doNotRestructure) {
380         RenderMathMLBlock::addChild(child, beforeChild);
381         return;
382     }
383
384     RenderMathMLScripts* parentNode = toRenderMathMLScripts(parent());
385
386     if (m_kind == Base) {
387         RenderObject* sibling = nextSibling();
388
389         if (!isEmpty() && !beforeChild) {
390             // This is like inserting the child after the base wrapper.
391             parentNode->addChildInternal(false, sibling);
392             return;
393         }
394
395         // The old base (if any) becomes a script ; the new child becomes either the base or an <mprescripts> separator.
396         RenderObject* oldBase = firstChild();
397         if (oldBase)
398             RenderMathMLBlock::removeChild(oldBase);
399         if (isPrescript(child))
400             parentNode->addChildInternal(true, child, sibling);
401         else
402             RenderMathMLBlock::addChild(child);
403         if (oldBase)
404             parentNode->addChildInternal(false, oldBase, sibling);
405         return;
406     }
407
408     if (isPrescript(child)) {
409         // We insert an <mprescripts> element.
410         if (!beforeChild)
411             parentNode->addChildInternal(true, child, nextSibling());
412         else if (beforeChild == firstChild())
413             parentNode->addChildInternal(true, child, this);
414         else {
415             // We insert the <mprescripts> in the middle of a subSup pair so we must split that pair.
416             RenderObject* sibling = nextSibling();
417             parentNode->removeChildInternal(true, this);
418             parentNode->addChildInternal(true, child, sibling);
419
420             RenderObject* script = firstChild();
421             RenderMathMLBlock::removeChild(script);
422             parentNode->addChildInternal(false, script, child);
423
424             script = beforeChild;
425             RenderMathMLBlock::removeChild(script);
426             parentNode->addChildInternal(false, script, sibling);
427             destroy();
428         }
429         return;
430     }
431
432     // We first move to the last subSup pair in the curent sequence of scripts.
433     RenderMathMLScriptsWrapper* subSupPair = this;
434     while (subSupPair->nextSibling() && !isPrescript(subSupPair->nextSibling()))
435         subSupPair = toRenderMathMLScriptsWrapper(subSupPair->nextSibling());
436     if (subSupPair->firstChild()->nextSibling()) {
437         // The last pair has two children so we need to create a new pair to leave room for the new child.
438         RenderMathMLScriptsWrapper* newPair = createAnonymousWrapper(parentNode, RenderMathMLScriptsWrapper::SubSupPair);
439         parentNode->addChildInternal(true, newPair, subSupPair->nextSibling());
440         subSupPair = newPair;
441     }
442
443     // We shift the successors in the current sequence of scripts.
444     for (RenderObject* previousSibling = subSupPair->previousSibling(); subSupPair != this; previousSibling = previousSibling->previousSibling()) {
445         RenderMathMLScriptsWrapper* previousSubSupPair = toRenderMathMLScriptsWrapper(previousSibling);
446         RenderObject* script = previousSubSupPair->lastChild();
447         previousSubSupPair->removeChildInternal(true, script);
448         subSupPair->addChildInternal(true, script, subSupPair->firstChild());
449         subSupPair = toRenderMathMLScriptsWrapper(previousSibling);
450     }
451
452     // This subSup pair now contain one element which is either beforeChild or the script that was before. Hence we can insert the new child before of after that element.
453     RenderMathMLBlock::addChild(child, firstChild() == beforeChild ? beforeChild : 0);
454 }
455
456 void RenderMathMLScriptsWrapper::addChild(RenderObject* child, RenderObject* beforeChild)
457 {
458     RenderMathMLScripts* parentNode = toRenderMathMLScripts(parent());
459
460     addChildInternal(false, child, beforeChild);
461
462     parentNode->fixAnonymousStyles();
463 }
464
465 void RenderMathMLScriptsWrapper::removeChildInternal(bool doNotRestructure, RenderObject* child)
466 {
467     if (doNotRestructure) {
468         RenderMathMLBlock::removeChild(child);
469         return;
470     }
471
472     RenderMathMLScripts* parentNode = toRenderMathMLScripts(parent());
473
474     if (m_kind == Base) {
475         // We remove the child from the base wrapper.
476         RenderObject* sibling = nextSibling();
477         RenderMathMLBlock::removeChild(child);
478         if (sibling && !isPrescript(sibling)) {
479             // If there are postscripts, the first one becomes the base.
480             RenderMathMLScriptsWrapper* wrapper = toRenderMathMLScriptsWrapper(sibling);
481             RenderObject* script = wrapper->firstChild();
482             wrapper->removeChildInternal(false, script);
483             RenderMathMLBlock::addChild(script);
484         }
485         return;
486     }
487
488     // We remove the child and shift the successors in the current sequence of scripts.
489     RenderMathMLBlock::removeChild(child);
490     RenderMathMLScriptsWrapper* subSupPair = this;
491     for (RenderObject* nextSibling = subSupPair->nextSibling(); nextSibling && !isPrescript(nextSibling); nextSibling = nextSibling->nextSibling()) {
492         RenderMathMLScriptsWrapper* nextSubSupPair = toRenderMathMLScriptsWrapper(nextSibling);
493         RenderObject* script = nextSubSupPair->firstChild();
494         nextSubSupPair->removeChildInternal(true, script);
495         subSupPair->addChildInternal(true, script);
496         subSupPair = toRenderMathMLScriptsWrapper(nextSibling);
497     }
498
499     // We remove the last subSup pair if it became empty.
500     if (subSupPair->isEmpty()) {
501         parentNode->removeChildInternal(true, subSupPair);
502         subSupPair->destroy();
503     }
504 }
505
506 void RenderMathMLScriptsWrapper::removeChild(RenderObject* child)
507 {
508     if (beingDestroyed() || documentBeingDestroyed()) {
509         // The renderer is being destroyed so we remove the child normally.
510         RenderMathMLBlock::removeChild(child);
511         return;
512     }
513
514     RenderMathMLScripts* parentNode = toRenderMathMLScripts(parent());
515
516     removeChildInternal(false, child);
517
518     parentNode->fixAnonymousStyles();
519 }
520
521 }    
522
523 #endif // ENABLE(MATHML)