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() { 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); }