Bug 1790009, part 3 - Implement special handling for operators using U+0338 and U+20D2. r=emilio

MathML Core specifies that operators containing a UTF-16 strings of
length 2 ending with U+0338 COMBINING LONG SOLIDUS OVERLAY or U+20D2
COMBINING LONG VERTICAL LINE OVERLAY should just use the properties of
the first character. This commit implements that behavior. It removes
obsolete entries that are superseded by this rule and modifies
updateOperatorDictionary.pl to ensure that no such entries are present.

Existing WPT test operator-dictionary-combining.html is already passing
after bug 1789583 because the operators tested use the default spacing.
So extend it to try operators with different spacing.

[1] https://w3c.github.io/mathml-core/#dfn-algorithm-to-determine-the-category-of-an-operator

Differential Revision: https://phabricator.services.mozilla.com/D157707
This commit is contained in:
Frederic Wang 2022-09-21 06:28:05 +00:00
Родитель 218ba23a4d
Коммит 7e2948f114
4 изменённых файлов: 68 добавлений и 27 удалений

Просмотреть файл

@ -1201,8 +1201,6 @@ operator.\u002B\u002B.prefix = lspace:0 rspace:2 # ++
operator.\u002D\u002D.prefix = lspace:0 rspace:2 # --
operator.\u002E\u002E.postfix = lspace:0 rspace:0 # ..
operator.\u003B.postfix = lspace:0 rspace:0 separator # ;
operator.\u003C\u20D2.infix = lspace:5 rspace:5 # <⃒
operator.\u003E\u20D2.infix = lspace:5 rspace:5 # >⃒
operator.\u007E.infix = lspace:2 rspace:2 stretchy direction:horizontal # ~
operator.\u0332.postfix = lspace:0 rspace:0 stretchy accent direction:horizontal # _
operator.\u03F6.infix = lspace:5 rspace:5 # greek reversed lunate epsilon symbol
@ -1228,20 +1226,7 @@ operator.\u2234.infix = lspace:5 rspace:5 # ∴
operator.\u2235.infix = lspace:5 rspace:5 # ∵
operator.\u223D\u0331.infix = lspace:3 rspace:3 # reversed tilde with underline
operator.\u223F.infix = lspace:3 rspace:3 # sine wave
operator.\u2242\u0338.infix = lspace:5 rspace:5 # ≂̸
operator.\u224E\u0338.infix = lspace:5 rspace:5 # ≎̸
operator.\u224F\u0338.infix = lspace:5 rspace:5 # ≏̸
operator.\u2266\u0338.infix = lspace:5 rspace:5 # ≧̸
operator.\u226A\u0338.infix = lspace:5 rspace:5 # ≪̸
operator.\u226B\u0338.infix = lspace:5 rspace:5 # ≫̸
operator.\u227F\u0338.infix = lspace:5 rspace:5 # ≿̸
operator.\u2282\u020D2.infix = lspace:5 rspace:5 # ⊂⃒
operator.\u2282\u20D2.infix = lspace:5 rspace:5 # subset of with vertical line
operator.\u2283\u020D2.infix = lspace:5 rspace:5 # ⊃⃒
operator.\u2283\u20D2.infix = lspace:5 rspace:5 # superset of with vertical line
operator.\u228E.prefix = lspace:1 rspace:2 largeop movablelimits symmetric direction:vertical # ⊎
operator.\u228F\u0338.infix = lspace:5 rspace:5 # ⊏̸
operator.\u2290\u0338.infix = lspace:5 rspace:5 # ⊐̸
operator.\u2295.prefix = lspace:0 rspace:3 largeop movablelimits symmetric direction:vertical # ⊕
operator.\u2296.prefix = lspace:0 rspace:3 largeop movablelimits symmetric direction:vertical # ⊖
operator.\u2297.prefix = lspace:0 rspace:3 largeop movablelimits symmetric direction:vertical # ⊗
@ -1343,8 +1328,6 @@ operator.\u29CA.infix = lspace:3 rspace:3 # triangle with dot above
operator.\u29CB.infix = lspace:3 rspace:3 # triangle with underbar
operator.\u29CC.infix = lspace:3 rspace:3 # s in triangle
operator.\u29CD.infix = lspace:3 rspace:3 # triangle with serifs at bottom
operator.\u29CF\u0338.infix = lspace:5 rspace:5 # ⧏̸
operator.\u29D0\u0338.infix = lspace:5 rspace:5 # ⧐̸
operator.\u29D8.infix = lspace:3 rspace:3 # left wiggly fence
operator.\u29D9.infix = lspace:3 rspace:3 # right wiggly fence
operator.\u29DB.infix = lspace:3 rspace:3 # right double wiggly fence
@ -1367,15 +1350,6 @@ operator.\u29F2.infix = lspace:3 rspace:3 # error-barred white circle
operator.\u29F3.infix = lspace:3 rspace:3 # error-barred black circle
operator.\u29FE.infix = lspace:4 rspace:4 # tiny
operator.\u29FF.infix = lspace:4 rspace:4 # miny
operator.\u2A7D\u0338.infix = lspace:5 rspace:5 # ⩽̸
operator.\u2A7E\u0338.infix = lspace:5 rspace:5 # ⩾̸
operator.\u2AA1\u0338.infix = lspace:5 rspace:5 # ⪡̸
operator.\u2AA2\u0338.infix = lspace:5 rspace:5 # ⪢̸
operator.\u2AAF\u0338.infix = lspace:5 rspace:5 # ⪯̸
operator.\u2AB0\u0338.infix = lspace:5 rspace:5 # ⪰̸
operator.\u2AC5\u0338.infix = lspace:5 rspace:5 # ⫅̸
operator.\u2AC6\u0338.infix = lspace:5 rspace:5 # ⫅̸
operator.\u2ADD\u0338.infix = lspace:5 rspace:5 # nonforking with slash
operator.\u2AEC.infix = lspace:5 rspace:5 # double stroke not sign
operator.\u2AED.infix = lspace:5 rspace:5 # reversed double stroke not sign
operator.\u2AEF.infix = lspace:5 rspace:5 # vertical line with circle above

