Beispiel #1
0
// FIXME: It's cleaner to only call updateFromElement when an attribute has changed. The body of
// this method should probably be moved to a private stretchHeightChanged or checkStretchHeight
// method. Probably at the same time, addChild/removeChild methods should be made to work for
// dynamic DOM changes.
void RenderMathMLOperator::updateFromElement()
{
    RenderElement* savedRenderer = element().renderer();

    // Destroy our current children
    destroyLeftoverChildren();

    // Since we share a node with our children, destroying our children may set our node's
    // renderer to 0, so we need to restore it.
    element().setRenderer(savedRenderer);
    
    RefPtr<RenderStyle> newStyle = RenderStyle::create();
    newStyle->inheritFrom(style());
    newStyle->setDisplay(FLEX);

    RenderMathMLBlock* container = new RenderMathMLBlock(element());
    // This container doesn't offer any useful information to accessibility.
    container->setIgnoreInAccessibilityTree(true);
    container->setStyle(newStyle.release());

    addChild(container);
    RenderText* text;
    if (m_operator)
        text = new RenderText(document(), String(&m_operator, 1));
    else
        text = new RenderText(document(), element().textContent().replace(hyphenMinus, minusSign).impl());

    // If we can't figure out the text, leave it blank.
    if (text)
        container->addChild(text);

    updateStyle();
    setNeedsLayoutAndPrefWidthsRecalc();
}
Beispiel #2
0
void  RenderMathMLUnderOver::stretchToHeight(int height)
{

    RenderObject* base = firstChild();
    if (!base)
        return;
        
    // For over or underover, the base is the sibling of the first child
    if (m_kind != Under) 
        base = base->nextSibling();
        
    if (!base)
        return;
        
    // use the child of the row which is the actual base
    base = base->firstChild();
    
    if (base && base->isRenderMathMLBlock()) {
        RenderMathMLBlock* block = toRenderMathMLBlock(base);
        block->stretchToHeight(height);
        updateBoxModelInfoFromStyle();
        setNeedsLayoutAndPrefWidthsRecalc();
        markContainingBlocksForLayout();
    }
}
void RenderMathMLFraction::paint(PaintInfo& info, const LayoutPoint& paintOffset)
{
    RenderMathMLBlock::paint(info, paintOffset);
    if (info.context->paintingDisabled() || info.phase != PaintPhaseForeground)
        return;
    
    if (!firstChild() ||!m_lineThickness)
        return;

    LayoutUnit verticalOffset = 0;
    // The children are always RenderMathMLBlock instances
    if (firstChild()->isRenderMathMLBlock()) {
        int adjustForThickness = m_lineThickness > 1 ? int(m_lineThickness / 2) : 1;
        if (int(m_lineThickness) % 2 == 1)
            adjustForThickness++;
        RenderMathMLBlock* numerator = toRenderMathMLBlock(firstChild());
        if (numerator->isRenderMathMLRow())
            verticalOffset = numerator->offsetHeight() + adjustForThickness;
        else 
            verticalOffset = numerator->offsetHeight();        
    }
    
    LayoutPoint adjustedPaintOffset = paintOffset + location();
    adjustedPaintOffset.setY(adjustedPaintOffset.y() + verticalOffset);
    
    GraphicsContextStateSaver stateSaver(*info.context);
    
    info.context->setStrokeThickness(m_lineThickness);
    info.context->setStrokeStyle(SolidStroke);
    info.context->setStrokeColor(style()->visitedDependentColor(CSSPropertyColor), ColorSpaceSRGB);
    
    info.context->drawLine(adjustedPaintOffset, IntPoint(adjustedPaintOffset.x() + offsetWidth(), adjustedPaintOffset.y()));
}
void  RenderMathMLSubSup::stretchToHeight(int height)
{
    RenderObject* base = firstChild();
    if (!base)
        return;
    
    if (base->isRenderMathMLBlock()) {
        RenderMathMLBlock* block = toRenderMathMLBlock(base);
        block->stretchToHeight(static_cast<int>(gSubSupStretch * height));
    }
    if (height > 0 && m_kind == SubSup && m_scripts) {
        RenderObject* script = m_scripts->firstChild();
        if (script) {
            // Calculate the script height without the container margins.
            RenderObject* top = script;
            int topHeight = getBoxModelObjectHeight(top->firstChild());
            int topAdjust = topHeight / gTopAdjustDivisor;
            top->style()->setMarginTop(Length(-topAdjust, Fixed));
            top->style()->setMarginBottom(Length(height - topHeight + topAdjust, Fixed));
            if (top->isBoxModelObject()) {
                RenderBoxModelObject* topBox = toRenderBoxModelObject(top);
                topBox->updateBoxModelInfoFromStyle();
            }
            m_scripts->setNeedsLayoutAndPrefWidthsRecalc();
            m_scripts->markContainingBlocksForLayout();
        }
    }
    updateBoxModelInfoFromStyle();
    setNeedsLayoutAndPrefWidthsRecalc();
    markContainingBlocksForLayout();
}
RenderMathMLBlock* RenderMathMLBlock::createAnonymousMathMLBlock(EDisplay display)
{
    RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), display);
    RenderMathMLBlock* newBlock = new (renderArena()) RenderMathMLBlock(0);
    newBlock->setDocumentForAnonymous(document());
    newBlock->setStyle(newStyle.release());
    return newBlock;
}
Beispiel #6
0
void RenderMathMLBlock::stretchToHeight(int height)
{
    for (RenderObject* current = firstChild(); current; current = current->nextSibling())
        if (current->isRenderMathMLBlock()) {
            RenderMathMLBlock* block = toRenderMathMLBlock(current);
            block->stretchToHeight(height);
        }
}
void RenderMathMLUnderOver::stretchToHeight(int height)
{
    RenderBoxModelObject* base = this->base();
    if (base && base->isRenderMathMLBlock()) {
        RenderMathMLBlock* block = toRenderMathMLBlock(base);
        block->stretchToHeight(height);
        setNeedsLayout(true);
    }
}
Beispiel #8
0
void RenderMathMLFraction::addChild(RenderObject* child, RenderObject* beforeChild)
{
    RenderMathMLBlock* row = createAnonymousMathMLBlock();
    
    RenderMathMLBlock::addChild(row, beforeChild);
    row->addChild(child);
    
    fixChildStyle(row);
    updateFromElement();
}
Beispiel #9
0
int RenderMathMLRow::baselinePosition(FontBaseline, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
{
    if (firstChild() && firstChild()->isRenderMathMLBlock()) {
        RenderMathMLBlock* block = toRenderMathMLBlock(firstChild());
        if (block->isRenderMathMLOperator())
            return block->y() + block->baselinePosition(AlphabeticBaseline, firstLine, direction, linePositionMode);
    }
    
    return RenderBlock::baselinePosition(AlphabeticBaseline, firstLine, direction, linePositionMode);
}
Beispiel #10
0
void RenderMathMLSubSup::addChild(RenderObject* child, RenderObject* beforeChild)
{
    // Note: The RenderMathMLBlock only allows element children to be added.
    Element* childElement = toElement(child->node());

    if (childElement && !childElement->previousElementSibling()) {
        // Position 1 is always the base of the msub/msup/msubsup.
        RenderMathMLBlock* wrapper = new (renderArena()) RenderMathMLBlock(node());
        RefPtr<RenderStyle> wrapperStyle = RenderStyle::create();
        wrapperStyle->inheritFrom(style());
        wrapperStyle->setDisplay(INLINE_BLOCK);
        wrapperStyle->setVerticalAlign(BASELINE);
        wrapper->setStyle(wrapperStyle.release());
        RenderMathMLBlock::addChild(wrapper, firstChild());
        wrapper->addChild(child);
            
        // Make sure we have a script block for rendering.
        if (m_kind == SubSup && !m_scripts) {
            m_scripts = new (renderArena()) RenderMathMLBlock(node());
            RefPtr<RenderStyle> scriptsStyle = RenderStyle::create();
            scriptsStyle->inheritFrom(style());
            scriptsStyle->setDisplay(INLINE_BLOCK);
            scriptsStyle->setVerticalAlign(TOP);
            scriptsStyle->setMarginLeft(Length(gSubsupScriptMargin, Fixed));
            scriptsStyle->setTextAlign(LEFT);
            // Set this wrapper's font-size for its line-height & baseline position.
            scriptsStyle->setBlendedFontSize(static_cast<int>(0.75 * style()->fontSize()));
            m_scripts->setStyle(scriptsStyle.release());
            RenderMathMLBlock::addChild(m_scripts, beforeChild);
        }
    } else {
        if (m_kind == SubSup) {
            ASSERT(childElement);
            if (!childElement)
                return;

            RenderBlock* script = new (renderArena()) RenderMathMLBlock(node());
            RefPtr<RenderStyle> scriptStyle = RenderStyle::create();
            scriptStyle->inheritFrom(m_scripts->style());
            scriptStyle->setDisplay(BLOCK);
            script->setStyle(scriptStyle.release());

            // The order is always backwards so the first script is the subscript and the superscript 
            // is last. That means the superscript is the first to render vertically.
            Element* previousSibling = childElement->previousElementSibling();
            if (previousSibling && !previousSibling->previousElementSibling()) 
                m_scripts->addChild(script);
            else                 
                m_scripts->addChild(script, m_scripts->firstChild());
            
            script->addChild(child);
        } else
            RenderMathMLBlock::addChild(child, beforeChild);
    }
}
Beispiel #11
0
void RenderMathMLUnderOver::addChild(RenderObject* child, RenderObject* beforeChild)
{    
    RenderMathMLBlock* row = new (renderArena()) RenderMathMLBlock(node());
    RefPtr<RenderStyle> rowStyle = makeBlockStyle();
    row->setStyle(rowStyle.release());
    
    // 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);    
}
int RenderMathMLUnderOver::nonOperatorHeight() const 
{
    int nonOperators = 0;
    for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
        if (current->firstChild() && current->firstChild()->isRenderMathMLBlock()) {
            RenderMathMLBlock* block = toRenderMathMLBlock(current->firstChild());
            if (!block->isRenderMathMLOperator()) 
                nonOperators += getOffsetHeight(current);
        } else
            nonOperators += getOffsetHeight(current);
    }
    return nonOperators;
}
LayoutUnit RenderMathMLFraction::baselinePosition(FontBaseline, bool firstLine, LineDirectionMode lineDirection, LinePositionMode linePositionMode) const
{
    if (firstChild() && firstChild()->isRenderMathMLBlock()) {
        RenderMathMLBlock* numerator = toRenderMathMLBlock(firstChild());
        RenderStyle* refStyle = style();
        if (previousSibling())
            refStyle = previousSibling()->style();
        else if (nextSibling())
            refStyle = nextSibling()->style();
        int shift = int(ceil((refStyle->fontMetrics().xHeight() + 1) / 2));
        return numerator->offsetHeight() + shift;
    }
    return RenderBlock::baselinePosition(AlphabeticBaseline, firstLine, lineDirection, linePositionMode);
}
Beispiel #14
0
int RenderMathMLRow::nonOperatorHeight() const
{
    int maxHeight = 0;
    for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
        if (current->isRenderMathMLBlock()) {
            RenderMathMLBlock* block = toRenderMathMLBlock(current);
            int blockHeight = block->nonOperatorHeight();
            // Check to see if this box has a larger height
            if (blockHeight > maxHeight)
                maxHeight = blockHeight;
        } else if (current->isBoxModelObject()) {
            RenderBoxModelObject* box = toRenderBoxModelObject(current);
            // Check to see if this box has a larger height
            if (box->offsetHeight() > maxHeight)
                maxHeight = box->offsetHeight();
        }
        
    }
    return maxHeight;
}
Beispiel #15
0
void RenderMathMLRow::layout()
{
    int stretchHeightAboveBaseline = 0, stretchDepthBelowBaseline = 0;
    for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
        if (child->needsLayout())
            toRenderElement(child)->layout();
        if (child->isRenderMathMLBlock()) {
            // We skip the stretchy operators as they must not be included in the computation of the stretch size.
            auto renderOperator = toRenderMathMLBlock(child)->unembellishedOperator();
            if (renderOperator && renderOperator->hasOperatorFlag(MathMLOperatorDictionary::Stretchy))
                continue;
        }
        LayoutUnit childHeightAboveBaseline = 0, childDepthBelowBaseline = 0;
        if (child->isRenderMathMLBlock()) {
            RenderMathMLBlock* mathmlChild = toRenderMathMLBlock(child);
            childHeightAboveBaseline = mathmlChild->firstLineBaseline();
            if (childHeightAboveBaseline == -1)
                childHeightAboveBaseline = mathmlChild->logicalHeight();
            childDepthBelowBaseline = mathmlChild->logicalHeight() - childHeightAboveBaseline;
        } else if (child->isRenderMathMLTable()) {
            RenderMathMLTable* tableChild = toRenderMathMLTable(child);
            childHeightAboveBaseline = tableChild->firstLineBaseline();
            childDepthBelowBaseline = tableChild->logicalHeight() - childHeightAboveBaseline;
        } else if (child->isBox()) {
            childHeightAboveBaseline = toRenderBox(child)->logicalHeight();
            childDepthBelowBaseline = 0;
        }
        stretchHeightAboveBaseline = std::max<LayoutUnit>(stretchHeightAboveBaseline, childHeightAboveBaseline);
        stretchDepthBelowBaseline = std::max<LayoutUnit>(stretchDepthBelowBaseline, childDepthBelowBaseline);
    }
    if (stretchHeightAboveBaseline + stretchDepthBelowBaseline <= 0)
        stretchHeightAboveBaseline = style().fontSize();
    
    // Set the sizes of (possibly embellished) stretchy operator children.
    for (auto& child : childrenOfType<RenderMathMLBlock>(*this)) {
        if (auto renderOperator = child.unembellishedOperator())
            renderOperator->stretchTo(stretchHeightAboveBaseline, stretchDepthBelowBaseline);
    }

    RenderMathMLBlock::layout();
}
void RenderMathMLBlock::computeChildrenPreferredLogicalHeights()
{
    ASSERT(needsLayout());

    // This is ugly, but disable fragmentation when computing the preferred heights.
    FragmentationDisabler fragmentationDisabler(this);

    // Ensure a full repaint will happen after layout finishes.
    setNeedsLayout(true, MarkOnlyThis);

    RenderView* renderView = view();
    bool hadLayoutState = renderView->layoutState();
    if (!hadLayoutState)
        renderView->pushLayoutState(this);
    {
        LayoutStateDisabler layoutStateDisabler(renderView);

        LayoutUnit oldAvailableLogicalWidth = availableLogicalWidth();
        setLogicalWidth(cLargeLogicalWidth);

        for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
            if (!child->isBox())
                continue;

            // Because our width changed, |child| may need layout.
            if (child->maxPreferredLogicalWidth() > oldAvailableLogicalWidth)
                child->setNeedsLayout(true, MarkOnlyThis);

            RenderMathMLBlock* childMathMLBlock = child->isRenderMathMLBlock() ? toRenderMathMLBlock(child) : 0;
            if (childMathMLBlock && !childMathMLBlock->isPreferredLogicalHeightDirty())
                continue;
            // Layout our child to compute its preferred logical height.
            child->layoutIfNeeded();
            if (childMathMLBlock)
                childMathMLBlock->setPreferredLogicalHeight(childMathMLBlock->logicalHeight());
        }
    }
    if (!hadLayoutState)
        renderView->popLayoutState(this);
}
void RenderMathMLSubSup::addChild(RenderObject* child, RenderObject* beforeChild)
{
    if (firstChild()) {
        // We already have a base, so this is the super/subscripts being added.
        
        if (m_kind == SubSup) {
            if (!m_scripts) {
                m_scripts = new (renderArena()) RenderMathMLBlock(node());
                RefPtr<RenderStyle> scriptsStyle = RenderStyle::create();
                scriptsStyle->inheritFrom(style());
                scriptsStyle->setDisplay(INLINE_BLOCK);
                scriptsStyle->setVerticalAlign(MIDDLE);
                scriptsStyle->setMarginLeft(Length(gSubsupScriptMargin, Fixed));
                scriptsStyle->setTextAlign(LEFT);
                m_scripts->setStyle(scriptsStyle.release());
                RenderMathMLBlock::addChild(m_scripts, beforeChild);
            }
            
            RenderBlock* script = new (renderArena()) RenderMathMLBlock(node());
            RefPtr<RenderStyle> scriptStyle = RenderStyle::create();
            scriptStyle->inheritFrom(m_scripts->style());
            scriptStyle->setDisplay(BLOCK);
            script->setStyle(scriptStyle.release());
            
            m_scripts->addChild(script, m_scripts->firstChild());
            script->addChild(child);
        } else
            RenderMathMLBlock::addChild(child, beforeChild);
        
    } else {
        RenderMathMLBlock* wrapper = new (renderArena()) RenderMathMLBlock(node());
        RefPtr<RenderStyle> wrapperStyle = RenderStyle::create();
        wrapperStyle->inheritFrom(style());
        wrapperStyle->setDisplay(INLINE_BLOCK);
        wrapperStyle->setVerticalAlign(MIDDLE);
        wrapper->setStyle(wrapperStyle.release());
        RenderMathMLBlock::addChild(wrapper, beforeChild);
        wrapper->addChild(child);
    }
}
Beispiel #18
0
void RenderMathMLSubSup::addChild(RenderObject* child, RenderObject* beforeChild)
{
    // Note: The RenderMathMLBlock only allows element children to be added.
    Element* childElement = toElement(child->node());

    if (childElement && !childElement->previousElementSibling()) {
        // Position 1 is always the base of the msub/msup/msubsup.
        RenderMathMLBlock* baseWrapper = createAnonymousMathMLBlock(INLINE_BLOCK);
        RenderMathMLBlock::addChild(baseWrapper, firstChild());
        baseWrapper->addChild(child);
            
        // Make sure we have a script block for rendering.
        if (m_kind == SubSup && !m_scripts) {
            m_scripts = createAnonymousMathMLBlock(INLINE_BLOCK);
            fixScriptsStyle();
            RenderMathMLBlock::addChild(m_scripts, beforeChild);
        }
    } else {
        if (m_kind == SubSup) {
            ASSERT(childElement);
            if (!childElement)
                return;

            RenderMathMLBlock* script = m_scripts->createAnonymousMathMLBlock();

            // The order is always backwards so the first script is the subscript and the superscript 
            // is last. That means the superscript is the first to render vertically.
            Element* previousSibling = childElement->previousElementSibling();
            if (previousSibling && !previousSibling->previousElementSibling()) 
                m_scripts->addChild(script);
            else                 
                m_scripts->addChild(script, m_scripts->firstChild());
            
            script->addChild(child);
        } else
            RenderMathMLBlock::addChild(child, beforeChild);
    }
}
Beispiel #19
0
void RenderMathMLUnderOver::stretchToHeight(int height)
{

    RenderObject* base = firstChild();
    if (!base)
        return;
        
    // For over or underover, the base is the sibling of the first child
    if (m_kind != Under) 
        base = base->nextSibling();
        
    if (!base)
        return;
        
    // use the child of the row which is the actual base
    base = base->firstChild();
    
    if (base && base->isRenderMathMLBlock()) {
        RenderMathMLBlock* block = toRenderMathMLBlock(base);
        block->stretchToHeight(height);
        setNeedsLayout(true);
    }
}
Beispiel #20
0
void RenderMathMLRow::layout() 
{
    RenderBlock::layout();
    
    int maxHeight = 0;

    // Calculate the non-operator max height of the row.
    for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
        if (current->isRenderMathMLBlock()) {
            RenderMathMLBlock* block = toRenderMathMLBlock(current);
            if (!block->unembellishedOperator() && block->offsetHeight() > maxHeight)
                maxHeight = block->offsetHeight();
        } else if (current->isBoxModelObject()) {
            RenderBoxModelObject* box = toRenderBoxModelObject(current);
            // Check to see if this box has a larger height.
            if (box->pixelSnappedOffsetHeight() > maxHeight)
                maxHeight = box->pixelSnappedOffsetHeight();
        }
    }
    
    if (!maxHeight)
        maxHeight = style()->fontSize();
    
    // Stretch everything to the same height (blocks can ignore the request).
    if (maxHeight > 0) {
        bool didStretch = false;
        for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
            if (current->isRenderMathMLBlock()) {
                RenderMathMLBlock* block = toRenderMathMLBlock(current);
                block->stretchToHeight(maxHeight);
                didStretch = true;
            }
        }
        if (didStretch) {
            setNeedsLayout(true);
            setPreferredLogicalWidthsDirty(true, false);
            RenderBlock::layout();
        }
    }
    
}    
void RenderMathMLScripts::layout()
{
    RenderMathMLBlock::layout();

    if (!m_baseWrapper)
        return;
    RenderBox* base = m_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.

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

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

    LayoutUnit topPadding = 0;
    LayoutUnit bottomPadding = 0;

    Element* scriptElement = element();
    LayoutUnit superscriptShiftValue = 0;
    LayoutUnit subscriptShiftValue = 0;
    if (m_kind == Sub || m_kind == SubSup || m_kind == Multiscripts)
        parseMathMLLength(scriptElement->fastGetAttribute(MathMLNames::subscriptshiftAttr), subscriptShiftValue, &style(), false);
    if (m_kind == Super || m_kind == SubSup || m_kind == Multiscripts)
        parseMathMLLength(scriptElement->fastGetAttribute(MathMLNames::superscriptshiftAttr), superscriptShiftValue, &style(), false);

    bool isPostScript = true;
    RenderMathMLBlock* subSupPair = downcast<RenderMathMLBlock>(m_baseWrapper->nextSibling());
    for (; subSupPair; subSupPair = downcast<RenderMathMLBlock>(subSupPair->nextSibling())) {

        // We skip the base and <mprescripts/> elements.
        if (isPrescript(*subSupPair)) {
            if (!isPostScript)
                break;
            isPostScript = false;
            continue;
        }

        if (RenderBox* superscript = m_kind == Sub ? 0 : subSupPair->lastChildBox()) {
            LayoutUnit superscriptHeight = superscript->logicalHeight();
            LayoutUnit superscriptBaseline = superscript->firstLineBaseline().valueOr(superscriptHeight);
            LayoutUnit minBaseline = std::max<LayoutUnit>(fontSize / 3 + 1 + superscriptBaseline, superscriptHeight + axis + superscriptShiftValue);

            topPadding = std::max<LayoutUnit>(topPadding, minBaseline - baseBaseline);
        }

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

            bottomPadding = std::max<LayoutUnit>(bottomPadding, minExtendUnderBaseline - baseExtendUnderBaseline);
        }
    }

    Length newPadding(topPadding, Fixed);
    if (newPadding != m_baseWrapper->style().paddingTop()) {
        m_baseWrapper->style().setPaddingTop(newPadding);
        needsSecondLayout = true;
    }

    newPadding = Length(bottomPadding, Fixed);
    if (newPadding != m_baseWrapper->style().paddingBottom()) {
        m_baseWrapper->style().setPaddingBottom(newPadding);
        needsSecondLayout = true;
    }

    if (!needsSecondLayout)
        return;

    setNeedsLayout(MarkOnlyThis);
    m_baseWrapper->setChildNeedsLayout(MarkOnlyThis);

    RenderMathMLBlock::layout();
}
Beispiel #22
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 RenderMathMLRow::layout() 
{
    RenderBlock::layout();
    
    // Calculate the maximum height of the row without the operators.
    int maxHeight = nonOperatorHeight();
    
    // Set the maximum height of the row for intermediate layouts.
    style()->setHeight(Length(maxHeight, Fixed));

    // Notify contained operators they may need to re-layout their stretched operators.
    // We need to keep track of the number of children and operators because a row of
    // operators needs some special handling.
    int childCount = 0;
    int operatorCount = 0;
    for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
        childCount++;
        if (current->isRenderMathMLBlock()) {
            RenderMathMLBlock* block = toRenderMathMLBlock(current);
            block->stretchToHeight(maxHeight);
            if (block->isRenderMathMLOperator()) 
                operatorCount++;
        }
    }
    
    // Layout the non-operators which have just been stretched.
    setNeedsLayoutAndPrefWidthsRecalc();
    markContainingBlocksForLayout();
    RenderBlock::layout();

    // Make a second pass with the real height of the operators.
    int operatorHeight = 0;
    for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
        if (current->isRenderMathMLBlock()) {
            RenderMathMLBlock* block = toRenderMathMLBlock(current);
            if (!block->hasBase() && !block->isRenderMathMLOperator()) {
                // Check to see if this box has a larger height.
                if (block->offsetHeight() > maxHeight)
                    maxHeight = block->offsetHeight();
            }
            if (block->isRenderMathMLOperator())
                if (block->offsetHeight() > operatorHeight)
                    operatorHeight = block->offsetHeight();
        } else if (current->isBoxModelObject()) {
            RenderBoxModelObject* box = toRenderBoxModelObject(current);
            // Check to see if this box has a larger height.
            if (box->offsetHeight() > maxHeight)
                maxHeight = box->offsetHeight();
        }
    }
    
    if (childCount > 0 && childCount == operatorCount) {
        // We have only operators and so set the max height to the operator height.
        maxHeight = operatorHeight;
    }
    
    int stretchHeight = maxHeight;
    
    // Stretch the operators again and re-calculate the row height.
    for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
        if (current->isRenderMathMLBlock()) {
            RenderMathMLBlock* block = toRenderMathMLBlock(current);
            if (block->isRenderMathMLOperator()) {
                RenderMathMLOperator* mathop = toRenderMathMLOperator(block);
                mathop->stretchToHeight(stretchHeight);
            } else {
                block->stretchToHeight(stretchHeight);
                RenderBoxModelObject* box = toRenderBoxModelObject(current);
                // Check to see if this box has a larger height
                if (box->offsetHeight() > maxHeight)
                    maxHeight = box->offsetHeight();
            }
        } else if (current->isBoxModelObject()) {
            RenderBoxModelObject* box = toRenderBoxModelObject(current);
            // Check to see if this box has a larger height
            if (box->offsetHeight() > maxHeight)
                maxHeight = box->offsetHeight();
        }
    }

    // Set the maximum height of the row based on the calculations.
    style()->setHeight(Length(maxHeight, Fixed));
    
    // Do the final layout by calling our parent's layout again.
    setNeedsLayoutAndPrefWidthsRecalc();
    markContainingBlocksForLayout();
    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();
}
Beispiel #25
0
void RenderMathMLRow::layout() 
{
    RenderBlock::layout();
    
    LayoutUnit maxHeight = 0;
    int childCount = 0;
    int operatorCount = 0;

    // Calculate the non-operator max height of the row.
    LayoutUnit operatorHeight = 0;
    for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
        childCount++;
        if (current->isRenderMathMLBlock()) {
            RenderMathMLBlock* block = toRenderMathMLBlock(current);
            // Check to see if the non-operator block has a greater height.
            if (!block->hasBase() && !block->isRenderMathMLOperator() && block->offsetHeight() > maxHeight)
                maxHeight = block->offsetHeight();
            if (block->hasBase() && block->nonOperatorHeight() > maxHeight) 
                maxHeight = block->nonOperatorHeight();
            // If the block is an operator, capture the maximum height and increment the count.
            if (block->isRenderMathMLOperator()) {
                if (block->offsetHeight() > operatorHeight)
                    operatorHeight = block->offsetHeight();
                operatorCount++;
            }
        } else if (current->isBoxModelObject()) {
            RenderBoxModelObject* box = toRenderBoxModelObject(current);
            // Check to see if this box has a larger height.
            if (box->offsetHeight() > maxHeight)
                maxHeight = box->offsetHeight();
        }
    }
    
    if (childCount > 0 && childCount == operatorCount) {
        // We have only operators and so set the max height to the operator height.
        maxHeight = operatorHeight;
    }
    
    // Stretch everything to the same height (blocks can ignore the request).
    if (maxHeight > 0) {
        bool didStretch = false;
        for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
            if (current->isRenderMathMLBlock()) {
                RenderMathMLBlock* block = toRenderMathMLBlock(current);
                block->stretchToHeight(maxHeight);
                didStretch = true;
            }
        }
        if (didStretch) {
            setNeedsLayout(true);
            setPreferredLogicalWidthsDirty(true, false);
            RenderBlock::layout();
        }
    }
    
}