Commit d01e1075 authored by Frédéric Wang's avatar Frédéric Wang Committed by Commit Bot

[mathml] Use post.underlineThickness for the default fraction rulethickness

MathML Core currently defines fallback values to use when no MATH table
is available. This CL performs the remaining work to ensure fractions
align with the specification. It also adds WPT test to check these
fraction fallback parameters, although testing them extensively is
difficult.

Bug: 6606, 1058369
Change-Id: Ic916c0c4b925674d526d78989988e57d8735bf4e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2410384
Commit-Queue: Frédéric Wang <fwang@igalia.com>
Reviewed-by: default avatarIan Kilpatrick <ikilpatrick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#807083}
parent cca43ca1
......@@ -31,10 +31,12 @@ bool IsValidMathMLFraction(const NGBlockNode&);
bool IsValidMathMLScript(const NGBlockNode&);
bool IsValidMathMLRadical(const NGBlockNode&);
// https://mathml-refresh.github.io/mathml-core/#dfn-default-rule-thickness
inline float RuleThicknessFallback(const ComputedStyle& style) {
// This function returns a value for the default rule thickness (TeX's
// \xi_8) to be used as a fallback when we lack a MATH table.
return 0.05f * style.FontSize();
const SimpleFontData* font_data = style.GetFont().PrimaryFont();
if (!font_data)
return 0;
return font_data->GetFontMetrics().UnderlineThickness().value_or(0);
}
LayoutUnit MathAxisHeight(const ComputedStyle& style);
......
......@@ -1270,6 +1270,10 @@ crbug.com/6606 external/wpt/mathml/relations/html5-tree/href-click-1.html [ Fail
crbug.com/6606 external/wpt/mathml/relations/html5-tree/href-click-2.html [ Failure ]
crbug.com/6606 external/wpt/mathml/relations/html5-tree/href-click-3.html [ Failure ]
# This test fails on win10. It should really be made more reliable and take into
# account fallback parameters.
crbug.com/6606 [ Win10 ] external/wpt/mathml/presentation-markup/fractions/frac-1.html [ Failure ]
# This test fails on macOS.
crbug.com/6606 [ Mac ] external/wpt/mathml/relations/text-and-math/use-typo-metrics-1.html [ Failure ]
......
......@@ -10,8 +10,12 @@
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/mathml/support/feature-detection.js"></script>
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<style>
math, mspace {
/* OS/2.sxHeight = 800 */
/* post.underlineThickness == 20 */
font-family: Ahem;
font-size: 10px;
}
div.shrink-wrap {
......@@ -22,9 +26,9 @@
}
</style>
<script>
/* This test does not use any specific fonts and so the exact rules are not
specified precisely. We assume reasonable values for numerator/denominator
shifts and spacing. */
const xHeight = 800;
const underlineThickness = 800;
const emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
function getBox(aId) {
var box = document.getElementById(aId).getBoundingClientRect();
......@@ -33,22 +37,15 @@
return box;
}
function getFractionAxis(aId) {
return (getBox(aId).top * den.height + getBox(aId).bottom * num.height) / (num.height + den.height);
}
setup({ explicit_done: true });
window.addEventListener("load", runTests);
window.addEventListener("load", () => { document.fonts.ready.then(runTests); });
function runTests() {
test(function() {
assert_true(MathMLFeatureDetection.has_mspace());
var e = 3;
var mathAxis = getBox("axis").middle;
// For stacks, nothing in the OpenType MATH specification seems to ensure
// that the gap is split symmetrically around the math axis so we only
// do the following verification for standard fractions.
var e = 4;
var mathAxis = getBox("baseline").top - (xHeight/2) * emToPx;
for (var i = 0; i <= 4; i++) {
var frac = getBox("frac" + i);
var num = getBox("frac" + i + "num");
......@@ -65,7 +62,7 @@
assert_true(MathMLFeatureDetection.has_mspace());
for (var i = 0; i < 10; i++) {
assert_less_than(getBox("frac" + i + "num").bottom, getBox("frac" + i + "den").top, "numerator is above denominator");
assert_less_than_equal(getBox("frac" + i + "num").bottom, getBox("frac" + i + "den").top, "numerator is above denominator");
assert_less_than(getBox("frac" + i + "den").top - getBox("frac" + i + "num").bottom, 5, "The gap between numerator and denominator is not too large");
}
}, "Vertical positions of numerator and denominator");
......@@ -114,7 +111,7 @@
<div id="log"></div>
<p>
<math>
<mo id="axis"></mo>
<mspace id="baseline" width="1em" height="0em" depth="1em" style="background: black"/>
<mfrac id="frac0">
<mspace id="frac0num" width="15px" height="15px" style="background: blue"/>
<mspace id="frac0den" width="15px" height="15px" style="background: green"/>
......
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Fraction/Stack parameters (fallback)</title>
<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#fractions-mfrac">
<meta name="assert" content="Element mfrac correctly uses the fraction fallback parameters.">
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/mathml/support/feature-detection.js"></script>
<style>
/* Testing fallback values is tricky as we don't have a lot of flexibility to
make sure one parameter is not shadowed by another one. We also use the
Ahem font here, so can't really play with the fallback values involved. */
math, mspace {
font-size: 200px; /* Large value because underlineThickness is small */
}
math {
/* OS/2.sxHeight = 800 */
/* post.underlineThickness == 20 */
font-family: Ahem;
}
</style>
<script>
const emToPx = 200 / 1000; // font-size: 200px, font.em = 1000
const epsilon = 1;
const xHeight = 800;
const underlineThickness = 20;
// NB: This test assumes the fallback shifts are all equal to zero.
const axisHeight = xHeight / 2;
const fractionRuleThickness = underlineThickness;
const fractionNumeratorGapMin = underlineThickness;
const fractionDenominatorGapMin = underlineThickness;
const fractionNumeratorDisplayStyleGapMin = 3 * underlineThickness;
const fractionDenominatorDisplayStyleGapMin = 3 * underlineThickness;
const stackGapMin = 3 * underlineThickness;
const stackDisplayStyleGapMin = 7 * underlineThickness;
function getBox(aId) {
return document.getElementById(aId).getBoundingClientRect();
}
setup({ explicit_done: true });
window.addEventListener("load", () => { document.fonts.ready.then(runTests); });
function runTests() {
test(function() {
assert_true(MathMLFeatureDetection.has_mspace());
assert_approx_equals(axisHeight * emToPx,
(getBox("ref0001").top -
getBox("num0001").bottom) -
(fractionRuleThickness/2 +
fractionNumeratorGapMin) * emToPx,
epsilon);
assert_approx_equals((getBox("den0002").top -
getBox("num0002").bottom),
(fractionNumeratorGapMin +
fractionRuleThickness +
fractionDenominatorGapMin) * emToPx,
epsilon);
}, "nonzero linethickness, displaystyle=false");
test(function() {
assert_true(MathMLFeatureDetection.has_mspace());
assert_approx_equals(axisHeight * emToPx,
(getBox("ref0003").top -
getBox("num0003").bottom) -
(fractionRuleThickness/2 +
fractionNumeratorDisplayStyleGapMin) * emToPx,
epsilon, "mfrac: thickness, axis height");
assert_approx_equals((getBox("den0004").top -
getBox("num0004").bottom),
(fractionNumeratorDisplayStyleGapMin +
fractionRuleThickness +
fractionDenominatorDisplayStyleGapMin) * emToPx,
epsilon);
}, "nonzero linethickness, displaystyle=true");
test(function() {
assert_true(MathMLFeatureDetection.has_mspace());
assert_approx_equals((getBox("ref1001").top -
getBox("num1001").bottom),
stackGapMin/2 * emToPx,
epsilon);
assert_approx_equals((getBox("den1001").top) -
getBox("ref1001").top,
stackGapMin/2 * emToPx,
epsilon);
}, "linethickness=0, displaystyle=false");
test(function() {
assert_true(MathMLFeatureDetection.has_mspace());
assert_approx_equals((getBox("ref1002").top -
getBox("num1002").bottom),
stackDisplayStyleGapMin/2 * emToPx,
epsilon);
assert_approx_equals((getBox("den1002").top) -
getBox("ref1002").top,
stackDisplayStyleGapMin/2 * emToPx,
epsilon);
}, "linethickness=0, displaystyle=true");
done();
}
</script>
</head>
<body>
<div id="log"></div>
<p>
<math>
<mspace id="ref0001" height="0em" depth="1em" width="1em" style="background: green"/>
<mfrac>
<mspace width="1em" height="2em" depth="0em" id="num0001" style="background: blue"/>
<mspace width="1em" height="0em" depth="2em" id="den0001" style="background: purple"/>
</mfrac>
</math>
</p>
<p>
<math>
<mfrac>
<mspace width="1em" height="2em" depth="4em" id="num0002" style="background: blue"/>
<mspace width="1em" height="4em" depth="2em" id="den0002" style="background: purple"/>
</mfrac>
</math>
</p>
<hr/>
<p>
<math displaystyle="true">
<mspace id="ref0003" height="0em" depth="1em" width="1em" style="background: green"/>
<mfrac>
<mspace width="1em" height="2em" depth="0em" id="num0003" style="background: blue"/>
<mspace width="1em" height="0em" depth="2em" id="den0003" style="background: purple"/>
</mfrac>
</math>
</p>
<p>
<math displaystyle="true">
<mfrac>
<mspace width="1em" height="2em" depth="4em" id="num0004" style="background: blue"/>
<mspace width="1em" height="4em" depth="2em" id="den0004" style="background: purple"/>
</mfrac>
</math>
</p>
<hr/>
<p>
<math>
<mspace id="ref1001" height="0em" depth="1em" width="1em" style="background: green"/>
<mfrac linethickness="0">
<mspace width="1em" height="2em" depth="0em" id="num1001" style="background: blue"/>
<mspace width="1em" height="0em" depth="2em" id="den1001" style="background: purple"/>
</mfrac>
</math>
</p>
<hr/>
<p>
<math displaystyle="true">
<mspace id="ref1002" height="0em" depth="1em" width="1em" style="background: green"/>
<mfrac linethickness="0">
<mspace width="1em" height="2em" depth="0em" id="num1002" style="background: blue"/>
<mspace width="1em" height="0em" depth="2em" id="den1002" style="background: purple"/>
</mfrac>
</math>
</p>
</body>
</html>
......@@ -8,8 +8,10 @@
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/mathml/support/feature-detection.js"></script>
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<style>
math, mspace, mo {
font-family: Ahem;
font-size: 10px;
}
</style>
......@@ -26,7 +28,7 @@
}
setup({ explicit_done: true });
window.addEventListener("load", runTests);
window.addEventListener("load", () => { document.fonts.ready.then(runTests); });
function runTests() {
test(function() {
......@@ -85,13 +87,13 @@
test(function() {
assert_true(MathMLFeatureDetection.has_mspace());
var e = 3.2;
var e = 4;
for (var i = 0; i <= 3; i++) {
assert_approx_equals(getBox("under" + i).height, getBox("under" + i + "base").height + getBox("under" + i + "under").height + e, e, "munder " + i + ": height is determined by the sum of heights of base and script plus some spacing.");
assert_approx_equals(getBox("over" + i).height, getBox("over" + i + "base").height + getBox("over" + i + "over").height + e, e, "mover " + i + ": height is determined by the sum of heights of base and script plus some spacing.");
assert_approx_equals(getBox("under" + i).height, getBox("under" + i + "base").height + getBox("under" + i + "under").height, e, "munder " + i + ": height is determined by the sum of heights of base and script plus some spacing.");
assert_approx_equals(getBox("over" + i).height, getBox("over" + i + "base").height + getBox("over" + i + "over").height, e, "mover " + i + ": height is determined by the sum of heights of base and script plus some spacing.");
}
for (var i = 0; i <= 5; i++) {
assert_approx_equals(getBox("underover" + i).height, getBox("underover" + i + "base").height + getBox("underover" + i + "under").height + getBox("underover" + i + "over").height + e, e, "munderover " + i + ": height is determined by the sum heights of base and scripts");
assert_approx_equals(getBox("underover" + i).height, getBox("underover" + i + "base").height + getBox("underover" + i + "under").height + getBox("underover" + i + "over").height, e, "munderover " + i + ": height is determined by the sum heights of base and scripts");
}
}, "Height of scripted elements");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment