Introduce RenderTreeBuilder
[WebKit-https.git] / Source / WebCore / rendering / mathml / RenderMathMLRow.cpp
1 /*
2  * Copyright (C) 2010 Alex Milowski (alex@milowski.com). All rights reserved.
3  * Copyright (C) 2016 Igalia S.L.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "RenderMathMLRow.h"
29
30 #if ENABLE(MATHML)
31
32 #include "MathMLNames.h"
33 #include "MathMLRowElement.h"
34 #include "RenderIterator.h"
35 #include "RenderMathMLOperator.h"
36 #include "RenderMathMLRoot.h"
37 #include <wtf/IsoMallocInlines.h>
38
39 namespace WebCore {
40
41 using namespace MathMLNames;
42
43 WTF_MAKE_ISO_ALLOCATED_IMPL(RenderMathMLRow);
44
45 RenderMathMLRow::RenderMathMLRow(MathMLRowElement& element, RenderStyle&& style)
46     : RenderMathMLBlock(element, WTFMove(style))
47 {
48 }
49
50 MathMLRowElement& RenderMathMLRow::element() const
51 {
52     return static_cast<MathMLRowElement&>(nodeForNonAnonymous());
53 }
54
55 std::optional<int> RenderMathMLRow::firstLineBaseline() const
56 {
57     auto* baselineChild = firstChildBox();
58     if (!baselineChild)
59         return std::optional<int>();
60
61     return std::optional<int>(static_cast<int>(lroundf(ascentForChild(*baselineChild) + baselineChild->logicalTop())));
62 }
63
64 void RenderMathMLRow::computeLineVerticalStretch(LayoutUnit& ascent, LayoutUnit& descent)
65 {
66     for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
67         if (is<RenderMathMLBlock>(child)) {
68             auto* renderOperator = downcast<RenderMathMLBlock>(child)->unembellishedOperator();
69             if (renderOperator && renderOperator->isStretchy())
70                 continue;
71         }
72
73         child->layoutIfNeeded();
74
75         LayoutUnit childHeightAboveBaseline = ascentForChild(*child);
76         LayoutUnit childDepthBelowBaseline = child->logicalHeight() - childHeightAboveBaseline;
77
78         ascent = std::max(ascent, childHeightAboveBaseline);
79         descent = std::max(descent, childDepthBelowBaseline);
80     }
81
82     // We ensure a minimal stretch size.
83     if (ascent + descent <= 0) {
84         ascent = style().computedFontPixelSize();
85         descent = 0;
86     }
87 }
88
89 void RenderMathMLRow::computePreferredLogicalWidths()
90 {
91     ASSERT(preferredLogicalWidthsDirty());
92
93     m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
94
95     LayoutUnit preferredWidth = 0;
96     for (auto* child = firstChildBox(); child; child = child->nextSiblingBox())
97         preferredWidth += child->maxPreferredLogicalWidth() + child->marginLogicalWidth();
98
99     m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = preferredWidth + borderAndPaddingLogicalWidth();
100
101     setPreferredLogicalWidthsDirty(false);
102 }
103
104 void RenderMathMLRow::layoutRowItems(LayoutUnit& ascent, LayoutUnit& descent)
105 {
106     // We first stretch the vertical operators.
107     // For inline formulas, we can then calculate the logical width.
108     LayoutUnit width = borderAndPaddingStart();
109     for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
110         if (child->isOutOfFlowPositioned())
111             continue;
112
113         if (is<RenderMathMLBlock>(child)) {
114             auto renderOperator = downcast<RenderMathMLBlock>(child)->unembellishedOperator();
115             if (renderOperator && renderOperator->isStretchy() && renderOperator->isVertical())
116                 renderOperator->stretchTo(ascent, descent);
117         }
118
119         child->layoutIfNeeded();
120
121         width += child->marginStart() + child->logicalWidth() + child->marginEnd();
122     }
123
124     width += borderEnd() + paddingEnd();
125     if ((!isRenderMathMLMath() || style().display() == INLINE))
126         setLogicalWidth(width);
127
128     LayoutUnit verticalOffset = borderTop() + paddingTop();
129     LayoutUnit maxAscent = 0, maxDescent = 0; // Used baseline alignment.
130     LayoutUnit horizontalOffset = borderAndPaddingStart();
131     bool shouldFlipHorizontal = !style().isLeftToRightDirection();
132     for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
133         if (child->isOutOfFlowPositioned()) {
134             child->containingBlock()->insertPositionedObject(*child);
135             continue;
136         }
137         LayoutUnit childHorizontalExtent = child->logicalWidth();
138         LayoutUnit ascent = ascentForChild(*child);
139         LayoutUnit descent = child->verticalMarginExtent() + child->logicalHeight() - ascent;
140         maxAscent = std::max(maxAscent, ascent);
141         maxDescent = std::max(maxDescent, descent);
142         LayoutUnit childVerticalMarginBoxExtent = maxAscent + maxDescent;
143
144         horizontalOffset += child->marginStart();
145
146         setLogicalHeight(std::max(logicalHeight(), verticalOffset + borderBottom() + paddingBottom() + childVerticalMarginBoxExtent + horizontalScrollbarHeight()));
147
148         LayoutPoint childLocation(shouldFlipHorizontal ? logicalWidth() - horizontalOffset - childHorizontalExtent : horizontalOffset, verticalOffset + child->marginTop());
149         child->setLocation(childLocation);
150
151         horizontalOffset += childHorizontalExtent + child->marginEnd();
152     }
153
154     LayoutUnit centerBlockOffset = 0;
155     if (style().display() == BLOCK)
156         centerBlockOffset = std::max<LayoutUnit>(0, (logicalWidth() - (horizontalOffset + borderEnd() + paddingEnd())) / 2);
157
158     if (shouldFlipHorizontal && centerBlockOffset > 0)
159         centerBlockOffset = -centerBlockOffset;
160
161     for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
162         LayoutUnit ascent = ascentForChild(*child);
163         LayoutUnit startOffset = maxAscent - ascent;
164         child->setLocation(child->location() + LayoutPoint(centerBlockOffset, startOffset));
165     }
166
167     ascent = maxAscent;
168     descent = maxDescent;
169 }
170
171 void RenderMathMLRow::layoutBlock(bool relayoutChildren, LayoutUnit)
172 {
173     ASSERT(needsLayout());
174
175     if (!relayoutChildren && simplifiedLayout())
176         return;
177
178     LayoutUnit ascent = 0;
179     LayoutUnit descent = 0;
180     computeLineVerticalStretch(ascent, descent);
181
182     recomputeLogicalWidth();
183
184     setLogicalHeight(borderAndPaddingLogicalHeight() + scrollbarLogicalHeight());
185
186     layoutRowItems(ascent, descent);
187
188     updateLogicalHeight();
189
190     layoutPositionedObjects(relayoutChildren);
191
192     clearNeedsLayout();
193 }
194
195 }
196
197 #endif // ENABLE(MATHML)