Title: [226177] trunk/Source/WebCore
Revision
226177
Author
commit-qu...@webkit.org
Date
2017-12-20 06:28:05 -0800 (Wed, 20 Dec 2017)

Log Message

Refactor RenderMathMLFraction to remove members modified during layout
https://bugs.webkit.org/show_bug.cgi?id=180151

Patch by Frederic Wang <fw...@igalia.com> on 2017-12-20
Reviewed by Manuel Rego Casasnovas.

Currently, RenderMathMLFraction has three LayoutUnit members m_defaultLineThickness,
m_lineThickness and m_ascent that are set during layout. In the past such members have caused
MathML rendering bugs due to update issues. This patch refactors the layout of MathML
fractions so that it does not require to store and keep these LayoutUnit members up-to-date.
New helper functions are introduced to perform the simple arithmetic calculations required.

No new tests, behavior unchanged and already covered by existing tests.

* rendering/mathml/RenderMathMLFraction.cpp: We add new helper functions to calculate line
thickness values. This allows to remove updateLineThickness(), m_defaultLineThickness and
m_lineThickness. We also introduce the ascentOverHorizontalAxis() helper function to
calculate the ascent over the middle of its fraction bar or stack gap. This allows to remove
the m_ascent member.
(WebCore::RenderMathMLFraction::defaultLineThickness const): Helper function to calculate
the default thickness of the fraction bar given in the MATH table or a fallback value.
This replaces the use of m_defaultLineThickness.
(WebCore::RenderMathMLFraction::lineThickness const): Helper function to resolve the
actual thickness based on the @linethickness attribute and the default value. This replaces
the use of m_lineThickness.
(WebCore::RenderMathMLFraction::relativeLineThickness const): Rewrite this function using
the new helper functions.
(WebCore::RenderMathMLFraction::fractionParameters const): Make this const and replaces
isStack() with !lineThickness().
(WebCore::RenderMathMLFraction::stackParameters const): Ditto. Also move from layoutBlock
the adjustment of parameters to ensure a minimum gap. Doing so assumes that the fraction is
valid so we add an ASSERT.
(WebCore::RenderMathMLFraction::horizontalOffset const): Make this a const since it does not
mutate anything.
(WebCore::RenderMathMLFraction::ascentOverHorizontalAxis const): Move this code from
layoutBlock() to determine the middle of the stack gap or of the fraction bar. This helper
function replaces m_ascent - mathAxisHeight(). Note that the adjustment of topShiftUp is now
done in stackParameters().
(WebCore::RenderMathMLFraction::layoutBlock): Remove the call to updateLineThickness().
Rely on stackParameters() and ascentOverHorizontalAxis() to perform the necessary calculation
of bottomShiftDown and ascent respectively.
(WebCore::RenderMathMLFraction::paint): Use lineThickness() and ascentOverHorizontalAxis()
instead of m_lineThickness, m_ascent and isStack().
(WebCore::RenderMathMLFraction::firstLineBaseline const): Use ascentOverHorizontalAxis() and
mathAxisHeight() instead of m_ascent.
(WebCore::RenderMathMLFraction::updateLineThickness): Deleted.
* rendering/mathml/RenderMathMLFraction.h: Declare new helper functions for line thickness
values and ascent and remove the old LayoutUnit members. Make horizontalOffset(),
fractionParameter() and stackParameters() const since they do not modify anything and the two
last are used in the const function ascentOverHorizontalAxis(), itself used in
firstLineBaseline().

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (226176 => 226177)


