Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / rendering / mathml / RenderMathMLUnderOver.cpp
index 0621cd6..b0c34c0 100644 (file)
 
 #include "RenderMathMLUnderOver.h"
 
-#include "FontSelector.h"
+#include "MathMLElement.h"
 #include "MathMLNames.h"
+#include "RenderIterator.h"
+#include "RenderMathMLOperator.h"
 
 namespace WebCore {
 
 using namespace MathMLNames;
     
-static const double gOverSpacingAdjustment = 0.5;
-    
-RenderMathMLUnderOver::RenderMathMLUnderOver(Element* element)
-    : RenderMathMLBlock(element)
+RenderMathMLUnderOver::RenderMathMLUnderOver(Element& element, Ref<RenderStyle>&& style)
+    : RenderMathMLBlock(element, WTFMove(style))
 {
     // Determine what kind of under/over expression we have by element name
-    if (element->hasLocalName(MathMLNames::munderTag))
+    if (element.hasTagName(MathMLNames::munderTag))
         m_kind = Under;
-    else if (element->hasLocalName(MathMLNames::moverTag))
+    else if (element.hasTagName(MathMLNames::moverTag))
         m_kind = Over;
     else {
-        ASSERT(element->hasLocalName(MathMLNames::munderoverTag));
+        ASSERT(element.hasTagName(MathMLNames::munderoverTag));
         m_kind = UnderOver;
     }
 }
 
-RenderBoxModelObject* RenderMathMLUnderOver::base() const
-{
-    RenderObject* baseWrapper = firstChild();
-    if ((m_kind == Over || m_kind == UnderOver) && baseWrapper)
-        baseWrapper = baseWrapper->nextSibling();
-    if (!baseWrapper)
-        return 0;
-    RenderObject* base = baseWrapper->firstChild();
-    if (!base || !base->isBoxModelObject())
-        return 0;
-    return toRenderBoxModelObject(base);
-}
-
-void RenderMathMLUnderOver::addChild(RenderObject* child, RenderObject* beforeChild)
-{    
-    RenderMathMLBlock* row = new (renderArena()) RenderMathMLBlock(node());
-    RefPtr<RenderStyle> rowStyle = createBlockStyle();
-    row->setStyle(rowStyle.release());
-    row->setIsAnonymous(true);
-    
-    // look through the children for rendered elements counting the blocks so we know what child
-    // we are adding
-    int blocks = 0;
-    RenderObject* current = this->firstChild();
-    while (current) {
-        blocks++;
-        current = current->nextSibling();
-    }
-    
-    switch (blocks) {
-    case 0:
-        // this is the base so just append it
-        RenderBlock::addChild(row, beforeChild);
-        break;
-    case 1:
-        // the under or over
-        // FIXME: text-align: center does not work
-        row->style()->setTextAlign(CENTER);
-        if (m_kind == Over) {
-            // add the over as first
-            RenderBlock::addChild(row, firstChild());
-        } else {
-            // add the under as last
-            RenderBlock::addChild(row, beforeChild);
-        }
-        break;
-    case 2:
-        // the under or over
-        // FIXME: text-align: center does not work
-        row->style()->setTextAlign(CENTER);
-        if (m_kind == UnderOver) {
-            // add the over as first
-            RenderBlock::addChild(row, firstChild());
-        } else {
-            // we really shouldn't get here as only munderover should have three children
-            RenderBlock::addChild(row, beforeChild);
-        }
-        break;
-    default:
-        // munderover shouldn't have more than three children. In theory we shouldn't 
-        // get here if the MathML is correctly formed, but that isn't a guarantee.
-        // We will treat this as another under element and they'll get something funky.
-        RenderBlock::addChild(row, beforeChild);
-    }
-    row->addChild(child);    
-}
-
 RenderMathMLOperator* RenderMathMLUnderOver::unembellishedOperator()
 {
-    RenderBoxModelObject* base = this->base();
-    if (!base || !base->isRenderMathMLBlock())
-        return 0;
-    return toRenderMathMLBlock(base)->unembellishedOperator();
+    RenderObject* base = firstChild();
+    if (!is<RenderMathMLBlock>(base))
+        return nullptr;
+    return downcast<RenderMathMLBlock>(*base).unembellishedOperator();
 }
 
-inline int getOffsetHeight(RenderObject* obj) 
+Optional<int> RenderMathMLUnderOver::firstLineBaseline() const
 {
-    if (obj->isBoxModelObject()) {
-        RenderBoxModelObject* box = toRenderBoxModelObject(obj);
-        return box->offsetHeight();
-    }
-   
-    return 0;
-}
-
-void RenderMathMLUnderOver::stretchToHeight(int height)
-{
-    RenderBoxModelObject* base = this->base();
-    if (base && base->isRenderMathMLBlock()) {
-        RenderMathMLBlock* block = toRenderMathMLBlock(base);
-        block->stretchToHeight(height);
-        setNeedsLayout(true);
-    }
+    RenderBox* base = firstChildBox();
+    if (!base)
+        return Optional<int>();
+    Optional<int> baseline = base->firstLineBaseline();
+    if (baseline)
+        baseline.value() += static_cast<int>(base->logicalTop());
+    return baseline;
 }
 
-void RenderMathMLUnderOver::layout() 
+void RenderMathMLUnderOver::layout()
 {
-    RenderBlock::layout();
-    RenderObject* over = 0;
-    RenderObject* base = 0;
-    switch (m_kind) {
-    case Over:
-        // We need to calculate the baseline over the over versus the start of the base and 
-        // adjust the placement of the base.
-        over = firstChild();
-        if (over) {
-            // FIXME: descending glyphs intrude into base (e.g. lowercase y over base)
-            // FIXME: bases that ascend higher than the line box intrude into the over
-            if (!over->firstChild() || !over->firstChild()->isBoxModelObject())
-                break;
-            
-            LayoutUnit overSpacing = static_cast<LayoutUnit>(gOverSpacingAdjustment * (getOffsetHeight(over) - toRenderBoxModelObject(over->firstChild())->baselinePosition(AlphabeticBaseline, true, HorizontalLine)));
-            
-            // base row wrapper
-            base = over->nextSibling();
-            if (base) {
-                if (overSpacing > 0) 
-                    base->style()->setMarginTop(Length(-overSpacing, Fixed));
-                else 
-                    base->style()->setMarginTop(Length(0, Fixed));
+    LayoutUnit stretchWidth = 0;
+    Vector<RenderMathMLOperator*, 2> renderOperators;
+
+    for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+        if (child->needsLayout()) {
+            if (is<RenderMathMLBlock>(child)) {
+                if (auto renderOperator = downcast<RenderMathMLBlock>(*child).unembellishedOperator()) {
+                    if (!renderOperator->isVertical()) {
+                        renderOperator->resetStretchSize();
+                        renderOperators.append(renderOperator);
+                    }
+                }
             }
-            
-        }
-        break;
-    case Under:
-        // FIXME: Non-ascending glyphs in the under should be moved closer to the base
 
-        // We need to calculate the baseline of the base versus the start of the under block and
-        // adjust the placement of the under block.
-        
-        // base row wrapper
-        base = firstChild();
-        if (base) {
-            LayoutUnit baseHeight = getOffsetHeight(base);
-            // actual base
-            base = base->firstChild();
-            if (!base || !base->isBoxModelObject())
-                break;
-            
-            // FIXME: We need to look at the space between a single maximum height of
-            //        the line boxes and the baseline and squeeze them together
-            LayoutUnit underSpacing = baseHeight - toRenderBoxModelObject(base)->baselinePosition(AlphabeticBaseline, true, HorizontalLine);
-            
-            // adjust the base's intrusion into the under
-            RenderObject* under = lastChild();
-            if (under && underSpacing > 0)
-                under->style()->setMarginTop(Length(-underSpacing, Fixed));
+            downcast<RenderElement>(*child).layout();
         }
-        break;
-    case UnderOver:
-        // FIXME: Non-descending glyphs in the over should be moved closer to the base
-        // FIXME: Non-ascending glyphs in the under should be moved closer to the base
-        
-        // We need to calculate the baseline of the over versus the start of the base and 
-        // adjust the placement of the base.
-        
-        over = firstChild();
-        if (over) {
-            // FIXME: descending glyphs intrude into base (e.g. lowercase y over base)
-            // FIXME: bases that ascend higher than the line box intrude into the over
-            if (!over->firstChild() || !over->firstChild()->isBoxModelObject())
-                break;
-            LayoutUnit overSpacing = static_cast<LayoutUnit>(gOverSpacingAdjustment * (getOffsetHeight(over) - toRenderBoxModelObject(over->firstChild())->baselinePosition(AlphabeticBaseline, true, HorizontalLine)));
-            
-            // base row wrapper
-            base = over->nextSibling();
-            
-            if (base) {
-                if (overSpacing > 0)
-                    base->style()->setMarginTop(Length(-overSpacing, Fixed));
-                
-                // We need to calculate the baseline of the base versus the start of the under block and
-                // adjust the placement of the under block.
-                
-                LayoutUnit baseHeight = getOffsetHeight(base);
-                // actual base
-                base = base->firstChild();
-                if (!base || !base->isBoxModelObject())
-                    break;
 
-                // FIXME: We need to look at the space between a single maximum height of
-                //        the line boxes and the baseline and squeeze them together
-                LayoutUnit underSpacing = baseHeight - toRenderBoxModelObject(base)->baselinePosition(AlphabeticBaseline, true, HorizontalLine);
-                
-                RenderObject* under = lastChild();
-                if (under && under->firstChild() && under->firstChild()->isRenderInline() && underSpacing > 0)
-                    under->style()->setMarginTop(Length(-underSpacing, Fixed));
-                
-            }
-        }
-        break;
+        // Skipping the embellished op does not work for nested structures like
+        // <munder><mover><mo>_</mo>...</mover> <mo>_</mo></munder>.
+        if (is<RenderBox>(*child))
+            stretchWidth = std::max<LayoutUnit>(stretchWidth, downcast<RenderBox>(*child).logicalWidth());
     }
-    setNeedsLayout(true);
-    RenderBlock::layout();
-}
-
-LayoutUnit RenderMathMLUnderOver::baselinePosition(FontBaseline, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
-{
-    RenderObject* current = firstChild();
-    if (!current || linePositionMode == PositionOfInteriorLineBoxes)
-        return RenderBlock::baselinePosition(AlphabeticBaseline, firstLine, direction, linePositionMode);
 
-    LayoutUnit baseline = 0;
-    switch (m_kind) {
-    case UnderOver:
-    case Over:
-        baseline += getOffsetHeight(current);
-        current = current->nextSibling();
-        if (current) {
-            // actual base
-            RenderObject* base = current->firstChild();
-            if (!base || !base->isBoxModelObject())
-                break;
-            baseline += toRenderBoxModelObject(base)->baselinePosition(AlphabeticBaseline, firstLine, HorizontalLine, linePositionMode);
-            // added the negative top margin
-            baseline += current->style()->marginTop().value();
-        }
-        break;
-    case Under:
-        RenderObject* base = current->firstChild();
-        if (base && base->isBoxModelObject())
-            baseline += toRenderBoxModelObject(base)->baselinePosition(AlphabeticBaseline, true, HorizontalLine);
-    }
+    // Set the sizes of (possibly embellished) stretchy operator children.
+    for (auto& renderOperator : renderOperators)
+        renderOperator->stretchTo(stretchWidth);
 
-    return baseline;
+    RenderMathMLBlock::layout();
 }
 
 }