Просмотреть файл

@ -323,6 +323,16 @@ bool nsMathMLOperators::LookupOperator(const nsString& aOperator,
return false;
}
// Ignore the combining "negation" suffix for 2-character strings.
// https://w3c.github.io/mathml-core/#dfn-algorithm-to-determine-the-category-of-an-operator
if (aOperator.Length() == 2 &&
(aOperator[1] == 0x0338 || aOperator[1] == 0x20D2)) {
nsAutoString newOperator;
newOperator.Append(aOperator[0]);
return LookupOperator(newOperator, aForm, aFlags, aLeadingSpace,
aTrailingSpace);
}
if (!gGlobalsInitialized) {
InitOperatorGlobals();
}

Просмотреть файл

@ -141,6 +141,12 @@ if ($ARGV[0] eq "check") {
print $file_syntax_errors "error: \"$key\" has more than 2 characters\n";
}
if ($key =~ /\\u20D2\./ || $key =~ /\\u0338\./) {
$valid = 0;
$nb_errors++;
print $file_syntax_errors "error: \"$key\" ends with character U+20D2 or U+0338\n";
}
@moz = @{ $moz_hash{$key} };
$entry = &generateEntry($key, @moz);
$valid = 1;

Просмотреть файл

@ -33,7 +33,12 @@
var epsilon = 1;
var emToPx = 25;
["equal", "vertical_bar"].forEach(id => {
[
"equal",
"vertical_bar",
"left_normal_factor_semidirect_product",
"there_exists",
].forEach(id => {
var div = document.getElementById(id);
var ref = div.getElementsByClassName("reference")[0];
var totalSpaceRef = spaceBetween(ref, 0, 2);
@ -104,5 +109,51 @@
</math>
</p>
</div>
<div id="left_normal_factor_semidirect_product">
<p>
<math class="reference">
<mn>&nbsp;</mn>
<mo stretchy="false"></mo>
<mn>&nbsp;</mn>
</math>
</p>
<p>
<math class="combining">
<mn>&nbsp;</mn>
<mo stretchy="false">&#x338;</mo>
<mn>&nbsp;</mn>
</math>
</p>
<p>
<math class="combining">
<mn>&nbsp;</mn>
<mo stretchy="false">&#x20D2;</mo>
<mn>&nbsp;</mn>
</math>
</p>
</div>
<div id="there_exists">
<p>
<math class="reference">
<mn>&nbsp;</mn>
<mo stretchy="false"></mo>
<mn>&nbsp;</mn>
</math>
</p>
<p>
<math class="combining">
<mn>&nbsp;</mn>
<mo stretchy="false">&#x338;</mo>
<mn>&nbsp;</mn>
</math>
</p>
<p>
<math class="combining">
<mn>&nbsp;</mn>
<mo stretchy="false">&#x20D2;</mo>
<mn>&nbsp;</mn>
</math>
</p>
</div>
</body>
</html>