예제 #1
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();
}
예제 #2
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();
}
예제 #3
0
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);
}