| Differences between
and this patch
- a/Source/WebCore/ChangeLog +55 lines
Lines 1-3 a/Source/WebCore/ChangeLog_sec1
1
2017-12-20  Frederic Wang  <fwang@igalia.com>
2
3
        Split layout of RenderMathMLRow into smaller steps
4
        https://bugs.webkit.org/show_bug.cgi?id=180348
5
6
        Reviewed by Manuel Rego Casasnovas.
7
8
        Currently, RenderMathMLRow mixes too many steps in the same layout functions: layout children,
9
        calculate stretch size, stretch vertical operators, calculate final ascent/descent, handle
10
        out-of-flow positioned children, set logical height, set logical width for non-display
11
        <math> tag, center display <math> tag etc This situation is inherited from the old flexbox
12
        implementation but it makes difficult to read the code and to re-use layout & metrics
13
        calculation for follow-up work on <mrow>-like elements (<menclose>, <mapdded>, <msqrt> or
14
        <math>). See for example bug 160547 for <math> or bug 161126 for <menclose>.
15
        This patch rewrites RenderMathMLRow into smaller steps:
16
        - stretchVerticalOperatorsAndLayoutChildren() which calls layoutIfNeeded() or
17
        insertPositionedObject() on children and stretch vertical operators.
18
        - getContentBoundingBox() to determine the metrics of the mrow-like element without calling
19
        layout on children or positioning them, so that we can improve mrow-like element in the
20
        future.
21
        - layoutRowItems() which sets the position of children.
22
23
        Setting the logical width/height or centering children is now moved into layoutBlock() since
24
        derived class overriding layoutBlock() will do their own adjustment for width, height and
25
        positions.
26
27
        Test: mathml/mrow-preferred-width-with-out-of-flow-child.html
28
        The rest of the behavior is unchanged and already covered by existing tests.
29
30
        * rendering/mathml/RenderMathMLMenclose.cpp:
31
        (WebCore::RenderMathMLMenclose::layoutBlock): Use the new function and get contentWidth
32
        directly from getContentBoundingBox().
33
        * rendering/mathml/RenderMathMLPadded.cpp:
34
        (WebCore::RenderMathMLPadded::layoutBlock): Ditto.
35
        * rendering/mathml/RenderMathMLRoot.cpp:
36
        (WebCore::RenderMathMLRoot::layoutBlock): Ditto, also remove useless statement
37
        baseAscent = baseDescent.
38
        * rendering/mathml/RenderMathMLRow.cpp:
39
        (WebCore::toVerticalStretchyOperator): New helper function to cast to a vertical stretchy
40
        operator.
41
        (WebCore::RenderMathMLRow::stretchVerticalOperatorsAndLayoutChildren): New helper function
42
        to ensure layoutIfNeeded()/insertPositionedObject() is called on children and that the
43
        vertical operators are stretched.
44
        (WebCore::RenderMathMLRow::getContentBoundingBox const): New helper function to determine
45
        the width/ascent/descent to use for the mrow content.
46
        (WebCore::RenderMathMLRow::computePreferredLogicalWidths): Skip out-of-flow children in the
47
        preferred width calculation. This is verified by the new test.
48
        (WebCore::RenderMathMLRow::layoutRowItems): Only keep the positioning of children with the
49
        specified width and ascent.
50
        (WebCore::RenderMathMLRow::layoutBlock): Center children for <math display="block"> tag and
51
        set the logical width in other cases. Also set the logical height here.
52
        (WebCore::RenderMathMLRow::computeLineVerticalStretch): Deleted. This work is included in
53
        stretchVerticalOperatorsAndLayoutChildren() now.
54
        * rendering/mathml/RenderMathMLRow.h: Update declaration of functions.
55
1
2017-12-20  Ms2ger  <Ms2ger@igalia.com>
56
2017-12-20  Ms2ger  <Ms2ger@igalia.com>
2
57
3
        REGRESSION(r226160) Build broken when MEDIA_STREAM is disabled with MediaStreamRequest namespace confusion
58
        REGRESSION(r226160) Build broken when MEDIA_STREAM is disabled with MediaStreamRequest namespace confusion
