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);    
}
Example #2
0
void RenderMathMLSubSup::layout()
{
    RenderBlock::layout();
    
    if (m_kind != SubSup || !m_scripts)
        return;
    RenderMathMLBlock* baseWrapper = toRenderMathMLBlock(firstChild());
    RenderMathMLBlock* superscriptWrapper = toRenderMathMLBlock(m_scripts->firstChild());
    RenderMathMLBlock* subscriptWrapper = toRenderMathMLBlock(m_scripts->lastChild());
    if (!baseWrapper || !superscriptWrapper || !subscriptWrapper || superscriptWrapper == subscriptWrapper)
        return;
    
    LayoutUnit baseWrapperBaseline = toRenderBox(firstChild())->firstLineBoxBaseline();
    LayoutUnit baseBaseline = baseWrapperBaseline - baseWrapper->paddingBefore();
    LayoutUnit baseExtendUnderBaseline = baseWrapper->logicalHeight() - baseWrapperBaseline;
    LayoutUnit axis = style()->fontMetrics().xHeight() / 2;
    LayoutUnit superscriptHeight = superscriptWrapper->logicalHeight() - superscriptWrapper->paddingAfter();
    LayoutUnit subscriptHeight = subscriptWrapper->logicalHeight();
    
    // Our layout rules are: Don't let the superscript go below the "axis" (half x-height above the
    // baseline), or the subscript above the axis. Also, don't let the superscript's top edge be
    // below the base's top edge, or the subscript's bottom edge above the base's bottom edge.
    //
    // FIXME: Check any subscriptshift or superscriptshift attributes, and maybe use more sophisticated
    // heuristics from TeX or elsewhere. See https://bugs.webkit.org/show_bug.cgi?id=79274#c5.
    
    // Above we did scriptsStyle->setVerticalAlign(TOP) for mscripts' style, so the superscript's
    // top edge will equal the top edge of the base's padding.
    LayoutUnit basePaddingTop = superscriptHeight + axis - baseBaseline;
    // If basePaddingTop is positive, it's indeed the base's padding-top that we need. If it's negative,
    // then we should instead use its absolute value to pad the bottom of the superscript, to get the
    // superscript's bottom edge down to the axis. First we compute how much more we need to shift the
    // subscript down, once its top edge is at the axis.
    LayoutUnit superPaddingBottom = max<LayoutUnit>(baseExtendUnderBaseline + axis - subscriptHeight, 0);
    if (basePaddingTop < 0) {
        superPaddingBottom += -basePaddingTop;
        basePaddingTop = 0;
    }
    
    setChildNeedsLayout(true, MarkOnlyThis);
    
    baseWrapper->style()->setPaddingTop(Length(basePaddingTop, Fixed));
    baseWrapper->setNeedsLayout(true, MarkOnlyThis);
    
    superscriptWrapper->style()->setPaddingBottom(Length(superPaddingBottom, Fixed));
    superscriptWrapper->setNeedsLayout(true, MarkOnlyThis);
    m_scripts->setNeedsLayout(true, MarkOnlyThis);
    
    RenderBlock::layout();
}
void RenderMathMLSubSup::layout()
{
    RenderMathMLBlock::layout();

    RenderMathMLBlock* baseWrapper = toRenderMathMLBlock(firstChild());
    if (!baseWrapper || !m_scripts)
        return;
    RenderBox* base = baseWrapper->firstChildBox();
    if (!base)
        return;

    // Our layout rules include: Don't let the superscript go below the "axis" (half x-height above the
    // baseline), or the subscript above the axis. Also, don't let the superscript's top edge be
    // below the base's top edge, or the subscript's bottom edge above the base's bottom edge.
    //
    // FIXME: Check any subscriptshift or superscriptshift attributes, and maybe use more sophisticated
    // heuristics from TeX or elsewhere. See https://bugs.webkit.org/show_bug.cgi?id=79274#c5.

    LayoutUnit baseHeight = base->logicalHeight();
    LayoutUnit baseBaseline = base->firstLineBoxBaseline();
    if (baseBaseline == -1)
        baseBaseline = baseHeight;
    LayoutUnit axis = style()->fontMetrics().xHeight() / 2;
    int fontSize = style()->fontSize();

    ASSERT(baseWrapper->style()->hasOneRef());
    bool needsSecondLayout = false;

    if (RenderBox* superscript = m_kind == Sub ? 0 : m_scripts->lastChildBox()) {
        LayoutUnit superscriptHeight = superscript->logicalHeight();
        LayoutUnit superscriptBaseline = superscript->firstLineBoxBaseline();
        if (superscriptBaseline == -1)
            superscriptBaseline = superscriptHeight;
        LayoutUnit minBaseline = max<LayoutUnit>(fontSize / 3 + 1 + superscriptBaseline, superscriptHeight + axis);

        Length newPadding = Length(max<LayoutUnit>(minBaseline - baseBaseline, 0), Fixed);
        if (newPadding != baseWrapper->style()->paddingTop()) {
            baseWrapper->style()->setPaddingTop(newPadding);
            needsSecondLayout = true;
        }
    }

    if (RenderBox* subscript = m_kind == Super ? 0 : m_scripts->firstChildBox()) {
        LayoutUnit subscriptHeight = subscript->logicalHeight();
        LayoutUnit subscriptBaseline = subscript->firstLineBoxBaseline();
        if (subscriptBaseline == -1)
            subscriptBaseline = subscriptHeight;
        LayoutUnit baseExtendUnderBaseline = baseHeight - baseBaseline;
        LayoutUnit subscriptUnderItsBaseline = subscriptHeight - subscriptBaseline;
        LayoutUnit minExtendUnderBaseline = max<LayoutUnit>(fontSize / 5 + 1 + subscriptUnderItsBaseline, subscriptHeight - axis);

        Length newPadding = Length(max<LayoutUnit>(minExtendUnderBaseline - baseExtendUnderBaseline, 0), Fixed);
        if (newPadding != baseWrapper->style()->paddingBottom()) {
            baseWrapper->style()->setPaddingBottom(newPadding);
            needsSecondLayout = true;
        }
    }

    if (!needsSecondLayout)
        return;

    setNeedsLayout(true, MarkOnlyThis);
    baseWrapper->setChildNeedsLayout(true, MarkOnlyThis);

    RenderMathMLBlock::layout();
}