Bug 1912435 - Make MathML boolean attributes ASCII case-insensitive. r=emilio

This commit ensures MathML boolean attributes (namely displaystyle,
mo@stretchy, mo@symmetric, mo@largeop, mo@movablelimits,
munder@accentunder, mover@accent, munderover@accent,
munderover@accentunder) are ASCII case-insensitive [1]. For
displaystyle that was handled in [2]. For mover/munder/munderover
attributes, this is covered by a test case from scriptlevel-001.html
checking both case-insensitivity and dynamic changes at the same time ;
the latter still seems broken, so these checks are moved into separate
test cases. For mo attributes, a new WPT test is added. Note that
mo@accent, mo@fence, mo@separator are not part of MathML Core (with the
two last without visual effect), we make them case-insensitive for
consistency but don't bother adding tests for them.

[1] https://w3c.github.io/mathml-core/#dfn-boolean used here:
[2] https://bugzilla.mozilla.org/show_bug.cgi?id=1574087

Differential Revision: https://phabricator.services.mozilla.com/D218944
This commit is contained in:
Frédéric Wang
2024-09-02 13:59:59 +00:00
parent 91080ecb36
commit fe0998d618
6 changed files with 148 additions and 31 deletions

View File

@@ -237,17 +237,19 @@ void nsMathMLmoFrame::ProcessOperatorData() {
// see if the accent attribute is there
mContent->AsElement()->GetAttr(nsGkAtoms::accent_, value);
if (value.EqualsLiteral("true"))
if (value.LowerCaseEqualsLiteral("true")) {
mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENT;
else if (value.EqualsLiteral("false"))
} else if (value.LowerCaseEqualsLiteral("false")) {
mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENT;
}
// see if the movablelimits attribute is there
mContent->AsElement()->GetAttr(nsGkAtoms::movablelimits_, value);
if (value.EqualsLiteral("true"))
if (value.LowerCaseEqualsLiteral("true")) {
mEmbellishData.flags |= NS_MATHML_EMBELLISH_MOVABLELIMITS;
else if (value.EqualsLiteral("false"))
} else if (value.LowerCaseEqualsLiteral("false")) {
mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_MOVABLELIMITS;
}
// ---------------------------------------------------------------------
// we will be called again to re-sync the rest of our state next time...
@@ -444,36 +446,39 @@ void nsMathMLmoFrame::ProcessOperatorData() {
// don't process them here
mContent->AsElement()->GetAttr(nsGkAtoms::stretchy_, value);
if (value.EqualsLiteral("false")) {
if (value.LowerCaseEqualsLiteral("false")) {
mFlags &= ~NS_MATHML_OPERATOR_STRETCHY;
} else if (value.EqualsLiteral("true")) {
} else if (value.LowerCaseEqualsLiteral("true")) {
mFlags |= NS_MATHML_OPERATOR_STRETCHY;
}
if (NS_MATHML_OPERATOR_IS_FENCE(mFlags)) {
mContent->AsElement()->GetAttr(nsGkAtoms::fence_, value);
if (value.EqualsLiteral("false"))
if (value.LowerCaseEqualsLiteral("false")) {
mFlags &= ~NS_MATHML_OPERATOR_FENCE;
else
} else {
mEmbellishData.flags |= NS_MATHML_EMBELLISH_FENCE;
}
}
mContent->AsElement()->GetAttr(nsGkAtoms::largeop_, value);
if (value.EqualsLiteral("false")) {
if (value.LowerCaseEqualsLiteral("false")) {
mFlags &= ~NS_MATHML_OPERATOR_LARGEOP;
} else if (value.EqualsLiteral("true")) {
} else if (value.LowerCaseEqualsLiteral("true")) {
mFlags |= NS_MATHML_OPERATOR_LARGEOP;
}
if (NS_MATHML_OPERATOR_IS_SEPARATOR(mFlags)) {
mContent->AsElement()->GetAttr(nsGkAtoms::separator_, value);
if (value.EqualsLiteral("false"))
if (value.LowerCaseEqualsLiteral("false")) {
mFlags &= ~NS_MATHML_OPERATOR_SEPARATOR;
else
} else {
mEmbellishData.flags |= NS_MATHML_EMBELLISH_SEPARATOR;
}
}
mContent->AsElement()->GetAttr(nsGkAtoms::symmetric_, value);
if (value.EqualsLiteral("false"))
if (value.LowerCaseEqualsLiteral("false")) {
mFlags &= ~NS_MATHML_OPERATOR_SYMMETRIC;
else if (value.EqualsLiteral("true"))
} else if (value.LowerCaseEqualsLiteral("true")) {
mFlags |= NS_MATHML_OPERATOR_SYMMETRIC;
}
// minsize
//

View File

@@ -223,9 +223,9 @@ XXX The winner is the outermost setting in conflicting settings like these:
// if we have an accentunder attribute, it overrides what the underscript
// said
if (mContent->AsElement()->GetAttr(nsGkAtoms::accentunder_, value)) {
if (value.EqualsLiteral("true")) {
if (value.LowerCaseEqualsLiteral("true")) {
mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTUNDER;
} else if (value.EqualsLiteral("false")) {
} else if (value.LowerCaseEqualsLiteral("false")) {
mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTUNDER;
}
}
@@ -244,9 +244,9 @@ XXX The winner is the outermost setting in conflicting settings like these:
// if we have an accent attribute, it overrides what the overscript said
if (mContent->AsElement()->GetAttr(nsGkAtoms::accent_, value)) {
if (value.EqualsLiteral("true")) {
if (value.LowerCaseEqualsLiteral("true")) {
mEmbellishData.flags |= NS_MATHML_EMBELLISH_ACCENTOVER;
} else if (value.EqualsLiteral("false")) {
} else if (value.LowerCaseEqualsLiteral("false")) {
mEmbellishData.flags &= ~NS_MATHML_EMBELLISH_ACCENTOVER;
}
}

View File

@@ -1,3 +1,3 @@
[scriptlevel-001.html]
[checking dynamic/case-insensitive accent/accentunder]
[checking dynamic accent/accentunder]
expected: FAIL

View File

@@ -0,0 +1,45 @@
<!DOCTYPE html>
<meta charset="utf-8"/>
<title>Test case insensitivity of mo boolean attributes (reference)</title>
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<style>
math {
font: 25px/1 Ahem;
}
@font-face {
font-family: operators;
src: url("/fonts/math/operators.woff");
}
mo {
font-family: operators;
}
</style>
<p>
<math>
<mrow>
<mo symmetric="false" stretchy="false"></mo>
<mspace height="2em"></mspace>
</mrow>
</math>
</p>
<p>
<math>
<mrow>
<mo symmetric="true" stretchy="true"></mo>
<mspace height="1.5em"></mspace>
</mrow>
</math>
</p>
<p>
<math displaystyle="true">
<mo largeop="false"></mo>
</math>
</p>
<p>
<math>
<munder>
<mo movablelimits="false"></mo>
<mtext>X</mtext>
</munder>
</math>
</p>

View File

@@ -0,0 +1,51 @@
<!DOCTYPE html>
<meta charset="utf-8"/>
<title>Test case insensitivity of mo boolean attributes</title>
<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript">
<meta name="assert" content="Verifies case insensitivity of mo boolean attributes.">
<link rel="match" href="mo-boolean-attributes-case-insensitive-ref.html">
<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
<style>
math {
font: 25px/1 Ahem;
}
@font-face {
font-family: operators;
src: url("/fonts/math/operators.woff");
}
mo {
font-family: operators;
}
</style>
<p>
<math>
<mrow>
<mo symmetric="false" stretchy="FaLsE"></mo>
<mspace height="2em"></mspace>
</mrow>
</math>
</p>
<p>
<math>
<mrow>
<mo symmetric="TrUe" stretchy="true"></mo>
<mspace height="1.5em"></mspace>
</mrow>
</math>
</p>
<p>
<math displaystyle="true">
<mo largeop="FALSe"></mo>
</math>
</p>
<p>
<math>
<munder>
<mo movablelimits="fALse"></mo>
<mtext>X</mtext>
</munder>
</math>
</p>
<script src="/mathml/support/feature-detection.js"></script>
<script>MathMLFeatureDetection.ensure_for_match_reftest("has_munderover");</script>

View File

@@ -55,43 +55,50 @@
});
test(function() {
var element = document.querySelector("munder[accentunder='true']");
var element = document.getElementById("munder-accentunder")
assert_approx_equals(fontSize(element.children[0]), fontSizeAtScriptLevelZero, epsilon, "base");
assert_approx_equals(fontSize(element.children[1]), fontSizeAtScriptLevelZero, epsilon, "under");
}, `automatic scriptlevel on munder (accentunder=true)`);
test(function() {
var element = document.querySelector("mover[accent='true']");
var element = document.getElementById("mover-accent")
assert_approx_equals(fontSize(element.children[0]), fontSizeAtScriptLevelZero, epsilon, "base");
assert_approx_equals(fontSize(element.children[1]), fontSizeAtScriptLevelZero, epsilon, "over");
}, `automatic scriptlevel on mover (accent=true)`);
test(function() {
var element = document.querySelector("munderover[accentunder='true']");
var element = document.getElementById("munderover-accentunder")
assert_approx_equals(fontSize(element.children[0]), fontSizeAtScriptLevelZero, epsilon, "base");
assert_approx_equals(fontSize(element.children[1]), fontSizeAtScriptLevelZero, epsilon, "under");
assert_approx_equals(fontSize(element.children[2]), fontSizeAtScriptLevelZero * .71, epsilon, "over");
}, `automatic scriptlevel on munderover (accentunder=true)`);
test(function() {
var element = document.querySelector("munderover[accent='true']");
var element = document.getElementById("munderover-accent")
assert_approx_equals(fontSize(element.children[0]), fontSizeAtScriptLevelZero, epsilon, "base");
assert_approx_equals(fontSize(element.children[1]), fontSizeAtScriptLevelZero * .71, epsilon, "under");
assert_approx_equals(fontSize(element.children[2]), fontSizeAtScriptLevelZero, epsilon, "over");
}, `automatic scriptlevel on munderover (accent=true)`);
test(function() {
var element = document.getElementById("munderover-dynamic-case-insensitive")
var element = document.getElementById("munderover-case-insensitive")
assert_approx_equals(fontSize(element.children[0]), fontSizeAtScriptLevelZero, epsilon, "base");
assert_approx_equals(fontSize(element.children[1]), fontSizeAtScriptLevelZero, epsilon, "under");
assert_approx_equals(fontSize(element.children[2]), fontSizeAtScriptLevelZero, epsilon, "over");
}, "checking case-insensitivity accent/accentunder");
test(function() {
var element = document.getElementById("munderover-dynamic")
assert_approx_equals(fontSize(element.children[0]), fontSizeAtScriptLevelZero, epsilon, "base");
assert_approx_equals(fontSize(element.children[1]), fontSizeAtScriptLevelZero * .71, epsilon, "under");
assert_approx_equals(fontSize(element.children[2]), fontSizeAtScriptLevelZero, epsilon, "over");
element.removeAttribute("accent");
element.setAttribute("accentunder", "TrUe");
element.setAttribute("accentunder", "true");
assert_approx_equals(fontSize(element.children[0]), fontSizeAtScriptLevelZero, epsilon, "base");
assert_approx_equals(fontSize(element.children[1]), fontSizeAtScriptLevelZero, epsilon, "under");
assert_approx_equals(fontSize(element.children[2]), fontSizeAtScriptLevelZero * .71, epsilon, "over");
}, "checking dynamic/case-insensitive accent/accentunder");
}, "checking dynamic accent/accentunder");
done();
}
@@ -179,26 +186,26 @@
</p>
<p>
<math>
<munder accentunder="true">
<munder id="munder-accentunder" accentunder="true">
<mn>0</mn>
<mn>1</mn>
</munder>
</math>
<math>
<mover accent="true">
<mover id="mover-accent" accent="true">
<mn>0</mn>
<mn>1</mn>
</mover>
</math>
<math>
<munderover accent="true">
<munderover id="munderover-accent" accent="true">
<mn>0</mn>
<mn>1</mn>
<mn>2</mn>
</munderover>
</math>
<math>
<munderover accentunder="true">
<munderover id="munderover-accentunder" accentunder="true">
<mn>0</mn>
<mn>1</mn>
<mn>2</mn>
@@ -207,7 +214,16 @@
</p>
<p>
<math>
<munderover id="munderover-dynamic-case-insensitive" accent="TrUe">
<munderover id="munderover-case-insensitive" accent="TrUe" accentunder="TrUe">
<mn>0</mn>
<mn>1</mn>
<mn>2</mn>
</munderover>
</math>
</p>
<p>
<math>
<munderover id="munderover-dynamic" accent="true">
<mn>0</mn>
<mn>1</mn>
<mn>2</mn>