--- trunk/Source/WebCore/ChangeLog	2017-12-20 14:25:50 UTC (rev 226176)
+++ trunk/Source/WebCore/ChangeLog	2017-12-20 14:28:05 UTC (rev 226177)
@@ -1,3 +1,56 @@
+2017-12-20  Frederic Wang  <fw...@igalia.com>
+
+        Refactor RenderMathMLFraction to remove members modified during layout
+        https://bugs.webkit.org/show_bug.cgi?id=180151
+
+        Reviewed by Manuel Rego Casasnovas.
+
+        Currently, RenderMathMLFraction has three LayoutUnit members m_defaultLineThickness,
+        m_lineThickness and m_ascent that are set during layout. In the past such members have caused
+        MathML rendering bugs due to update issues. This patch refactors the layout of MathML
+        fractions so that it does not require to store and keep these LayoutUnit members up-to-date.
+        New helper functions are introduced to perform the simple arithmetic calculations required.
+
+        No new tests, behavior unchanged and already covered by existing tests.
+
+        * rendering/mathml/RenderMathMLFraction.cpp: We add new helper functions to calculate line
+        thickness values. This allows to remove updateLineThickness(), m_defaultLineThickness and
+        m_lineThickness. We also introduce the ascentOverHorizontalAxis() helper function to
+        calculate the ascent over the middle of its fraction bar or stack gap. This allows to remove
+        the m_ascent member.
+        (WebCore::RenderMathMLFraction::defaultLineThickness const): Helper function to calculate
+        the default thickness of the fraction bar given in the MATH table or a fallback value.
+        This replaces the use of m_defaultLineThickness.
+        (WebCore::RenderMathMLFraction::lineThickness const): Helper function to resolve the
+        actual thickness based on the @linethickness attribute and the default value. This replaces
+        the use of m_lineThickness.
+        (WebCore::RenderMathMLFraction::relativeLineThickness const): Rewrite this function using
+        the new helper functions.
+        (WebCore::RenderMathMLFraction::fractionParameters const): Make this const and replaces
+        isStack() with !lineThickness().
+        (WebCore::RenderMathMLFraction::stackParameters const): Ditto. Also move from layoutBlock
+        the adjustment of parameters to ensure a minimum gap. Doing so assumes that the fraction is
+        valid so we add an ASSERT.
+        (WebCore::RenderMathMLFraction::horizontalOffset const): Make this a const since it does not
+        mutate anything.
+        (WebCore::RenderMathMLFraction::ascentOverHorizontalAxis const): Move this code from
+        layoutBlock() to determine the middle of the stack gap or of the fraction bar. This helper
+        function replaces m_ascent - mathAxisHeight(). Note that the adjustment of topShiftUp is now
+        done in stackParameters().
+        (WebCore::RenderMathMLFraction::layoutBlock): Remove the call to updateLineThickness().
+        Rely on stackParameters() and ascentOverHorizontalAxis() to perform the necessary calculation
+        of bottomShiftDown and ascent respectively.
+        (WebCore::RenderMathMLFraction::paint): Use lineThickness() and ascentOverHorizontalAxis()
+        instead of m_lineThickness, m_ascent and isStack().
+        (WebCore::RenderMathMLFraction::firstLineBaseline const): Use ascentOverHorizontalAxis() and
+        mathAxisHeight() instead of m_ascent.
+        (WebCore::RenderMathMLFraction::updateLineThickness): Deleted.
+        * rendering/mathml/RenderMathMLFraction.h: Declare new helper functions for line thickness
+        values and ascent and remove the old LayoutUnit members. Make horizontalOffset(),
+        fractionParameter() and stackParameters() const since they do not modify anything and the two
+        last are used in the const function ascentOverHorizontalAxis(), itself used in
+        firstLineBaseline().
+
 2017-12-20  Carlos Alberto Lopez Perez  <clo...@igalia.com>
 
         [GTK][Clang] Build fix after r226138

Modified: trunk/Source/WebCore/rendering/mathml/RenderMathMLFraction.cpp (226176 => 226177)


--- trunk/Source/WebCore/rendering/mathml/RenderMathMLFraction.cpp	2017-12-20 14:25:50 UTC (rev 226176)
+++ trunk/Source/WebCore/rendering/mathml/RenderMathMLFraction.cpp	2017-12-20 14:28:05 UTC (rev 226177)
@@ -68,25 +68,29 @@
     return *firstChildBox()->nextSiblingBox();
 }
 