- a/Source/WebCore/rendering/mathml/RenderMathMLMenclose.cpp -5 / +4 lines
Lines 173-183 void RenderMathMLMenclose::layoutBlock(bool relayoutChildren, LayoutUnit) a/Source/WebCore/rendering/mathml/RenderMathMLMenclose.cpp_sec1
173
    if (!relayoutChildren && simplifiedLayout())
173
    if (!relayoutChildren && simplifiedLayout())
174
        return;
174
        return;
175
175
176
    LayoutUnit contentAscent = 0;
176
    LayoutUnit contentWidth, contentAscent, contentDescent;
177
    LayoutUnit contentDescent = 0;
177
    stretchVerticalOperatorsAndLayoutChildren();
178
    RenderMathMLRow::computeLineVerticalStretch(contentAscent, contentDescent);
178
    getContentBoundingBox(contentWidth, contentAscent, contentDescent);
179
    RenderMathMLRow::layoutRowItems(contentAscent, contentDescent);
179
    layoutRowItems(contentWidth, contentAscent);
180
    LayoutUnit contentWidth = logicalWidth();
181
180
182
    SpaceAroundContent space = spaceAroundContent(contentWidth, contentAscent + contentDescent);
181
    SpaceAroundContent space = spaceAroundContent(contentWidth, contentAscent + contentDescent);
183
    setLogicalWidth(space.left + contentWidth + space.right);
182
    setLogicalWidth(space.left + contentWidth + space.right);
- a/Source/WebCore/rendering/mathml/RenderMathMLPadded.cpp -5 / +4 lines
Lines 90-100 void RenderMathMLPadded::layoutBlock(bool relayoutChildren, LayoutUnit) a/Source/WebCore/rendering/mathml/RenderMathMLPadded.cpp_sec1
90
        return;
90
        return;
91
91
92
    // We first layout our children as a normal <mrow> element.
92
    // We first layout our children as a normal <mrow> element.
93
    LayoutUnit contentAscent, contentDescent, contentWidth;
93
    LayoutUnit contentWidth, contentAscent, contentDescent;
94
    contentAscent = contentDescent = 0;
94
    stretchVerticalOperatorsAndLayoutChildren();
95
    RenderMathMLRow::computeLineVerticalStretch(contentAscent, contentDescent);
95
    getContentBoundingBox(contentWidth, contentAscent, contentDescent);
96
    RenderMathMLRow::layoutRowItems(contentAscent, contentDescent);
96
    layoutRowItems(contentWidth, contentAscent);
97
    contentWidth = logicalWidth();
98
97
99
    // We parse the mpadded attributes using the content metrics as the default value.
98
    // We parse the mpadded attributes using the content metrics as the default value.
100
    LayoutUnit width = mpaddedWidth(contentWidth);
99
    LayoutUnit width = mpaddedWidth(contentWidth);
- a/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp -4 / +3 lines
Lines 201-210 void RenderMathMLRoot::layoutBlock(bool relayoutChildren, LayoutUnit) a/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp_sec1
201
    LayoutUnit baseAscent, baseDescent;
201
    LayoutUnit baseAscent, baseDescent;
202
    recomputeLogicalWidth();
202
    recomputeLogicalWidth();
