blob: ea3d5ae2b1cea077f32df23d9174600fbb19d27f [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Operator dictionary</title>
<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#dictionary-based-attributes">
<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-dictionary">
<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#stretchy-operator-axis">
<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
<meta name="timeout" content="long">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/mathml/support/feature-detection.js"></script>
<script src="/mathml/support/operator-dictionary.js"></script>
<style>
@font-face {
font-family: operators;
src: url("/fonts/math/operators.woff");
}
math, math * {
font-family: operators;
/* Use large enough font-size so that 1/18em = 2.77px > epsilon and
one can really distinguish lspace/rspace values. */
font-size: 50px;
}
</style>
<script>
setup({ explicit_done: true });
window.addEventListener("load", () => { document.fonts.ready.then(runTests); });
async function runTests() {
let epsilon = 1;
let json = await fetchOperatorDictionary();
// The operator dictionary has more than one thousand of entries so the
// tests are grouped in chunks so that these don't get much more
// importance than other MathML tests. For easy debugging, one can set the
// chunk size to 1. Also, note that the test div will remain visible for
// failed tests.
const entryPerChunk = 50
var counter = 0;
var tests = {
"lspace/rspace": null,
"movablelimits": null,
"largeop": null,
"stretchy": null,
"symmetric": null,
"accent": null
};
for (key in json.dictionary) {
if (counter % entryPerChunk === 0) {
// Start of a new chunk.
// Complete current async tests and create new ones for the next chunk.
for (name in tests) {
if (tests[name]) tests[name].done();
tests[name] = async_test(`Operator dictionary chunk ${1 + counter / entryPerChunk} - ${name}`);
}
}
let parsedKey = splitKey(key);
let entry = json.dictionary[key];
tests["lspace/rspace"].step(function() {
assert_true(MathMLFeatureDetection.has_operator_spacing());
document.body.insertAdjacentHTML("beforeend", `<div>\
lspace/rspace for "${parsedKey.characters}" (${parsedKey.form}): \
<math>\
<mrow>\
<mn>&nbsp;</mn>\
<mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
<mn>&nbsp;</mn>\
</mrow>\
</math>\
VS \
<math>\
<mrow>\
<mn>&nbsp;</mn>\
<mo form="${parsedKey.form}" lspace="${defaultPropertyValue(entry, 'lspace')}" rspace="${defaultPropertyValue(entry, 'rspace')}">${parsedKey.characters}</mo>\
<mn>&nbsp;</mn>\
</mrow>\
</math>\
</div>`);
var div = document.body.lastElementChild;
var mrows = div.getElementsByTagName("mrow");
function spaceBetween(element, i, j) {
return element.children[j].getBoundingClientRect().left -
element.children[i].getBoundingClientRect().right;
}
var lspace = spaceBetween(mrows[0], 0, 1);
var rspace = spaceBetween(mrows[0], 1, 2);
var lspaceRef = spaceBetween(mrows[1], 0, 1);
var rspaceRef = spaceBetween(mrows[1], 1, 2);
assert_approx_equals(lspace, lspaceRef, epsilon, `lspace (${key})`);
assert_approx_equals(rspace, rspaceRef, epsilon, `rspace (${key})`);
div.style.display = "none";
});
tests["movablelimits"].step(function() {
assert_true(MathMLFeatureDetection.has_movablelimits());
var defaultValue = defaultPropertyValue(entry, "movablelimits");
document.body.insertAdjacentHTML("beforeend", `<div>\
movablelimits for "${parsedKey.characters}" (${parsedKey.form}): \
<math>\
<munder>\
<mo stretchy="false" form="${parsedKey.form}">${parsedKey.characters}</mo>\
<mn>&nbsp;</mn>\
</munder>\
</math>\
VS \
<math>\
<munder>\
<mo stretchy="false" form="${parsedKey.form}" movablelimits="${defaultValue}">${parsedKey.characters}</mo>\
<mn>&nbsp;</mn>\
</munder>\
</math>\
</div>`);
var div = document.body.lastElementChild;
var munders = div.getElementsByTagName("munder");
munder = munders[0].getBoundingClientRect()
munderRef = munders[1].getBoundingClientRect()
assert_approx_equals(munder.height, munderRef.height, epsilon, `Movablelimits property for ${key} should be '${defaultValue}'`);
div.style.display = "none";
});
tests["largeop"].step(function() {
// FIXME: Should really detect largeop support...
assert_true(MathMLFeatureDetection.has_mspace());
var defaultValue = defaultPropertyValue(entry, "largeop");
document.body.insertAdjacentHTML("beforeend", `<div>\
largeop for "${parsedKey.characters}" (${parsedKey.form}): \
<math displaystyle="true">\
<mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
</math>\
VS \
<math displaystyle="true">\
<mo form="${parsedKey.form}" largeop="${defaultValue}">${parsedKey.characters}</mo>\
</math>\
</div>`);
var div = document.body.lastElementChild;
var mos = div.getElementsByTagName("mo");
mo = mos[0].getBoundingClientRect()
moRef = mos[1].getBoundingClientRect()
assert_approx_equals(mo.height, moRef.height, epsilon, `Largeop property for ${key} should be '${defaultValue}'`);
div.style.display = "none";
});
if (entry.horizontal) {
tests["stretchy"].step(function() {
// FIXME: Should really detect stretchy support...
assert_true(MathMLFeatureDetection.has_munder());
var defaultValue = defaultPropertyValue(entry, "stretchy");
document.body.insertAdjacentHTML("beforeend", `<div>\
stretchy for "${parsedKey.characters}" (${parsedKey.form}): \
<math>\
<munder>\
<mn>&nbsp;&nbsp;</mn>\
<mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
</munder>\
</math>\
VS \
<math>\
<munder>\
<mn>&nbsp;&nbsp;</mn>\
<mo form="${parsedKey.form}" stretchy="${defaultValue}">${parsedKey.characters}</mo>\
</munder>\
</math>\
</div>`);
var div = document.body.lastElementChild;
var mos = div.getElementsByTagName("mo");
mo = mos[0].getBoundingClientRect()
moRef = mos[1].getBoundingClientRect()
assert_approx_equals(mo.width, moRef.width, epsilon, `Stretchy property for ${key} should be '${defaultValue}'`);
div.style.display = "none";
});
} else {
tests["stretchy"].step(function() {
// FIXME: Should really detect stretchy support...
assert_true(MathMLFeatureDetection.has_mspace());
var defaultValue = defaultPropertyValue(entry, "stretchy");
document.body.insertAdjacentHTML("beforeend", `<div>\
stretchy for "${parsedKey.characters}" (${parsedKey.form}): \
<math>\
<mrow>\
<mo form="${parsedKey.form}" symmetric="false">${parsedKey.characters}</mo>\
<mspace height="2em"></mspace>\
</mrow>\
</math>\
VS \
<math>\
<mrow>\
<mo form="${parsedKey.form}" symmetric="false" stretchy="${defaultValue}">${parsedKey.characters}</mo>\
<mspace height="2em"></mspace>\
</mrow>\
</math>\
</div>`);
var div = document.body.lastElementChild;
var mos = div.getElementsByTagName("mo");
mo = mos[0].getBoundingClientRect()
moRef = mos[1].getBoundingClientRect()
assert_approx_equals(mo.height, moRef.height, epsilon, `Stretchy property for ${key} should be '${defaultValue}'`);
div.style.display = "none";
});
tests["symmetric"].step(function() {
// FIXME: Should really detect symmetric support...
assert_true(MathMLFeatureDetection.has_mspace());
var defaultValue = defaultPropertyValue(entry, "symmetric");
document.body.insertAdjacentHTML("beforeend", `<div>\
symmetric for "${parsedKey.characters}" (${parsedKey.form}): \
<math>\
<mrow>\
<mo form="${parsedKey.form}" stretchy="true">${parsedKey.characters}</mo>\
<mspace height="1.5em"></mspace>\
</mrow>\
</math>\
VS \
<math>\
<mrow>\
<mo form="${parsedKey.form}" stretchy="true" symmetric="${defaultValue}">${parsedKey.characters}</mo>\
<mspace height="1.5em"></mspace>\
</mrow>\
</math>\
</div>`);
var div = document.body.lastElementChild;
var mos = div.getElementsByTagName("mo");
mo = mos[0].getBoundingClientRect()
moRef = mos[1].getBoundingClientRect()
assert_approx_equals(mo.height, moRef.height, epsilon, `Symmetric property for ${key} should be '${defaultValue}'`);
div.style.display = "none";
});
}
tests["accent"].step(function() {
// FIXME: Should really detect accent support...
assert_true(MathMLFeatureDetection.has_mover());
var defaultValue = defaultPropertyValue(entry, "accent");
document.body.insertAdjacentHTML("beforeend", `<div>\
accent for "${parsedKey.characters}" (${parsedKey.form}): \
<math>\
<mover>\
<mn>&nbsp;</mn>\
<mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
</mover>\
</math>\
VS \
<math>\
<mover>\
<mn>&nbsp;</mn>\
<mo form="${parsedKey.form}" accent="${defaultValue}">${parsedKey.characters}</mo>\
</mover>\
</math>\
</div>`);
var div = document.body.lastElementChild;
var movers = div.getElementsByTagName("mover");
function gapBetweenBaseAndScript(mover) {
return mover.children[0].getBoundingClientRect().top -
mover.children[1].getBoundingClientRect().bottom;
}
var gap = gapBetweenBaseAndScript(movers[0])
var gapRef = gapBetweenBaseAndScript(movers[1])
assert_approx_equals(gap, gapRef, epsilon, `Accent property for ${key} should be '${defaultValue}'`);
div.style.display = "none";
});
counter++;
}
// Complete current async tests.
for (name in tests) {
if (tests[name]) tests[name].done();
}
done();
}
</script>
</head>
<body>
<div id="log"></div>
</body>
</html>