-void RenderMathMLFraction::updateLineThickness()
+LayoutUnit RenderMathMLFraction::defaultLineThickness() const
 {
-    // We first determine the default line thickness.
     const auto& primaryFont = style().fontCascade().primaryFont();
-    const auto* mathData = style().fontCascade().primaryFont().mathData();
-    if (mathData)
-        m_defaultLineThickness = mathData->getMathConstant(primaryFont, OpenTypeMathData::FractionRuleThickness);
-    else
-        m_defaultLineThickness = ruleThicknessFallback();
+    if (const auto* mathData = primaryFont.mathData())
+        return mathData->getMathConstant(primaryFont, OpenTypeMathData::FractionRuleThickness);
+    return ruleThicknessFallback();
+}
 
-    // Next we resolve the thickness using m_defaultLineThickness as the default value.
-    m_lineThickness = toUserUnits(element().lineThickness(), style(), m_defaultLineThickness);
-    if (m_lineThickness < 0)
-        m_lineThickness = 0;
+LayoutUnit RenderMathMLFraction::lineThickness() const
+{
+    return std::max<LayoutUnit>(toUserUnits(element().lineThickness(), style(), defaultLineThickness()), 0);
 }
 
-RenderMathMLFraction::FractionParameters RenderMathMLFraction::fractionParameters()
+float RenderMathMLFraction::relativeLineThickness() const
 {
-    ASSERT(!isStack());
+    if (LayoutUnit defaultThickness = defaultLineThickness())
+        return lineThickness() / defaultThickness;
+    return 0;
+}
+
+RenderMathMLFraction::FractionParameters RenderMathMLFraction::fractionParameters() const
+{
+    ASSERT(lineThickness());
     FractionParameters parameters;
 
     // We try and read constants to draw the fraction from the OpenType MATH and use fallback values otherwise.
@@ -111,9 +115,10 @@
     return parameters;
 }
 
-RenderMathMLFraction::StackParameters RenderMathMLFraction::stackParameters()
+RenderMathMLFraction::StackParameters RenderMathMLFraction::stackParameters() const
 {
-    ASSERT(isStack());
+    ASSERT(!lineThickness());
+    ASSERT(isValid());
     StackParameters parameters;
     
     // We try and read constants to draw the stack from the OpenType MATH and use fallback values otherwise.
@@ -133,6 +138,17 @@
         parameters.bottomShiftDown = 0;
     }
 
+    LayoutUnit numeratorAscent = ascentForChild(numerator());
+    LayoutUnit numeratorDescent = numerator().logicalHeight() - numeratorAscent;
+    LayoutUnit denominatorAscent = ascentForChild(denominator());
+    LayoutUnit gap = parameters.topShiftUp - numeratorDescent + parameters.bottomShiftDown - denominatorAscent;
+    if (gap < parameters.gapMin) {
+        // If the gap is not large enough, we increase the shifts by the same value.
+        LayoutUnit delta = (parameters.gapMin - gap) / 2;
+        parameters.topShiftUp += delta;
+        parameters.bottomShiftDown += delta;
+    }
+
     return parameters;
 }
 
@@ -160,7 +176,7 @@
     setPreferredLogicalWidthsDirty(false);
 }
 