203
    if (rootType() == RootType::SquareRoot) {
203
    if (rootType() == RootType::SquareRoot) {
204
        baseAscent = baseDescent;
204
        stretchVerticalOperatorsAndLayoutChildren();
205
        RenderMathMLRow::computeLineVerticalStretch(baseAscent, baseDescent);
205
        getContentBoundingBox(m_baseWidth, baseAscent, baseDescent);
206
        RenderMathMLRow::layoutRowItems(baseAscent, baseDescent);
206
        layoutRowItems(m_baseWidth, baseAscent);
207
        m_baseWidth = logicalWidth();
208
    } else {
207
    } else {
209
        getBase().layoutIfNeeded();
208
        getBase().layoutIfNeeded();
210
        m_baseWidth = getBase().logicalWidth();
209
        m_baseWidth = getBase().logicalWidth();
- a/Source/WebCore/rendering/mathml/RenderMathMLRow.cpp -80 / +83 lines
Lines 61-89 std::optional<int> RenderMathMLRow::firstLineBaseline() const a/Source/WebCore/rendering/mathml/RenderMathMLRow.cpp_sec1
61
    return std::optional<int>(static_cast<int>(lroundf(ascentForChild(*baselineChild) + baselineChild->logicalTop())));
61
    return std::optional<int>(static_cast<int>(lroundf(ascentForChild(*baselineChild) + baselineChild->logicalTop())));
62
}
62
}
63
63
64
void RenderMathMLRow::computeLineVerticalStretch(LayoutUnit& ascent, LayoutUnit& descent)
64
static RenderMathMLOperator* toVerticalStretchyOperator(RenderBox* box)
65
{
65
{
66
    if (is<RenderMathMLBlock>(box)) {
67
        auto* renderOperator = downcast<RenderMathMLBlock>(*box).unembellishedOperator();
68
        if (renderOperator && renderOperator->isStretchy() && renderOperator->isVertical())
69
            return renderOperator;
70
    }
71
    return nullptr;
72
}
73
74
void RenderMathMLRow::stretchVerticalOperatorsAndLayoutChildren()
75
{
76
    // First calculate stretch ascent and descent.
77
    LayoutUnit stretchAscent, stretchDescent;
66
    for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
78
    for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
67
        if (is<RenderMathMLBlock>(child)) {
79
        if (child->isOutOfFlowPositioned()) {
68
            auto* renderOperator = downcast<RenderMathMLBlock>(child)->unembellishedOperator();
80
            child->containingBlock()->insertPositionedObject(*child);
69
            if (renderOperator && renderOperator->isStretchy())
81
            continue;
70
                continue;
71
        }
82
        }
72
83
        if (toVerticalStretchyOperator(child))
84
            continue;
73
        child->layoutIfNeeded();
85
        child->layoutIfNeeded();
86
        LayoutUnit childAscent = ascentForChild(*child);
87
        LayoutUnit childDescent = child->logicalHeight() - childAscent;
88
        stretchAscent = std::max(stretchAscent, childAscent);
89
        stretchDescent = std::max(stretchDescent, childDescent);
90
    }
91
    if (stretchAscent + stretchDescent <= 0) {
92
        // We ensure a minimal stretch size.
93
        stretchAscent = style().computedFontPixelSize();
94
        stretchDescent = 0;
95
    }
74
96
75
        LayoutUnit childHeightAboveBaseline = ascentForChild(*child);
97
    // Next, we stretch the vertical operators.
76
        LayoutUnit childDepthBelowBaseline = child->logicalHeight() - childHeightAboveBaseline;
98
    for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
77
99
        if (child->isOutOfFlowPositioned())
78
        ascent = std::max(ascent, childHeightAboveBaseline);
100
            continue;
79
        descent = std::max(descent, childDepthBelowBaseline);
101
        if (auto renderOperator = toVerticalStretchyOperator(child)) {
102
            renderOperator->stretchTo(stretchAscent, stretchDescent);
103
            renderOperator->layoutIfNeeded();
104
        }
80
    }
105
    }
106
}
107
108
void RenderMathMLRow::getContentBoundingBox(LayoutUnit& width, LayoutUnit& ascent, LayoutUnit& descent) const
109
{
110
    ascent = 0;
111
    descent = 0;
112
    width = borderAndPaddingStart();
113
    for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
114
        if (child->isOutOfFlowPositioned())
115
            continue;
81
116
82
    // We ensure a minimal stretch size.
117
        width += child->marginStart() + child->logicalWidth() + child->marginEnd();
83
    if (ascent + descent <= 0) {
118
        LayoutUnit childAscent = ascentForChild(*child);
84
        ascent = style().computedFontPixelSize();
119
        LayoutUnit childDescent = child->logicalHeight() - childAscent;
85
        descent = 0;
120
        ascent = std::max(ascent, childAscent + child->marginTop());
121
        descent = std::max(descent, childDescent + child->marginBottom());
86
    }
122
    }
123
    width += borderEnd() + paddingEnd();
87
}
124
}
88
125
89
void RenderMathMLRow::computePreferredLogicalWidths()
126
void RenderMathMLRow::computePreferredLogicalWidths()
Lines 93-171 void RenderMathMLRow::computePreferredLogicalWidths() a/Source/WebCore/rendering/mathml/RenderMathMLRow.cpp_sec2
93
    m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
130
    m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
94
131
95
    LayoutUnit preferredWidth = 0;
132
    LayoutUnit preferredWidth = 0;
96
    for (auto* child = firstChildBox(); child; child = child->nextSiblingBox())
133
    for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
134
        if (child->isOutOfFlowPositioned())
135
            continue;
97
        preferredWidth += child->maxPreferredLogicalWidth() + child->marginLogicalWidth();
136
        preferredWidth += child->maxPreferredLogicalWidth() + child->marginLogicalWidth();
137
    }
98
138
99
    m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = preferredWidth + borderAndPaddingLogicalWidth();
139
    m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = preferredWidth + borderAndPaddingLogicalWidth();
100
140
101
    setPreferredLogicalWidthsDirty(false);
141
    setPreferredLogicalWidthsDirty(false);
102
}
142
}
103
143
104
void RenderMathMLRow::layoutRowItems(LayoutUnit& ascent, LayoutUnit& descent)
144
void RenderMathMLRow::layoutRowItems(LayoutUnit width, LayoutUnit ascent)
105
{
145
{
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();
146
    LayoutUnit horizontalOffset = borderAndPaddingStart();
131
    bool shouldFlipHorizontal = !style().isLeftToRightDirection();
132
    for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
147
    for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
133
        if (child->isOutOfFlowPositioned()) {
148
        if (child->isOutOfFlowPositioned())
134
            child->containingBlock()->insertPositionedObject(*child);
135
            continue;
149
            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();
150
        horizontalOffset += child->marginStart();
145
151
        LayoutUnit childAscent = ascentForChild(*child);
146
        setLogicalHeight(std::max(logicalHeight(), verticalOffset + borderBottom() + paddingBottom() + childVerticalMarginBoxExtent + horizontalScrollbarHeight()));
152
        LayoutUnit childVerticalOffset = borderTop() + paddingTop() + child->marginTop() + ascent - childAscent;
147
153
        LayoutUnit childWidth = child->logicalWidth();
148
        LayoutPoint childLocation(shouldFlipHorizontal ? logicalWidth() - horizontalOffset - childHorizontalExtent : horizontalOffset, verticalOffset + child->marginTop());
154
        LayoutUnit childHorizontalOffset = style().isLeftToRightDirection() ? horizontalOffset : width - horizontalOffset - childWidth;
149
        child->setLocation(childLocation);
155
        child->setLocation(LayoutPoint(childHorizontalOffset, childVerticalOffset));
150
156
        horizontalOffset += childWidth + child->marginEnd();
151
        horizontalOffset += childHorizontalExtent + child->marginEnd();
152
    }
157
    }
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
}
158
}
170
159
171
void RenderMathMLRow::layoutBlock(bool relayoutChildren, LayoutUnit)
160
void RenderMathMLRow::layoutBlock(bool relayoutChildren, LayoutUnit)
Lines 175-190 void RenderMathMLRow::layoutBlock(bool relayoutChildren, LayoutUnit) a/Source/WebCore/rendering/mathml/RenderMathMLRow.cpp_sec3
175
    if (!relayoutChildren && simplifiedLayout())
164
    if (!relayoutChildren && simplifiedLayout())
176
        return;
165
        return;
177
166
178
    LayoutUnit ascent = 0;
179
    LayoutUnit descent = 0;
180
    computeLineVerticalStretch(ascent, descent);
181
182
    recomputeLogicalWidth();
167
    recomputeLogicalWidth();
183
168
184
    setLogicalHeight(borderAndPaddingLogicalHeight() + scrollbarLogicalHeight());
169
    setLogicalHeight(borderAndPaddingLogicalHeight() + scrollbarLogicalHeight());
185
170
186
    layoutRowItems(ascent, descent);
171
    LayoutUnit width, ascent, descent;
172
    stretchVerticalOperatorsAndLayoutChildren();
173
    getContentBoundingBox(width, ascent, descent);
174
175
    if (isRenderMathMLMath() && style().display() == BLOCK) {
176
        // Display formulas must be centered horizontally.
177
        layoutRowItems(logicalWidth(), ascent);
178
        LayoutUnit centerBlockOffset = std::max<LayoutUnit>(0, logicalWidth() - width) / 2;
179
        if (!style().isLeftToRightDirection())
180
            centerBlockOffset = -centerBlockOffset;
181
        for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
182
            if (!child->isOutOfFlowPositioned())
183
                child->setLocation(child->location() + LayoutPoint(centerBlockOffset, 0));
184
        }
