| /* |
| * 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 |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #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<LayoutUnit> RenderMathMLRow::firstLineBaseline() const |
| { |
| auto* baselineChild = firstChildBox(); |
| if (!baselineChild) |
| return std::optional<LayoutUnit>(); |
| |
| return LayoutUnit { 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() |
| { |
| // First calculate stretch ascent and descent. |
| 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) { |
| // We ensure a minimal stretch size. |
| stretchAscent = style().computedFontPixelSize(); |
| stretchDescent = 0; |
| } |
| |
| // Next, we stretch the vertical operators. |
| for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) { |
| if (child->isOutOfFlowPositioned()) |
| continue; |
| if (auto renderOperator = toVerticalStretchyOperator(child)) { |
| renderOperator->stretchTo(stretchAscent, stretchDescent); |
| renderOperator->layoutIfNeeded(); |
| child->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; |
| 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); |
| layoutRowItems(width, ascent); |
| setLogicalWidth(width); |
| setLogicalHeight(borderTop() + paddingTop() + ascent + descent + borderBottom() + paddingBottom() + horizontalScrollbarHeight()); |
| updateLogicalHeight(); |
| |
| layoutPositionedObjects(relayoutChildren); |
| |
| updateScrollInfoAfterLayout(); |
| |
| clearNeedsLayout(); |
| } |
| |
| } |
| |
| #endif // ENABLE(MATHML) |