-LayoutUnit RenderMathMLFraction::horizontalOffset(RenderBox& child, MathMLFractionElement::FractionAlignment align)
+LayoutUnit RenderMathMLFraction::horizontalOffset(RenderBox& child, MathMLFractionElement::FractionAlignment align) const
 {
     switch (align) {
     case MathMLFractionElement::FractionAlignmentRight:
@@ -175,6 +191,22 @@
     return LayoutUnit(0);
 }
 
+LayoutUnit RenderMathMLFraction::ascentOverHorizontalAxis() const
+{
+    ASSERT(isValid());
+
+    LayoutUnit numeratorAscent = ascentForChild(numerator());
+    if (LayoutUnit thickness = lineThickness()) {
+        // For normal fraction layout, the axis is the middle of the fraction bar.
+        FractionParameters parameters = fractionParameters();
+        return std::max(numerator().logicalHeight() + parameters.numeratorGapMin + thickness / 2, numeratorAscent + parameters.numeratorMinShiftUp);
+    }
+
+    // For stack layout, the axis is the middle of the gap between numerator and denonimator.
+    StackParameters parameters = stackParameters();
+    return numeratorAscent + parameters.topShiftUp;
+}
+
 void RenderMathMLFraction::layoutBlock(bool relayoutChildren, LayoutUnit)
 {
     ASSERT(needsLayout());
@@ -192,38 +224,26 @@
 
     setLogicalWidth(std::max(numerator().logicalWidth(), denominator().logicalWidth()));
 
-    updateLineThickness();
     LayoutUnit verticalOffset = 0; // This is the top of the renderer.
     LayoutPoint numeratorLocation(horizontalOffset(numerator(), element().numeratorAlignment()), verticalOffset);
     numerator().setLocation(numeratorLocation);
 
-    LayoutUnit numeratorAscent = ascentForChild(numerator());
-    LayoutUnit numeratorDescent = numerator().logicalHeight() - numeratorAscent;
     LayoutUnit denominatorAscent = ascentForChild(denominator());
     LayoutUnit denominatorDescent = denominator().logicalHeight() - denominatorAscent;
-    if (isStack()) {
+    LayoutUnit ascent = ascentOverHorizontalAxis();
+    verticalOffset += ascent;
+    if (LayoutUnit thickness = lineThickness()) {
+        FractionParameters parameters = fractionParameters();
+        verticalOffset += std::max(thickness / 2 + parameters.denominatorGapMin, parameters.denominatorMinShiftDown - denominatorAscent);
+    } else {
         StackParameters parameters = stackParameters();
-        LayoutUnit gap = parameters.topShiftUp - numeratorDescent + parameters.bottomShiftDown - denominatorAscent;
-        if (gap < parameters.gapMin) {
-            // If the gap is not large enough, we increase the shifts by the same value.
-            LayoutUnit delta = (parameters.gapMin - gap) / 2;
-            parameters.topShiftUp += delta;
-            parameters.bottomShiftDown += delta;
-        }
-        verticalOffset += numeratorAscent + parameters.topShiftUp; // This is the middle of the stack gap.
-        m_ascent = verticalOffset + mathAxisHeight();
         verticalOffset += parameters.bottomShiftDown - denominatorAscent;
-    } else {
-        FractionParameters parameters = fractionParameters();
-        verticalOffset += std::max(numerator().logicalHeight() + parameters.numeratorGapMin + m_lineThickness / 2, numeratorAscent + parameters.numeratorMinShiftUp); // This is the middle of the fraction bar.
-        m_ascent = verticalOffset + mathAxisHeight();
-        verticalOffset += std::max(m_lineThickness / 2 + parameters.denominatorGapMin, parameters.denominatorMinShiftDown - denominatorAscent);
     }
 
     LayoutPoint denominatorLocation(horizontalOffset(denominator(), element().denominatorAlignment()), verticalOffset);
     denominator().setLocation(denominatorLocation);
 
-    verticalOffset = std::max(verticalOffset + denominator().logicalHeight(), m_ascent + denominatorDescent); // This is the bottom of our renderer.
+    verticalOffset = std::max(verticalOffset + denominator().logicalHeight(), ascent + mathAxisHeight() + denominatorDescent); // This is the bottom of our renderer.
     setLogicalHeight(verticalOffset);
 
     layoutPositionedObjects(relayoutChildren);
@@ -234,14 +254,15 @@
 void RenderMathMLFraction::paint(PaintInfo& info, const LayoutPoint& paintOffset)
 {
     RenderMathMLBlock::paint(info, paintOffset);
-    if (info.context().paintingDisabled() || info.phase != PaintPhaseForeground || style().visibility() != VISIBLE || !isValid() || isStack())
+    LayoutUnit thickness = lineThickness();
+    if (info.context().paintingDisabled() || info.phase != PaintPhaseForeground || style().visibility() != VISIBLE || !isValid() || !thickness)
         return;
 
-    IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location() + LayoutPoint(0, m_ascent - mathAxisHeight()));
+    IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location() + LayoutPoint(0, ascentOverHorizontalAxis()));
 
     GraphicsContextStateSaver stateSaver(info.context());
 
-    info.context().setStrokeThickness(m_lineThickness);
+    info.context().setStrokeThickness(thickness);
     info.context().setStrokeStyle(SolidStroke);
     info.context().setStrokeColor(style().visitedDependentColor(CSSPropertyColor));
     info.context().drawLine(adjustedPaintOffset, roundedIntPoint(LayoutPoint(adjustedPaintOffset.x() + logicalWidth(), adjustedPaintOffset.y())));
@@ -250,7 +271,7 @@
 std::optional<int> RenderMathMLFraction::firstLineBaseline() const
 {
     if (isValid())
-        return std::optional<int>(std::lround(static_cast<float>(m_ascent)));
+        return std::optional<int>(std::lround(static_cast<float>(ascentOverHorizontalAxis() + mathAxisHeight())));
     return RenderMathMLBlock::firstLineBaseline();
 }
 

Modified: trunk/Source/WebCore/rendering/mathml/RenderMathMLFraction.h (226176 => 226177)


--- trunk/Source/WebCore/rendering/mathml/RenderMathMLFraction.h	2017-12-20 14:25:50 UTC (rev 226176)
+++ trunk/Source/WebCore/rendering/mathml/RenderMathMLFraction.h	2017-12-20 14:28:05 UTC (rev 226177)
@@ -41,7 +41,9 @@
 public:
     RenderMathMLFraction(MathMLFractionElement&, RenderStyle&&);
 
-    float relativeLineThickness() const { return m_defaultLineThickness ? m_lineThickness / m_defaultLineThickness : LayoutUnit(0); }
+    LayoutUnit defaultLineThickness() const;
+    LayoutUnit lineThickness() const;
+    float relativeLineThickness() const;
 
 private:
     bool isRenderMathMLFraction() const final { return true; }
@@ -55,12 +57,10 @@
 
     MathMLFractionElement& element() const { return static_cast<MathMLFractionElement&>(nodeForNonAnonymous()); }
 
-    bool isStack() const { return !m_lineThickness; }
     bool isValid() const;
     RenderBox& numerator() const;
     RenderBox& denominator() const;
-    LayoutUnit horizontalOffset(RenderBox&, MathMLFractionElement::FractionAlignment);
-    void updateLineThickness();
+    LayoutUnit horizontalOffset(RenderBox&, MathMLFractionElement::FractionAlignment) const;
     struct FractionParameters {
         LayoutUnit numeratorGapMin;
         LayoutUnit denominatorGapMin;
@@ -67,17 +67,14 @@
         LayoutUnit numeratorMinShiftUp;
         LayoutUnit denominatorMinShiftDown;
     };
-    FractionParameters fractionParameters();
+    FractionParameters fractionParameters() const;
     struct StackParameters {
         LayoutUnit gapMin;
         LayoutUnit topShiftUp;
         LayoutUnit bottomShiftDown;
     };
-    StackParameters stackParameters();
-
-    LayoutUnit m_ascent;
-    LayoutUnit m_defaultLineThickness { 1 };
-    LayoutUnit m_lineThickness;
+    StackParameters stackParameters() const;
+    LayoutUnit ascentOverHorizontalAxis() const;
 };
 
 } // namespace WebCore
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to