185
    } else {
186
        layoutRowItems(width, ascent);
187
        setLogicalWidth(width);
188
    }
187
189
190
    setLogicalHeight(borderTop() + paddingTop() + ascent + descent + borderBottom() + paddingBottom() + horizontalScrollbarHeight());
188
    updateLogicalHeight();
191
    updateLogicalHeight();
189
192
190
    layoutPositionedObjects(relayoutChildren);
193
    layoutPositionedObjects(relayoutChildren);
- a/Source/WebCore/rendering/mathml/RenderMathMLRow.h -2 / +3 lines
Lines 44-51 protected: a/Source/WebCore/rendering/mathml/RenderMathMLRow.h_sec1
44
    void layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight = 0) override;
44
    void layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight = 0) override;
45
    std::optional<int> firstLineBaseline() const override;
45
    std::optional<int> firstLineBaseline() const override;
46
46
47
    void layoutRowItems(LayoutUnit& ascent, LayoutUnit& descent);
47
    void stretchVerticalOperatorsAndLayoutChildren();
48
    void computeLineVerticalStretch(LayoutUnit& ascent, LayoutUnit& descent);
48
    void getContentBoundingBox(LayoutUnit& width, LayoutUnit& ascent, LayoutUnit& descent) const;
49
    void layoutRowItems(LayoutUnit width, LayoutUnit ascent);
49
    void computePreferredLogicalWidths() override;
50
    void computePreferredLogicalWidths() override;
50
51
51
private:
52
private:
- a/LayoutTests/ChangeLog +13 lines
Lines 1-3 a/LayoutTests/ChangeLog_sec1
1
2017-12-20  Frederic Wang  <fwang@igalia.com>
2
3
        Split layout of RenderMathMLRow into smaller steps
4
        https://bugs.webkit.org/show_bug.cgi?id=180348
5
6
        Reviewed by Manuel Rego Casasnovas.
7
8
        New test to verify that out-of-flow positioned children are not taken into account in the
9
        calculation of the preferred width of the mrow element.
10
11
        * mathml/mrow-preferred-width-with-out-of-flow-child-expected.html: Added.
12
        * mathml/mrow-preferred-width-with-out-of-flow-child.html: Added.
13
1
2017-12-20  Ms2ger  <Ms2ger@igalia.com>
14
2017-12-20  Ms2ger  <Ms2ger@igalia.com>
2
15
3
        Make fast/css-generated-content/quotes-lang.html pass on GTK
16
        Make fast/css-generated-content/quotes-lang.html pass on GTK
- a/LayoutTests/mathml/mrow-preferred-width-with-out-of-flow-child-expected.html +21 lines
Line 0 a/LayoutTests/mathml/mrow-preferred-width-with-out-of-flow-child-expected.html_sec1
1
<!DOCTYPE html>
2
<html>
3
  <head>
4
    <title>mrow preferred width with out-of-flow child</title>
5
  </head>
6
  <body>
7
8
    <p>This test passes if the absolute positioned child is not taken in account in the preferred width computation. You'll see a blue rectangle of about 100px width.</p>
9
10
    <table>
11
      <tr>
12
        <td style="background: blue">
13
          <math>
14
            <mspace width="100px"></mspace>
15
          </math>
16
        </td>
17
      </tr>
18
    </table>
19
20
  </body>
21
</html>
- a/LayoutTests/mathml/mrow-preferred-width-with-out-of-flow-child.html +22 lines
Line 0 a/LayoutTests/mathml/mrow-preferred-width-with-out-of-flow-child.html_sec1
1
<!DOCTYPE html>
2
<html>
3
  <head>
4
    <title>mrow preferred width with out-of-flow child</title>
5
  </head>
6
  <body>
7
8
    <p>This test passes if the absolute positioned child is not taken in account in the preferred width computation. You'll see a blue rectangle of about 100px width.</p>
9
10
    <table>
11
      <tr>
12
        <td style="background: blue">
13
          <math>
14
            <mspace style="position: absolute;" width="100px"></mspace>
15
            <mspace width="100px"></mspace>
16
          </math>
17
        </td>
18
      </tr>
19
    </table>
20
21
  </body>
22
</html>

Return to Bug 180348