RenderMathMLRow.cpp [plain text]
#include "config.h"
#include "RenderMathMLRow.h"
#if ENABLE(MATHML)
#include "MathMLNames.h"
#include "MathMLRowElement.h"
#include "RenderIterator.h"
#include "RenderMathMLOperator.h"
#include "RenderMathMLRoot.h"
#include <wtf/IsoMallocInlines.h>
namespace WebCore {
using namespace MathMLNames;
WTF_MAKE_ISO_ALLOCATED_IMPL(RenderMathMLRow);
RenderMathMLRow::RenderMathMLRow(MathMLRowElement& element, RenderStyle&& style)
: RenderMathMLBlock(element, WTFMove(style))
{
}
MathMLRowElement& RenderMathMLRow::element() const
{
return static_cast<MathMLRowElement&>(nodeForNonAnonymous());
}
std::optional<int> RenderMathMLRow::firstLineBaseline() const
{
auto* baselineChild = firstChildBox();
if (!baselineChild)
return std::optional<int>();
return std::optional<int>(static_cast<int>(lroundf(ascentForChild(*baselineChild) + baselineChild->logicalTop())));
}
static RenderMathMLOperator* toVerticalStretchyOperator(RenderBox* box)
{
if (is<RenderMathMLBlock>(box)) {
auto* renderOperator = downcast<RenderMathMLBlock>(*box).unembellishedOperator();
if (renderOperator && renderOperator->isStretchy() && renderOperator->isVertical())
return renderOperator;
}
return nullptr;
}
void RenderMathMLRow::stretchVerticalOperatorsAndLayoutChildren()
{
LayoutUnit stretchAscent, stretchDescent;
for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
if (child->isOutOfFlowPositioned()) {
child->containingBlock()->insertPositionedObject(*child);
continue;
}
if (toVerticalStretchyOperator(child))
continue;
child->layoutIfNeeded();
LayoutUnit childAscent = ascentForChild(*child);
LayoutUnit childDescent = child->logicalHeight() - childAscent;
stretchAscent = std::max(stretchAscent, childAscent);
stretchDescent = std::max(stretchDescent, childDescent);
}
if (stretchAscent + stretchDescent <= 0) {
stretchAscent = style().computedFontPixelSize();
stretchDescent = 0;
}
for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
if (child->isOutOfFlowPositioned())
continue;
if (auto renderOperator = toVerticalStretchyOperator(child)) {
renderOperator->stretchTo(stretchAscent, stretchDescent);
renderOperator->layoutIfNeeded();
}
}
}
void RenderMathMLRow::getContentBoundingBox(LayoutUnit& width, LayoutUnit& ascent, LayoutUnit& descent) const
{
ascent = 0;
descent = 0;
width = borderAndPaddingStart();
for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
if (child->isOutOfFlowPositioned())
continue;
width += child->marginStart() + child->logicalWidth() + child->marginEnd();
LayoutUnit childAscent = ascentForChild(*child);
LayoutUnit childDescent = child->logicalHeight() - childAscent;
ascent = std::max(ascent, childAscent + child->marginTop());
descent = std::max(descent, childDescent + child->marginBottom());
}
width += borderEnd() + paddingEnd();
}
void RenderMathMLRow::computePreferredLogicalWidths()
{
ASSERT(preferredLogicalWidthsDirty());
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
LayoutUnit preferredWidth = 0;
for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
if (child->isOutOfFlowPositioned())
continue;
preferredWidth += child->maxPreferredLogicalWidth() + child->marginLogicalWidth();
}
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = preferredWidth + borderAndPaddingLogicalWidth();
setPreferredLogicalWidthsDirty(false);
}
void RenderMathMLRow::layoutRowItems(LayoutUnit width, LayoutUnit ascent)
{
LayoutUnit horizontalOffset = borderAndPaddingStart();
for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
if (child->isOutOfFlowPositioned())
continue;
horizontalOffset += child->marginStart();
LayoutUnit childAscent = ascentForChild(*child);
LayoutUnit childVerticalOffset = borderTop() + paddingTop() + child->marginTop() + ascent - childAscent;
LayoutUnit childWidth = child->logicalWidth();
LayoutUnit childHorizontalOffset = style().isLeftToRightDirection() ? horizontalOffset : width - horizontalOffset - childWidth;
child->setLocation(LayoutPoint(childHorizontalOffset, childVerticalOffset));
horizontalOffset += childWidth + child->marginEnd();
}
}
void RenderMathMLRow::layoutBlock(bool relayoutChildren, LayoutUnit)
{
ASSERT(needsLayout());
if (!relayoutChildren && simplifiedLayout())
return;
recomputeLogicalWidth();
setLogicalHeight(borderAndPaddingLogicalHeight() + scrollbarLogicalHeight());
LayoutUnit width, ascent, descent;
stretchVerticalOperatorsAndLayoutChildren();
getContentBoundingBox(width, ascent, descent);
if (isRenderMathMLMath() && style().display() == BLOCK) {
layoutRowItems(logicalWidth(), ascent);
LayoutUnit centerBlockOffset = std::max<LayoutUnit>(0, logicalWidth() - width) / 2;
if (!style().isLeftToRightDirection())
centerBlockOffset = -centerBlockOffset;
for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
if (!child->isOutOfFlowPositioned())
child->setLocation(child->location() + LayoutPoint(centerBlockOffset, 0));
}
} else {
layoutRowItems(width, ascent);
setLogicalWidth(width);
}
setLogicalHeight(borderTop() + paddingTop() + ascent + descent + borderBottom() + paddingBottom() + horizontalScrollbarHeight());
updateLogicalHeight();
layoutPositionedObjects(relayoutChildren);
clearNeedsLayout();
}
}
#endif // ENABLE(MATHML)