Overflow of formulas is hidden for display mathematics
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 29 Jan 2018 06:35:57 +0000 (06:35 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 29 Jan 2018 06:35:57 +0000 (06:35 +0000)
https://bugs.webkit.org/show_bug.cgi?id=160547

Patch by Minsheng Liu <lambda@liu.ms> on 2018-01-28
Reviewed by Frédéric Wang.

Source/WebCore:

Previously, <math> with display="block" uses its container's logical width as logical width.
However, that behavior will truncate overflowed contents. The patch fixes it by setting
the logical width as its content width rather than its container's logical width
if the former is wider than the latter.

Test: mathml/presentation/display-math-horizontal-overflow.html

* rendering/mathml/RenderMathMLRow.cpp:
(WebCore::RenderMathMLRow::layoutBlock):

LayoutTests:

Add a test to ensure <math> with display="block" will not truncate overflowed contents.

* mathml/presentation/display-math-horizontal-overflow-expected.txt: Added.
* mathml/presentation/display-math-horizontal-overflow.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@227722 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/mathml/presentation/math-inline-display-width-expected.txt [new file with mode: 0644]
LayoutTests/mathml/presentation/math-inline-display-width.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/mathml/RenderMathMLMath.cpp
Source/WebCore/rendering/mathml/RenderMathMLMath.h
Source/WebCore/rendering/mathml/RenderMathMLRow.cpp

index 084ce38..7a808eb 100644 (file)
@@ -1,3 +1,15 @@
+2018-01-28  Minsheng Liu  <lambda@liu.ms>
+
+        Overflow of formulas is hidden for display mathematics
+        https://bugs.webkit.org/show_bug.cgi?id=160547
+
+        Reviewed by Frédéric Wang.
+
+        Add a test to ensure <math> with display="block" will not truncate overflowed contents.
+
+        * mathml/presentation/display-math-horizontal-overflow-expected.txt: Added.
+        * mathml/presentation/display-math-horizontal-overflow.html: Added.
+
 2018-01-28  Zan Dobersek  <zdobersek@igalia.com>
 
         Unreviewed WPE gardening.
diff --git a/LayoutTests/mathml/presentation/math-inline-display-width-expected.txt b/LayoutTests/mathml/presentation/math-inline-display-width-expected.txt
new file mode 100644 (file)
index 0000000..919f7dd
--- /dev/null
@@ -0,0 +1,14 @@
+Inline math of 100px content in a 200px container. The test passes if the bar is to the left of the container.
+
+Display math of 100px content in a 200px container. The test passes if the bar is in the middle of the container.
+
+Inline math of 400px content in a 200px container. The test passes if the bar can be scrolled horizontally to see the full content.
+
+Display math of 400px content in a 200px container. The test passes if the bar behaves exactly the same as the previous one.
+
+
+PASS inline math, 100px content, 200px container 
+PASS display math, 100px content, 200px container 
+PASS inline math, 400px content, 200px container 
+PASS display math, 400px content, 200px container 
+
diff --git a/LayoutTests/mathml/presentation/math-inline-display-width.html b/LayoutTests/mathml/presentation/math-inline-display-width.html
new file mode 100644 (file)
index 0000000..bab8bbb
--- /dev/null
@@ -0,0 +1,82 @@
+<!doctype html>
+<html>
+  <head>
+    <title>display math overflow</title>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+    <script>
+      setup({ "explicit_done": true });
+
+      function run() {
+        test(function() {
+          let math = document.getElementById('inline-100');
+          assert_equals(math.clientWidth, 100);
+        }, "inline math, 100px content, 200px container");
+
+        test(function() {
+          let math = document.getElementById('display-100');
+          assert_equals(math.clientWidth, 200);
+
+          let mspace = document.getElementById('space-100');
+
+          let mathBox = math.getBoundingClientRect();
+          let mspaceBox = mspace.getBoundingClientRect();
+          assert_equals(mspaceBox.left - mathBox.left, mathBox.right - mspaceBox.right);
+        }, "display math, 100px content, 200px container");
+
+        test(function() {
+          let math = document.getElementById('inline-400');
+          assert_equals(math.clientWidth, 400);
+        }, "inline math, 400px content, 200px container");
+
+        test(function() {
+          let math = document.getElementById('display-400');
+          assert_equals(math.clientWidth, 400);
+        }, "display math, 400px content, 200px container");
+        done();
+      }
+    </script>
+
+    <style>
+      #test-area div {
+        width: 200px;
+        overflow: hidden;
+        border-style: solid;
+        /* Make sure inline <math> will fill the whole <div> vertically. */
+        line-height: 0;
+      }
+    </style>
+  </head>
+  <body onload="run()">
+
+    <div id="test-area">
+      <p>Inline math of 100px content in a 200px container. The test passes if the bar is to the left of the container.</p>
+      <div>
+        <math id="inline-100" xmlns="http://www.w3.org/1998/Math/MathML">
+          <mspace width="100px" height="50px" style="background: linear-gradient(to right, red, green)"></mspace>
+        </math>
+      </div>
+
+      <p>Display math of 100px content in a 200px container. The test passes if the bar is in the middle of the container.</p>
+      <div>
+        <math id="display-100" display="block" xmlns="http://www.w3.org/1998/Math/MathML">
+          <mspace id="space-100" width="100px" height="50px" style="background: linear-gradient(to right, red, green)"></mspace>
+        </math>
+      </div>
+
+      <p>Inline math of 400px content in a 200px container. The test passes if the bar can be scrolled horizontally to see the full content.</p>
+      <div>
+        <math id="inline-400" xmlns="http://www.w3.org/1998/Math/MathML">
+          <mspace width="400px" height="50px" style="background: linear-gradient(to right, red, green)"></mspace>
+        </math>
+      </div>
+
+      <p>Display math of 400px content in a 200px container. The test passes if the bar behaves exactly the same as the previous one.</p>
+      <div>
+        <math id="display-400" display="block" xmlns="http://www.w3.org/1998/Math/MathML">
+          <mspace width="400px" height="50px" style="background: linear-gradient(to right, red, green)"></mspace>
+        </math>
+      </div>
+    </div>
+  </body>
+</html>
index d59b5af..2189cc5 100644 (file)
@@ -1,3 +1,20 @@
+2018-01-28  Minsheng Liu  <lambda@liu.ms>
+
+        Overflow of formulas is hidden for display mathematics
+        https://bugs.webkit.org/show_bug.cgi?id=160547
+
+        Reviewed by Frédéric Wang.
+
+        Previously, <math> with display="block" uses its container's logical width as logical width.
+        However, that behavior will truncate overflowed contents. The patch fixes it by setting
+        the logical width as its content width rather than its container's logical width
+        if the former is wider than the latter.
+
+        Test: mathml/presentation/display-math-horizontal-overflow.html
+
+        * rendering/mathml/RenderMathMLRow.cpp:
+        (WebCore::RenderMathMLRow::layoutBlock):
+
 2018-01-26  Antoine Quint  <graouts@apple.com>
 
         [Web Animations] Distinguish between an omitted and a null timeline argument to the Animation constructor
index f8d8fa7..cd98236 100644 (file)
@@ -43,6 +43,53 @@ RenderMathMLMath::RenderMathMLMath(MathMLRowElement& element, RenderStyle&& styl
 {
 }
 
+void RenderMathMLMath::centerChildren(LayoutUnit contentWidth)
+{
+    LayoutUnit centerBlockOffset = (logicalWidth() - contentWidth) / 2;
+    if (!style().isLeftToRightDirection())
+        centerBlockOffset = -centerBlockOffset;
+    for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
+        if (!child->isOutOfFlowPositioned())
+            child->setLocation(child->location() + LayoutPoint(centerBlockOffset, 0));
+    }
+}
+
+void RenderMathMLMath::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
+{
+    ASSERT(needsLayout());
+
+    if (style().display() != BLOCK) {
+        RenderMathMLRow::layoutBlock(relayoutChildren, pageLogicalHeight);
+        return;
+    }
+
+    if (!relayoutChildren && simplifiedLayout())
+        return;
+
+    recomputeLogicalWidth();
+
+    setLogicalHeight(borderAndPaddingLogicalHeight() + scrollbarLogicalHeight());
+
+    LayoutUnit width, ascent, descent;
+    stretchVerticalOperatorsAndLayoutChildren();
+    getContentBoundingBox(width, ascent, descent);
+    layoutRowItems(logicalWidth(), ascent);
+
+    // Display formulas must be centered horizontally if there is extra space left.
+    // Otherwise, logical width must be updated to the content width to avoid truncation.
+    if (width < logicalWidth())
+        centerChildren(width);
+    else
+        setLogicalWidth(width);
+
+    setLogicalHeight(borderTop() + paddingTop() + ascent + descent + borderBottom() + paddingBottom() + horizontalScrollbarHeight());
+    updateLogicalHeight();
+
+    layoutPositionedObjects(relayoutChildren);
+
+    clearNeedsLayout();
+}
+
 }
 
 #endif // ENABLE(MATHML)
index 8ece511..6084bce 100644 (file)
@@ -41,6 +41,9 @@ public:
 private:
     bool isRenderMathMLMath() const final { return true; }
     const char* renderName() const final { return "RenderMathMLMath"; }
+
+    void centerChildren(LayoutUnit contentWidth);
+    void layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight = 0) final;
 };
 
 }
index b33fd2c..0505ef0 100644 (file)
@@ -171,22 +171,8 @@ void RenderMathMLRow::layoutBlock(bool relayoutChildren, LayoutUnit)
     LayoutUnit width, ascent, descent;
     stretchVerticalOperatorsAndLayoutChildren();
     getContentBoundingBox(width, ascent, descent);
-
-    if (isRenderMathMLMath() && style().display() == BLOCK) {
-        // Display formulas must be centered horizontally.
-        layoutRowItems(logicalWidth(), ascent);
-        LayoutUnit centerBlockOffset = std::max<LayoutUnit>(0, logicalWidth() - width) / 2;
-        if (!style().isLeftToRightDirection())
-            centerBlockOffset = -centerBlockOffset;
-        for (auto* child = firstChildBox(); child; child = child->nextSiblingBox()) {
-            if (!child->isOutOfFlowPositioned())
-                child->setLocation(child->location() + LayoutPoint(centerBlockOffset, 0));
-        }
-    } else {
-        layoutRowItems(width, ascent);
-        setLogicalWidth(width);
-    }
-
+    layoutRowItems(width, ascent);
+    setLogicalWidth(width);
     setLogicalHeight(borderTop() + paddingTop() + ascent + descent + borderBottom() + paddingBottom() + horizontalScrollbarHeight());
     updateLogicalHeight();