diff options
Diffstat (limited to 'Source/WebCore/rendering/mathml/RenderMathMLRow.cpp')
-rw-r--r-- | Source/WebCore/rendering/mathml/RenderMathMLRow.cpp | 162 |
1 files changed, 134 insertions, 28 deletions
diff --git a/Source/WebCore/rendering/mathml/RenderMathMLRow.cpp b/Source/WebCore/rendering/mathml/RenderMathMLRow.cpp index 02ef296cd..c4bebc2a2 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLRow.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLRow.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 Alex Milowski (alex@milowski.com). All rights reserved. + * Copyright (C) 2016 Igalia S.L. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,12 +25,12 @@ */ #include "config.h" +#include "RenderMathMLRow.h" #if ENABLE(MATHML) -#include "RenderMathMLRow.h" - #include "MathMLNames.h" +#include "MathMLRowElement.h" #include "RenderIterator.h" #include "RenderMathMLOperator.h" #include "RenderMathMLRoot.h" @@ -38,47 +39,152 @@ namespace WebCore { using namespace MathMLNames; -RenderMathMLRow::RenderMathMLRow(Element& element, PassRef<RenderStyle> style) - : RenderMathMLBlock(element, std::move(style)) +RenderMathMLRow::RenderMathMLRow(MathMLRowElement& element, RenderStyle&& style) + : RenderMathMLBlock(element, WTFMove(style)) { } -RenderMathMLRow::RenderMathMLRow(Document& document, PassRef<RenderStyle> style) - : RenderMathMLBlock(document, std::move(style)) +MathMLRowElement& RenderMathMLRow::element() const { + return static_cast<MathMLRowElement&>(nodeForNonAnonymous()); } -RenderPtr<RenderMathMLRow> RenderMathMLRow::createAnonymousWithParentRenderer(RenderMathMLRoot& parent) +std::optional<int> RenderMathMLRow::firstLineBaseline() const { - RenderPtr<RenderMathMLRow> newMRow = createRenderer<RenderMathMLRow>(parent.document(), RenderStyle::createAnonymousStyleWithDisplay(&parent.style(), FLEX)); - newMRow->initializeStyle(); - return newMRow; + auto* baselineChild = firstChildBox(); + if (!baselineChild) + return std::optional<int>(); + + return std::optional<int>(static_cast<int>(lroundf(ascentForChild(*baselineChild) + baselineChild->logicalTop()))); } -void RenderMathMLRow::layout() +void RenderMathMLRow::computeLineVerticalStretch(LayoutUnit& ascent, LayoutUnit& descent) { - int stretchLogicalHeight = 0; - for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { - if (child->needsLayout()) - toRenderElement(child)->layout(); - // FIXME: Only skip renderMo if it is stretchy. - if (child->isRenderMathMLBlock() && toRenderMathMLBlock(child)->unembellishedOperator()) + for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) { + if (is<RenderMathMLBlock>(child)) { + auto* renderOperator = downcast<RenderMathMLBlock>(child)->unembellishedOperator(); + if (renderOperator && renderOperator->isStretchy()) + continue; + } + + child->layoutIfNeeded(); + + LayoutUnit childHeightAboveBaseline = ascentForChild(*child); + LayoutUnit childDepthBelowBaseline = child->logicalHeight() - childHeightAboveBaseline; + + ascent = std::max(ascent, childHeightAboveBaseline); + descent = std::max(descent, childDepthBelowBaseline); + } + + // We ensure a minimal stretch size. + if (ascent + descent <= 0) { + ascent = style().fontSize(); + descent = 0; + } +} + +void RenderMathMLRow::computePreferredLogicalWidths() +{ + ASSERT(preferredLogicalWidthsDirty()); + + m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0; + + LayoutUnit preferredWidth = 0; + for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) + preferredWidth += child->maxPreferredLogicalWidth() + child->marginLogicalWidth(); + + m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = preferredWidth + borderAndPaddingLogicalWidth(); + + setPreferredLogicalWidthsDirty(false); +} + +void RenderMathMLRow::layoutRowItems(LayoutUnit& ascent, LayoutUnit& descent) +{ + // We first stretch the vertical operators. + // For inline formulas, we can then calculate the logical width. + LayoutUnit width = borderAndPaddingStart(); + for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) { + if (child->isOutOfFlowPositioned()) continue; - if (child->isBox()) - stretchLogicalHeight = std::max<int>(stretchLogicalHeight, roundToInt(toRenderBox(child)->logicalHeight())); + + if (is<RenderMathMLBlock>(child)) { + auto renderOperator = downcast<RenderMathMLBlock>(child)->unembellishedOperator(); + if (renderOperator && renderOperator->isStretchy() && renderOperator->isVertical()) + renderOperator->stretchTo(ascent, descent); + } + + child->layoutIfNeeded(); + + width += child->marginStart() + child->logicalWidth() + child->marginEnd(); } - if (!stretchLogicalHeight) - stretchLogicalHeight = style().fontSize(); - - // Set the sizes of (possibly embellished) stretchy operator children. - for (auto& child : childrenOfType<RenderMathMLBlock>(*this)) { - if (auto renderMo = child.unembellishedOperator()) { - if (renderMo->stretchHeight() != stretchLogicalHeight) - renderMo->stretchToHeight(stretchLogicalHeight); + + width += borderEnd() + paddingEnd(); + if ((!isRenderMathMLMath() || style().display() == INLINE)) + setLogicalWidth(width); + + LayoutUnit verticalOffset = borderTop() + paddingTop(); + LayoutUnit maxAscent = 0, maxDescent = 0; // Used baseline alignment. + LayoutUnit horizontalOffset = borderAndPaddingStart(); + bool shouldFlipHorizontal = !style().isLeftToRightDirection(); + for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) { + if (child->isOutOfFlowPositioned()) { + child->containingBlock()->insertPositionedObject(*child); + continue; } + LayoutUnit childHorizontalExtent = child->logicalWidth(); + LayoutUnit ascent = ascentForChild(*child); + LayoutUnit descent = child->verticalMarginExtent() + child->logicalHeight() - ascent; + maxAscent = std::max(maxAscent, ascent); + maxDescent = std::max(maxDescent, descent); + LayoutUnit childVerticalMarginBoxExtent = maxAscent + maxDescent; + + horizontalOffset += child->marginStart(); + + setLogicalHeight(std::max(logicalHeight(), verticalOffset + borderBottom() + paddingBottom() + childVerticalMarginBoxExtent + horizontalScrollbarHeight())); + + LayoutPoint childLocation(shouldFlipHorizontal ? logicalWidth() - horizontalOffset - childHorizontalExtent : horizontalOffset, verticalOffset + child->marginTop()); + child->setLocation(childLocation); + + horizontalOffset += childHorizontalExtent + child->marginEnd(); } - RenderMathMLBlock::layout(); + LayoutUnit centerBlockOffset = 0; + if (style().display() == BLOCK) + centerBlockOffset = std::max<LayoutUnit>(0, (logicalWidth() - (horizontalOffset + borderEnd() + paddingEnd())) / 2); + + if (shouldFlipHorizontal && centerBlockOffset > 0) + centerBlockOffset = -centerBlockOffset; + + for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) { + LayoutUnit ascent = ascentForChild(*child); + LayoutUnit startOffset = maxAscent - ascent; + child->setLocation(child->location() + LayoutPoint(centerBlockOffset, startOffset)); + } + + ascent = maxAscent; + descent = maxDescent; +} + +void RenderMathMLRow::layoutBlock(bool relayoutChildren, LayoutUnit) +{ + ASSERT(needsLayout()); + + if (!relayoutChildren && simplifiedLayout()) + return; + + LayoutUnit ascent = 0; + LayoutUnit descent = 0; + computeLineVerticalStretch(ascent, descent); + + recomputeLogicalWidth(); + + setLogicalHeight(borderAndPaddingLogicalHeight() + scrollbarLogicalHeight()); + + layoutRowItems(ascent, descent); + + updateLogicalHeight(); + + clearNeedsLayout(); } } |