d70b6a9ce2f26fa23c4bfc64160b70b857001538
[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 "MathMLElement.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(const RenderObject& renderObject)
54 {
55     return renderObject.node() && renderObject.node()->hasTagName(MathMLNames::mprescriptsTag);
56 }
57
58 RenderMathMLScripts::RenderMathMLScripts(Element& element, Ref<RenderStyle>&& style)
59     : RenderMathMLBlock(element, WTF::move(style))
60     , m_baseWrapper(0)
61 {
62     // Determine what kind of sub/sup expression we have by element name
63     if (element.hasTagName(MathMLNames::msubTag))
64         m_kind = Sub;
65     else if (element.hasTagName(MathMLNames::msupTag))
66         m_kind = Super;
67     else if (element.hasTagName(MathMLNames::msubsupTag))
68         m_kind = SubSup;
69     else {
70         ASSERT(element.hasTagName(MathMLNames::mmultiscriptsTag));
71         m_kind = Multiscripts;
72     }
73 }
74
75 RenderBoxModelObject* RenderMathMLScripts::base() const
76 {
77     if (!m_baseWrapper)
78         return nullptr;
79     RenderObject* base = m_baseWrapper->firstChild();
80     if (!is<RenderBoxModelObject>(base))
81         return nullptr;
82     return downcast<RenderBoxModelObject>(base);
83 }
84
85 void RenderMathMLScripts::fixAnonymousStyleForSubSupPair(RenderObject* subSupPair, bool isPostScript)
86 {
87     ASSERT(subSupPair && subSupPair->style().refCount() == 1);
88     RenderStyle& scriptsStyle = subSupPair->style();
89
90     // subSup pairs are drawn in column from bottom (subscript) to top (superscript).
91     scriptsStyle.setFlexDirection(FlowColumnReverse);
92
93     // The MathML specification does not specify horizontal alignment of
94     // scripts. We align the bottom (respectively top) edge of the subscript
95     // (respectively superscript) with the bottom (respectively top) edge of
96     // the flex container. Note that for valid <msub> and <msup> elements, the
97     // subSupPair should actually have only one script.
98     scriptsStyle.setJustifyContent(m_kind == Sub ? JustifyFlexStart : m_kind == Super ? JustifyFlexEnd : JustifySpaceBetween);
99
100     // The MathML specification does not specify vertical alignment of scripts.
101     // Let's right align prescripts and left align postscripts.
102     // See http://lists.w3.org/Archives/Public/www-math/2012Aug/0006.html
103     scriptsStyle.setAlignItems(isPostScript ? AlignFlexStart : AlignFlexEnd);
104
105     // We set the order property so that the prescripts are drawn before the base.
106     scriptsStyle.setOrder(isPostScript ? 0 : -1);
107
108     // We set this wrapper's font-size for its line-height.
109     LayoutUnit scriptSize = static_cast<int>(0.75 * style().fontSize());
110     scriptsStyle.setFontSize(scriptSize);
111 }
112
113 void RenderMathMLScripts::fixAnonymousStyles()
114 {
115     // We set the base wrapper's style so that baseHeight in layout() will be an unstretched height.
116     ASSERT(m_baseWrapper && m_baseWrapper->style().hasOneRef());
117     m_baseWrapper->style().setAlignSelf(AlignFlexStart);
118
119     // This sets the style for postscript pairs.
120     RenderObject* subSupPair = m_baseWrapper;
121     for (subSupPair = subSupPair->nextSibling(); subSupPair && !isPrescript(*subSupPair); subSupPair = subSupPair->nextSibling())
122         fixAnonymousStyleForSubSupPair(subSupPair, true);
123
124     if (subSupPair && m_kind == Multiscripts) {
125         // This sets the style for prescript pairs.
126         for (subSupPair = subSupPair->nextSibling(); subSupPair && !isPrescript(*subSupPair); subSupPair = subSupPair->nextSibling())
127             fixAnonymousStyleForSubSupPair(subSupPair, false);
128     }
129
130     // This resets style for extra subSup pairs.
131     for (; subSupPair; subSupPair = subSupPair->nextSibling()) {
132         if (!isPrescript(*subSupPair)) {
133             ASSERT(subSupPair && subSupPair->style().refCount() == 1);
134             RenderStyle& scriptsStyle = subSupPair->style();
135             scriptsStyle.setFlexDirection(FlowRow);
136             scriptsStyle.setJustifyContent(JustifyFlexStart);
137             scriptsStyle.setAlignItems(AlignCenter);
138             scriptsStyle.setOrder(0);
139             scriptsStyle.setFontSize(style().fontSize());
140         }
141     }
142 }
143
144 void RenderMathMLScripts::addChildInternal(bool doNotRestructure, RenderObject* child, RenderObject* beforeChild)
145 {
146     if (doNotRestructure) {
147         RenderMathMLBlock::addChild(child, beforeChild);
148         return;
149     }
150
151     if (beforeChild) {
152         // beforeChild may be a grandchild, so we call the addChild function of the corresponding wrapper instead.
153         RenderObject* parent = beforeChild->parent();
154         if (parent != this) {
155             RenderMathMLBlock& parentBlock = downcast<RenderMathMLBlock>(*parent);
156             if (is<RenderMathMLScriptsWrapper>(parentBlock)) {
157                 RenderMathMLScriptsWrapper& wrapper = downcast<RenderMathMLScriptsWrapper>(parentBlock);
158                 wrapper.addChildInternal(false, child, beforeChild);
159                 return;
160             }
161         }
162     }
163
164     if (beforeChild == m_baseWrapper) {
165         // This is like inserting the child at the beginning of the base wrapper.
166         m_baseWrapper->addChildInternal(false, child, m_baseWrapper->firstChild());
167         return;
168     }
169     
170     if (isPrescript(*child)) {
171         // The new child becomes an <mprescripts/> separator.
172         RenderMathMLBlock::addChild(child, beforeChild);
173         return;
174     }
175
176     if (!beforeChild || isPrescript(*beforeChild)) {
177         // We are at the end of a sequence of subSup pairs.
178         RenderMathMLBlock* previousSibling = downcast<RenderMathMLBlock>(beforeChild ? beforeChild->previousSibling() : lastChild());
179         if (is<RenderMathMLScriptsWrapper>(previousSibling)) {
180             RenderMathMLScriptsWrapper& wrapper = downcast<RenderMathMLScriptsWrapper>(*previousSibling);
181             if ((wrapper.m_kind == RenderMathMLScriptsWrapper::Base && wrapper.isEmpty()) || (wrapper.m_kind == RenderMathMLScriptsWrapper::SubSupPair && !wrapper.firstChild()->nextSibling())) {
182                 // 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.
183                 wrapper.addChildInternal(true, child);
184                 return;
185             }
186         }
187         // Otherwise we create a new subSupPair to store the new child.
188         RenderMathMLScriptsWrapper* subSupPair = RenderMathMLScriptsWrapper::createAnonymousWrapper(this, RenderMathMLScriptsWrapper::SubSupPair);
189         subSupPair->addChildInternal(true, child);
190         RenderMathMLBlock::addChild(subSupPair, beforeChild);
191         return;
192     }
193
194     // beforeChild is a subSup pair. This is like inserting the new child at the beginning of the subSup wrapper.
195     RenderMathMLScriptsWrapper& wrapper = downcast<RenderMathMLScriptsWrapper>(*beforeChild);
196     ASSERT(wrapper.m_kind == RenderMathMLScriptsWrapper::SubSupPair);
197     ASSERT(!(m_baseWrapper->isEmpty() && m_baseWrapper->nextSibling() == beforeChild));
198     wrapper.addChildInternal(false, child, wrapper.firstChild());
199 }
200
201 void RenderMathMLScripts::removeChildInternal(bool doNotRestructure, RenderObject& child)
202 {
203     if (doNotRestructure) {
204         RenderMathMLBlock::removeChild(child);
205         return;
206     }
207
208     ASSERT(isPrescript(child));
209
210     RenderObject* previousSibling = child.previousSibling();
211     RenderObject* nextSibling = child.nextSibling();
212     ASSERT(previousSibling);
213
214     if (nextSibling && !isPrescript(*previousSibling) && !isPrescript(*nextSibling)) {
215         RenderMathMLScriptsWrapper& previousWrapper = downcast<RenderMathMLScriptsWrapper>(*previousSibling);
216         RenderMathMLScriptsWrapper& nextWrapper = downcast<RenderMathMLScriptsWrapper>(*nextSibling);
217         ASSERT(nextWrapper.m_kind == RenderMathMLScriptsWrapper::SubSupPair && !nextWrapper.isEmpty());
218         if ((previousWrapper.m_kind == RenderMathMLScriptsWrapper::Base && previousWrapper.isEmpty()) || (previousWrapper.m_kind == RenderMathMLScriptsWrapper::SubSupPair && !previousWrapper.firstChild()->nextSibling())) {
219             RenderObject* script = nextWrapper.firstChild();
220             nextWrapper.removeChildInternal(false, *script);
221             previousWrapper.addChildInternal(true, script);
222         }
223     }
224
225     RenderMathMLBlock::removeChild(child);
226 }
227
228 void RenderMathMLScripts::addChild(RenderObject* child, RenderObject* beforeChild)
229 {
230     if (isEmpty()) {
231         m_baseWrapper = RenderMathMLScriptsWrapper::createAnonymousWrapper(this, RenderMathMLScriptsWrapper::Base);
232         RenderMathMLBlock::addChild(m_baseWrapper);
233     }
234
235     addChildInternal(false, child, beforeChild);
236
237     fixAnonymousStyles();
238 }
239
240 void RenderMathMLScripts::removeChild(RenderObject& child)
241 {
242     if (beingDestroyed() || documentBeingDestroyed()) {
243         // The renderer is being destroyed so we remove the child normally.
244         RenderMathMLBlock::removeChild(child);
245         return;
246     }
247
248     removeChildInternal(false, child);
249     fixAnonymousStyles();
250 }
251
252 void RenderMathMLScripts::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
253 {
254     RenderMathMLBlock::styleDidChange(diff, oldStyle);
255     
256     if (!isEmpty())
257         fixAnonymousStyles();
258 }
259
260 RenderMathMLOperator* RenderMathMLScripts::unembellishedOperator()
261 {
262     RenderBoxModelObject* base = this->base();
263     if (!is<RenderMathMLBlock>(base))
264         return nullptr;
265     return downcast<RenderMathMLBlock>(*base).unembellishedOperator();
266 }
267
268 void RenderMathMLScripts::layout()
269 {
270     RenderMathMLBlock::layout();
271
272     if (!m_baseWrapper)
273         return;
274     RenderBox* base = m_baseWrapper->firstChildBox();
275     if (!base)
276         return;
277
278     // Our layout rules include: Don't let the superscript go below the "axis" (half x-height above the
279     // baseline), or the subscript above the axis. Also, don't let the superscript's top edge be
280     // below the base's top edge, or the subscript's bottom edge above the base's bottom edge.
281
282     LayoutUnit baseHeight = base->logicalHeight();
283     LayoutUnit baseBaseline = base->firstLineBaseline().valueOr(baseHeight);
284     LayoutUnit axis = style().fontMetrics().xHeight() / 2;
285     int fontSize = style().fontSize();
286
287     ASSERT(m_baseWrapper->style().hasOneRef());
288     bool needsSecondLayout = false;
289
290     LayoutUnit topPadding = 0;
291     LayoutUnit bottomPadding = 0;
292
293     Element* scriptElement = element();
294     LayoutUnit superscriptShiftValue = 0;
295     LayoutUnit subscriptShiftValue = 0;
296     if (m_kind == Sub || m_kind == SubSup || m_kind == Multiscripts)
297         parseMathMLLength(scriptElement->fastGetAttribute(MathMLNames::subscriptshiftAttr), subscriptShiftValue, &style(), false);
298     if (m_kind == Super || m_kind == SubSup || m_kind == Multiscripts)
299         parseMathMLLength(scriptElement->fastGetAttribute(MathMLNames::superscriptshiftAttr), superscriptShiftValue, &style(), false);
300
301     bool isPostScript = true;
302     RenderMathMLBlock* subSupPair = downcast<RenderMathMLBlock>(m_baseWrapper->nextSibling());
303     for (; subSupPair; subSupPair = downcast<RenderMathMLBlock>(subSupPair->nextSibling())) {
304
305         // We skip the base and <mprescripts/> elements.
306         if (isPrescript(*subSupPair)) {
307             if (!isPostScript)
308                 break;
309             isPostScript = false;
310             continue;
311         }
312
313         if (RenderBox* superscript = m_kind == Sub ? 0 : subSupPair->lastChildBox()) {
314             LayoutUnit superscriptHeight = superscript->logicalHeight();
315             LayoutUnit superscriptBaseline = superscript->firstLineBaseline().valueOr(superscriptHeight);
316             LayoutUnit minBaseline = std::max<LayoutUnit>(fontSize / 3 + 1 + superscriptBaseline, superscriptHeight + axis + superscriptShiftValue);
317
318             topPadding = std::max<LayoutUnit>(topPadding, minBaseline - baseBaseline);
319         }
320
321         if (RenderBox* subscript = m_kind == Super ? 0 : subSupPair->firstChildBox()) {
322             LayoutUnit subscriptHeight = subscript->logicalHeight();
323             LayoutUnit subscriptBaseline = subscript->firstLineBaseline().valueOr(subscriptHeight);
324             LayoutUnit baseExtendUnderBaseline = baseHeight - baseBaseline;
325             LayoutUnit subscriptUnderItsBaseline = subscriptHeight - subscriptBaseline;
326             LayoutUnit minExtendUnderBaseline = std::max<LayoutUnit>(fontSize / 5 + 1 + subscriptUnderItsBaseline, subscriptHeight + subscriptShiftValue - axis);
327
328             bottomPadding = std::max<LayoutUnit>(bottomPadding, minExtendUnderBaseline - baseExtendUnderBaseline);
329         }
330     }
331
332     Length newPadding(topPadding, Fixed);
333     if (newPadding != m_baseWrapper->style().paddingTop()) {
334         m_baseWrapper->style().setPaddingTop(newPadding);
335         needsSecondLayout = true;
336     }
337
338     newPadding = Length(bottomPadding, Fixed);
339     if (newPadding != m_baseWrapper->style().paddingBottom()) {
340         m_baseWrapper->style().setPaddingBottom(newPadding);
341         needsSecondLayout = true;
342     }
343
344     if (!needsSecondLayout)
345         return;
346
347     setNeedsLayout(MarkOnlyThis);
348     m_baseWrapper->setChildNeedsLayout(MarkOnlyThis);
349
350     RenderMathMLBlock::layout();
351 }
352
353 Optional<int> RenderMathMLScripts::firstLineBaseline() const
354 {
355     if (m_baseWrapper) {
356         if (Optional<int> baseline = m_baseWrapper->firstLineBaseline())
357             return baseline;
358     }
359     return RenderMathMLBlock::firstLineBaseline();
360 }
361
362 RenderMathMLScriptsWrapper* RenderMathMLScriptsWrapper::createAnonymousWrapper(RenderMathMLScripts* renderObject, WrapperType type)
363 {
364     RenderMathMLScriptsWrapper* newBlock = new RenderMathMLScriptsWrapper(renderObject->document(), RenderStyle::createAnonymousStyleWithDisplay(&renderObject->style(), FLEX), type);
365     newBlock->initializeStyle();
366     return newBlock;
367 }
368
369 void RenderMathMLScriptsWrapper::addChildInternal(bool doNotRestructure, RenderObject* child, RenderObject* beforeChild)
370 {
371     if (doNotRestructure) {
372         RenderMathMLBlock::addChild(child, beforeChild);
373         return;
374     }
375
376     RenderMathMLScripts* parentNode = downcast<RenderMathMLScripts>(parent());
377
378     if (m_kind == Base) {
379         RenderObject* sibling = nextSibling();
380
381         if (!isEmpty() && !beforeChild) {
382             // This is like inserting the child after the base wrapper.
383             parentNode->addChildInternal(false, sibling);
384             return;
385         }
386
387         // The old base (if any) becomes a script ; the new child becomes either the base or an <mprescripts> separator.
388         RenderObject* oldBase = firstChild();
389         if (oldBase)
390             RenderMathMLBlock::removeChild(*oldBase);
391         if (isPrescript(*child))
392             parentNode->addChildInternal(true, child, sibling);
393         else
394             RenderMathMLBlock::addChild(child);
395         if (oldBase)
396             parentNode->addChildInternal(false, oldBase, sibling);
397         return;
398     }
399
400     if (isPrescript(*child)) {
401         // We insert an <mprescripts> element.
402         if (!beforeChild)
403             parentNode->addChildInternal(true, child, nextSibling());
404         else if (beforeChild == firstChild())
405             parentNode->addChildInternal(true, child, this);
406         else {
407             // We insert the <mprescripts> in the middle of a subSup pair so we must split that pair.
408             RenderObject* sibling = nextSibling();
409             parentNode->removeChildInternal(true, *this);
410             parentNode->addChildInternal(true, child, sibling);
411
412             RenderObject* script = firstChild();
413             RenderMathMLBlock::removeChild(*script);
414             parentNode->addChildInternal(false, script, child);
415
416             script = beforeChild;
417             RenderMathMLBlock::removeChild(*script);
418             parentNode->addChildInternal(false, script, sibling);
419             destroy();
420         }
421         return;
422     }
423
424     // We first move to the last subSup pair in the curent sequence of scripts.
425     RenderMathMLScriptsWrapper* subSupPair = this;
426     while (subSupPair->nextSibling() && !isPrescript(*subSupPair->nextSibling()))
427         subSupPair = downcast<RenderMathMLScriptsWrapper>(subSupPair->nextSibling());
428     if (subSupPair->firstChild()->nextSibling()) {
429         // The last pair has two children so we need to create a new pair to leave room for the new child.
430         RenderMathMLScriptsWrapper* newPair = createAnonymousWrapper(parentNode, RenderMathMLScriptsWrapper::SubSupPair);
431         parentNode->addChildInternal(true, newPair, subSupPair->nextSibling());
432         subSupPair = newPair;
433     }
434
435     // We shift the successors in the current sequence of scripts.
436     for (RenderObject* previousSibling = subSupPair->previousSibling(); subSupPair != this; previousSibling = previousSibling->previousSibling()) {
437         RenderMathMLScriptsWrapper& previousSubSupPair = downcast<RenderMathMLScriptsWrapper>(*previousSibling);
438         RenderObject* script = previousSubSupPair.lastChild();
439         previousSubSupPair.removeChildInternal(true, *script);
440         subSupPair->addChildInternal(true, script, subSupPair->firstChild());
441         subSupPair = downcast<RenderMathMLScriptsWrapper>(previousSibling);
442     }
443
444     // 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.
445     RenderMathMLBlock::addChild(child, firstChild() == beforeChild ? beforeChild : nullptr);
446 }
447
448 void RenderMathMLScriptsWrapper::addChild(RenderObject* child, RenderObject* beforeChild)
449 {
450     RenderMathMLScripts* parentNode = downcast<RenderMathMLScripts>(parent());
451
452     addChildInternal(false, child, beforeChild);
453
454     parentNode->fixAnonymousStyles();
455 }
456
457 void RenderMathMLScriptsWrapper::removeChildInternal(bool doNotRestructure, RenderObject& child)
458 {
459     if (doNotRestructure) {
460         RenderMathMLBlock::removeChild(child);
461         return;
462     }
463
464     RenderMathMLScripts* parentNode = downcast<RenderMathMLScripts>(parent());
465
466     if (m_kind == Base) {
467         // We remove the child from the base wrapper.
468         RenderObject* sibling = nextSibling();
469         RenderMathMLBlock::removeChild(child);
470         if (sibling && !isPrescript(*sibling)) {
471             // If there are postscripts, the first one becomes the base.
472             RenderMathMLScriptsWrapper& wrapper = downcast<RenderMathMLScriptsWrapper>(*sibling);
473             RenderObject* script = wrapper.firstChild();
474             wrapper.removeChildInternal(false, *script);
475             RenderMathMLBlock::addChild(script);
476         }
477         return;
478     }
479
480     // We remove the child and shift the successors in the current sequence of scripts.
481     RenderMathMLBlock::removeChild(child);
482     RenderMathMLScriptsWrapper* subSupPair = this;
483     for (RenderObject* nextSibling = subSupPair->nextSibling(); nextSibling && !isPrescript(*nextSibling); nextSibling = nextSibling->nextSibling()) {
484         RenderMathMLScriptsWrapper& nextSubSupPair = downcast<RenderMathMLScriptsWrapper>(*nextSibling);
485         RenderObject* script = nextSubSupPair.firstChild();
486         nextSubSupPair.removeChildInternal(true, *script);
487         subSupPair->addChildInternal(true, script);
488         subSupPair = downcast<RenderMathMLScriptsWrapper>(nextSibling);
489     }
490
491     // We remove the last subSup pair if it became empty.
492     if (subSupPair->isEmpty()) {
493         parentNode->removeChildInternal(true, *subSupPair);
494         subSupPair->destroy();
495     }
496 }
497
498 void RenderMathMLScriptsWrapper::removeChild(RenderObject& child)
499 {
500     if (beingDestroyed() || documentBeingDestroyed()) {
501         // The renderer is being destroyed so we remove the child normally.
502         RenderMathMLBlock::removeChild(child);
503         return;
504     }
505
506     RenderMathMLScripts* parentNode = downcast<RenderMathMLScripts>(parent());
507     removeChildInternal(false, child);
508     parentNode->fixAnonymousStyles();
509 }
510
511 }    
512
513 #endif // ENABLE(MATHML)