Skip to content

Commit

Permalink
Update MathML Operator dictionary
Browse files Browse the repository at this point in the history
Support for the operator dictionary landed in september 2020 [1] [2].
However, after that initial support more changes were performed on the
specification side by the MathML CG. Now that the dictionary is stable
enough, this CL updates the implementation and tests accordingly.
We take the opportunity that operators.woff is regenerated to fix two
issues: make glyph indices of stretchy parts more stable and ensure
that the font contains glyphs for special combining characters [1].

- open_type_math_support_test.cc/stretchy_operator_shaper_test.cc:
  Access the glyph indices from their code points in the PUA.

- mathml_operator_element.cc/mathml_operator_dictionary.h: A new
  "Force Default" is introduced for the two operators having both an
  infix form with the default values and a different form, so they
  don't perform step 4 of [4]. Switch categories K and L.

- mathml_operator_dictionary.cc: Update operators_2_ascii_chars,
  and compact_dictionary from the spec. Also add special case for
  the "Force Default" category. Switch categories K and L.

- mathml_operator_dictionary_test.cc: Regenerate content of
  categories and switch categories K and L.

- character_names.h: Add new names for the operators in the
  "Force Default" category.

- operator-dictionary.json: Regenerate operator dictionary.

- operator-dictionary.py/mathfont.py: Store glyphs v0, h0, v1, h1, v2,
  h2, v3, h3 at the beginning of the PUA so they can be accessed by
  code point values. Ensure existence of glyphs for special combining
  characters.

- misc.py: Use the official repository for unicode.xml rather than the
  obsolete development branch for Unicode 14.

- operator-dictionary-combining-expected.txt: Removed since the test
  pass now that glyphs are available for combining characters.


Bug: 6606, 1082250,  1057596
Change-Id: I106b1551a910d1292df71b954981e0465ea222c1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3419439
Reviewed-by: Dominik Röttsches <drott@chromium.org>
Commit-Queue: Frédéric Wang <fwang@igalia.com>
Cr-Commit-Position: refs/heads/main@{#986939}
  • Loading branch information
fred-wang authored and Chromium LUCI CQ committed Mar 30, 2022
1 parent 200f12b commit 324b75d
Show file tree
Hide file tree
Showing 14 changed files with 197 additions and 154 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ struct MathMLOperatorDictionaryProperties {
static const MathMLOperatorDictionaryProperties
MathMLOperatorDictionaryCategories[] = {
{5, 5, kOperatorPropertyFlagsNone}, // None (default values)
{5, 5, kOperatorPropertyFlagsNone}, // ForceDefault
{5, 5, MathMLOperatorElement::kStretchy}, // Category A
{4, 4, kOperatorPropertyFlagsNone}, // Category B
{3, 3, kOperatorPropertyFlagsNone}, // Category C
{0, 0, kOperatorPropertyFlagsNone}, // Categories D, E, L
{0, 0, kOperatorPropertyFlagsNone}, // Categories D, E, K
{0, 0,
MathMLOperatorElement::kStretchy |
MathMLOperatorElement::kSymmetric}, // Categories F, G
Expand All @@ -43,7 +44,7 @@ static const MathMLOperatorDictionaryProperties
{3, 3,
MathMLOperatorElement::kSymmetric | MathMLOperatorElement::kLargeOp |
MathMLOperatorElement::kMovableLimits}, // Category J
{3, 0, kOperatorPropertyFlagsNone}, // Category K
{3, 0, kOperatorPropertyFlagsNone}, // Category L
{0, 3, kOperatorPropertyFlagsNone}, // Category M
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
#include "third_party/blink/renderer/platform/fonts/opentype/open_type_types.h"
#include "third_party/blink/renderer/platform/testing/font_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/wtf/text/character_names.h"

namespace {
const UChar32 kLeftBraceCodePoint = '{';
const UChar32 kOverBraceCodePoint = 0x23DE;
const UChar32 kRightwardsFrontTiltedShadowedWhiteArrowCodePoint = 0x1F8AB;
const UChar32 kNAryWhiteVerticalBarCodePoint = 0x2AFF;
} // namespace

Expand Down Expand Up @@ -296,19 +296,22 @@ TEST_F(OpenTypeMathSupportTest, MathVariantsWithTable) {
auto left_brace = math.PrimaryFont()->GlyphForCharacter(kLeftBraceCodePoint);
auto over_brace = math.PrimaryFont()->GlyphForCharacter(kOverBraceCodePoint);

// Calculate glyph indices from the last unicode character in the font.
// TODO(https://crbug.com/1057596): Find a better way to access these glyph
// indices.
auto v0 = math.PrimaryFont()->GlyphForCharacter(
kRightwardsFrontTiltedShadowedWhiteArrowCodePoint) +
1;
auto h0 = v0 + 1;
auto v1 = h0 + 1;
auto h1 = v1 + 1;
auto v2 = h1 + 1;
auto h2 = v2 + 1;
auto v3 = h2 + 1;
auto h3 = v3 + 1;
// Calculate glyph indices of stretchy operator's parts.
auto v0 = math.PrimaryFont()->GlyphForCharacter(kPrivateUseFirstCharacter);
auto h0 =
math.PrimaryFont()->GlyphForCharacter(kPrivateUseFirstCharacter + 1);
auto v1 =
math.PrimaryFont()->GlyphForCharacter(kPrivateUseFirstCharacter + 2);
auto h1 =
math.PrimaryFont()->GlyphForCharacter(kPrivateUseFirstCharacter + 3);
auto v2 =
math.PrimaryFont()->GlyphForCharacter(kPrivateUseFirstCharacter + 4);
auto h2 =
math.PrimaryFont()->GlyphForCharacter(kPrivateUseFirstCharacter + 5);
auto v3 =
math.PrimaryFont()->GlyphForCharacter(kPrivateUseFirstCharacter + 6);
auto h3 =
math.PrimaryFont()->GlyphForCharacter(kPrivateUseFirstCharacter + 7);

// Vertical variants for vertical operator.
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ namespace {

const UChar32 kLeftBraceCodePoint = '{';
const UChar32 kOverBraceCodePoint = 0x23DE;
const UChar32 kRightwardsFrontTiltedShadowedWhiteArrowCodePoint = 0x1F8AB;
const UChar32 kNAryWhiteVerticalBarCodePoint = 0x2AFF;
float kSizeError = .1;

Expand Down Expand Up @@ -63,17 +62,18 @@ TEST_F(StretchyOperatorShaperTest, GlyphVariants) {
auto left_brace = math.PrimaryFont()->GlyphForCharacter(kLeftBraceCodePoint);
auto over_brace = math.PrimaryFont()->GlyphForCharacter(kOverBraceCodePoint);

// Calculate glyph indices from the last unicode character in the font.
// TODO(https://crbug.com/1057596): Find a better way to access these glyph
// indices.
auto v0 = math.PrimaryFont()->GlyphForCharacter(
kRightwardsFrontTiltedShadowedWhiteArrowCodePoint) +
1;
auto h0 = v0 + 1;
auto v1 = h0 + 1;
auto h1 = v1 + 1;
auto v2 = h1 + 1;
auto h2 = v2 + 1;
// Calculate glyph indices of stretchy operator's parts.
auto v0 = math.PrimaryFont()->GlyphForCharacter(kPrivateUseFirstCharacter);
auto h0 =
math.PrimaryFont()->GlyphForCharacter(kPrivateUseFirstCharacter + 1);
auto v1 =
math.PrimaryFont()->GlyphForCharacter(kPrivateUseFirstCharacter + 2);
auto h1 =
math.PrimaryFont()->GlyphForCharacter(kPrivateUseFirstCharacter + 3);
auto v2 =
math.PrimaryFont()->GlyphForCharacter(kPrivateUseFirstCharacter + 4);
auto h2 =
math.PrimaryFont()->GlyphForCharacter(kPrivateUseFirstCharacter + 5);

// Stretch operators to target sizes (in font units) 125, 250, 375, 500, 625,
// 750, 875, 1000, 1125, ..., 3750, 3875, 4000.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ namespace blink {
namespace {

// https://w3c.github.io/mathml-core/#operator-dictionary-compact-special-tables
const char* operators_2_ascii_chars[] = {
"!!", "!=", "&&", "**", "*=", "++", "+=", "--", "-=", "->",
"..", "//", "/=", ":=", "<=", "<>", "==", ">=", "||"};
const char* operators_2_ascii_chars[] = {"!!", "!=", "&&", "**", "*=", "++",
"+=", "--", "-=", "->", "//", "/=",
":=", "<=", "<>", "==", ">=", "||"};

// https://w3c.github.io/mathml-core/#operator-dictionary-categories-hexa-table
struct EntryRange {
Expand All @@ -32,52 +32,57 @@ static inline uint16_t ExtractCategory(const EntryRange& range) {
// requirements by mapping codepoints and category to better make use of the
// available bytes. For details see
// https://w3c.github.io/mathml-core/#operator-dictionary.
// It was automatically generated from the spec's script:
// https://github.com/w3c/mathml-core/blob/main/tables/operator-dictionary.py
static const EntryRange compact_dictionary[] = {
{0x8025, 0}, {0x802A, 0}, {0x402B, 0}, {0x402D, 0}, {0x802E, 0},
{0x402F, 0}, {0x803F, 1}, {0xC05C, 0}, {0x805E, 1}, {0x807C, 0},
{0x402F, 0}, {0x803F, 1}, {0xC05C, 0}, {0x805E, 0}, {0xC05F, 0},
{0x40B1, 0}, {0x80B7, 0}, {0x80D7, 0}, {0x40F7, 0}, {0x4322, 0},
{0x8323, 0}, {0x832B, 0}, {0x832F, 0}, {0x8332, 0}, {0x8422, 0},
{0x8443, 0}, {0x4444, 0}, {0xC461, 3}, {0x0590, 9}, {0x059C, 15},
{0x05AC, 1}, {0x05AF, 6}, {0x05B9, 0}, {0x05BC, 15}, {0x05CC, 0},
{0x05D0, 13}, {0x05E0, 15}, {0x05F0, 0}, {0x05F3, 0}, {0x05F5, 1},
{0x05FD, 2}, {0x8606, 0}, {0x860E, 0}, {0x4612, 4}, {0x8617, 0},
{0x4618, 0}, {0x4624, 0}, {0x4627, 3}, {0x4636, 0}, {0x4638, 0},
{0x863F, 1}, {0x468C, 3}, {0x4693, 3}, {0x8697, 0}, {0x4698, 0},
{0x8699, 0}, {0x469D, 2}, {0x86A0, 1}, {0x46BB, 2}, {0x46C4, 0},
{0x86C5, 0}, {0x46C6, 0}, {0x86C7, 0}, {0x86C9, 3}, {0x46CE, 1},
{0x46D2, 1}, {0x8705, 1}, {0x89A0, 1}, {0x89AA, 1}, {0x89AD, 4},
{0x4B95, 2}, {0x8BCB, 0}, {0x8BCD, 0}, {0x0BF0, 1}, {0x4BF4, 0},
{0x0BF5, 10}, {0x0D0A, 6}, {0x0D12, 1}, {0x0D21, 1}, {0x0D4E, 15},
{0x0D5E, 3}, {0x0D6E, 1}, {0x8D81, 1}, {0x8D99, 1}, {0x8DB5, 0},
{0x4DBC, 0}, {0x8DC2, 1}, {0x8DC9, 4}, {0x8DD8, 1}, {0x8DDB, 0},
{0x8DDF, 1}, {0x8DE2, 0}, {0x8DE7, 6}, {0x4DF6, 0}, {0x8DF8, 3},
{0x8E1D, 4}, {0x4E22, 12}, {0x8E2F, 8}, {0x4E38, 2}, {0x8E3B, 2},
{0x8E3F, 0}, {0x4E40, 15}, {0x8E50, 0}, {0x4E51, 15}, {0x4E61, 2},
{0x4EDA, 1}, {0x8EDC, 1}, {0x4EFB, 0}, {0x4EFD, 0}, {0x8EFE, 0},
{0x4F32, 0}, {0x0F45, 1}, {0x1021, 0}, {0x5028, 0}, {0x102B, 0},
{0x102D, 0}, {0x505B, 0}, {0x507B, 1}, {0x10AC, 0}, {0x10B1, 0},
{0x1332, 0}, {0x5416, 0}, {0x1418, 0}, {0x141C, 0}, {0x1600, 1},
{0x1603, 1}, {0x1607, 0}, {0xD60F, 2}, {0x1612, 1}, {0x161F, 3},
{0x962B, 8}, {0x163C, 0}, {0x16BE, 1}, {0xD6C0, 3}, {0x5708, 0},
{0x570A, 0}, {0x1710, 0}, {0x1719, 0}, {0x5729, 0}, {0x5B72, 0},
{0x1B95, 1}, {0x1BC0, 0}, {0x5BE6, 0}, {0x5BE8, 0}, {0x5BEA, 0},
{0x5BEC, 0}, {0x5BEE, 0}, {0x5D80, 0}, {0x5D83, 0}, {0x5D85, 0},
{0x5D87, 0}, {0x5D89, 0}, {0x5D8B, 0}, {0x5D8D, 0}, {0x5D8F, 0},
{0x5D91, 0}, {0x5D93, 0}, {0x5D95, 0}, {0x5D97, 0}, {0x1D9B, 15},
{0x1DAB, 4}, {0x5DFC, 0}, {0xDE00, 10}, {0x9E0B, 15}, {0x9E1B, 1},
{0x1EEC, 1}, {0xDEFC, 0}, {0xDEFF, 0}, {0x2021, 1}, {0x2026, 1},
{0x6029, 0}, {0x605D, 0}, {0xA05E, 1}, {0x2060, 0}, {0x607C, 1},
{0xA07E, 0}, {0x20A8, 0}, {0xA0AF, 0}, {0x20B0, 0}, {0x20B2, 2},
{0x20B8, 1}, {0xA2C6, 1}, {0xA2C9, 0}, {0x22CA, 1}, {0xA2CD, 0},
{0x22D8, 2}, {0xA2DC, 0}, {0x22DD, 0}, {0xA2F7, 0}, {0xA302, 0},
{0x2311, 0}, {0x2320, 0}, {0x2325, 0}, {0x2327, 0}, {0x232A, 0},
{0x2332, 0}, {0x6416, 0}, {0x2419, 2}, {0x241D, 2}, {0x2432, 5},
{0x8323, 0}, {0x832E, 0}, {0x8422, 0}, {0x8443, 0}, {0x4444, 0},
{0xC461, 3}, {0x0590, 5}, {0x059A, 15}, {0x05AA, 4}, {0x05B0, 5},
{0x05B9, 0}, {0x05BC, 15}, {0x05CC, 9}, {0x05DA, 15}, {0x05EA, 6},
{0x05F3, 12}, {0xC606, 0}, {0x4612, 4}, {0x8617, 2}, {0x4627, 3},
{0x4636, 0}, {0x4638, 0}, {0x8640, 0}, {0x468C, 2}, {0x4693, 3},
{0x8697, 0}, {0x4698, 0}, {0x8699, 2}, {0x469D, 2}, {0x86A0, 1},
{0x86BA, 0}, {0x46BB, 2}, {0x86C4, 3}, {0x86C9, 3}, {0x46CE, 1},
{0x46D2, 1}, {0x8705, 1}, {0x0B94, 0}, {0x4B95, 2}, {0x0B99, 0},
{0x0B9B, 6}, {0x0BA5, 1}, {0x0BA8, 7}, {0x0BB1, 0}, {0x0BB3, 0},
{0x0BB5, 0}, {0x0BB8, 0}, {0x0BBA, 4}, {0x8BCB, 0}, {0x8BCD, 0},
{0x0BF0, 1}, {0x0BF4, 11}, {0x0D00, 15}, {0x0D10, 15}, {0x0D20, 0},
{0x0D34, 3}, {0x0D42, 15}, {0x0D52, 15}, {0x0D62, 15}, {0x0D72, 3},
{0x0D7C, 3}, {0x4DB8, 0}, {0x4DBC, 0}, {0x4DC4, 1}, {0x8DC6, 2},
{0x8DD4, 3}, {0x8DE2, 0}, {0x4DF5, 6}, {0x8E1D, 1}, {0x4E1F, 15},
{0x8E2F, 8}, {0x4E38, 2}, {0x8E3B, 2}, {0x4E3E, 0}, {0x8E3F, 0},
{0x4E40, 15}, {0x8E50, 0}, {0x4E51, 15}, {0x4E61, 2}, {0x8E64, 1},
{0x4EDB, 0}, {0x8EDC, 1}, {0x4EF6, 0}, {0x4EFB, 0}, {0x4EFD, 0},
{0x8EFE, 0}, {0x0F04, 3}, {0x0F0C, 5}, {0x0F30, 14}, {0x0F40, 12},
{0x0F60, 5}, {0x0F6A, 3}, {0x0F70, 3}, {0x0F7A, 3}, {0x0F80, 7},
{0x0F95, 0}, {0x0FA0, 15}, {0x0FB8, 0}, {0x1021, 0}, {0x5028, 0},
{0x102B, 0}, {0x102D, 0}, {0x505B, 0}, {0x507B, 1}, {0x10AC, 0},
{0x10B1, 0}, {0x1331, 0}, {0x5416, 0}, {0x1418, 0}, {0x141C, 0},
{0x1600, 1}, {0x1603, 1}, {0x1607, 0}, {0xD60F, 2}, {0x1612, 1},
{0x161F, 3}, {0x962B, 8}, {0x1634, 1}, {0x163C, 0}, {0x16BE, 1},
{0xD6C0, 3}, {0x5708, 0}, {0x570A, 0}, {0x1710, 0}, {0x1719, 0},
{0x5729, 0}, {0x5B72, 0}, {0x1B95, 1}, {0x1BC0, 0}, {0x5BE6, 0},
{0x5BE8, 0}, {0x5BEA, 0}, {0x5BEC, 0}, {0x5BEE, 0}, {0x5D80, 0},
{0x5D83, 0}, {0x5D85, 0}, {0x5D87, 0}, {0x5D89, 0}, {0x5D8B, 0},
{0x5D8D, 0}, {0x5D8F, 0}, {0x5D91, 0}, {0x5D93, 0}, {0x5D95, 0},
{0x5D97, 0}, {0x5D99, 0}, {0x1D9B, 15}, {0x1DAB, 4}, {0x5DD8, 0},
{0x5DDA, 0}, {0x5DFC, 0}, {0xDE00, 10}, {0x9E0B, 15}, {0x9E1B, 1},
{0xDE1D, 1}, {0x1EEC, 1}, {0xDEFC, 0}, {0xDEFF, 0}, {0x2021, 1},
{0x2025, 2}, {0x6029, 0}, {0x605D, 0}, {0xA05E, 1}, {0x2060, 0},
{0x607C, 1}, {0xA07E, 0}, {0x20A8, 0}, {0xA0AF, 0}, {0x20B0, 0},
{0x20B2, 2}, {0x20B8, 1}, {0xA2C6, 1}, {0xA2C9, 0}, {0x22CA, 1},
{0xA2CD, 0}, {0x22D8, 2}, {0xA2DC, 0}, {0x22DD, 0}, {0xA2F7, 0},
{0xA302, 0}, {0x2311, 0}, {0x2320, 0}, {0x2325, 0}, {0x2327, 0},
{0x2331, 0}, {0x6416, 0}, {0x2419, 2}, {0x241D, 2}, {0x2432, 5},
{0xA43E, 0}, {0x2457, 0}, {0x24DB, 1}, {0x6709, 0}, {0x670B, 0},
{0xA722, 1}, {0x672A, 0}, {0xA7B4, 1}, {0x27CD, 0}, {0xA7DC, 5},
{0x6B73, 0}, {0x6BE7, 0}, {0x6BE9, 0}, {0x6BEB, 0}, {0x6BED, 0},
{0x6BEF, 0}, {0x6D80, 0}, {0x6D84, 0}, {0x6D86, 0}, {0x6D88, 0},
{0x6D8A, 0}, {0x6D8C, 0}, {0x6D8E, 0}, {0x6D90, 0}, {0x6D92, 0},
{0x6D94, 0}, {0x6D96, 0}, {0x6D98, 0}, {0x6DFD, 0}};
{0x6D94, 0}, {0x6D96, 0}, {0x6D98, 1}, {0x6DD9, 0}, {0x6DDB, 0},
{0x6DFD, 0}};

} // namespace

Expand Down Expand Up @@ -128,12 +133,16 @@ MathMLOperatorDictionaryCategory FindCategory(

// Handle special categories that are not encoded in the compact dictionary.
// https://w3c.github.io/mathml-core/#operator-dictionary-categories-values
if (form == MathMLOperatorDictionaryForm::kInfix &&
(key == kVerticalLineCharacter || key == kTildeOperatorCharacter)) {
return MathMLOperatorDictionaryCategory::kForceDefault;
}
if (form == MathMLOperatorDictionaryForm::kPrefix &&
((kDoubleStruckItalicCapitalDCharacter <= key &&
key <= kDoubleStruckItalicSmallDCharacter) ||
key == kPartialDifferential ||
(kSquareRootCharacter <= key && key <= kFourthRootCharacter))) {
return MathMLOperatorDictionaryCategory::kK;
return MathMLOperatorDictionaryCategory::kL;
}
if (form == MathMLOperatorDictionaryForm::kInfix &&
(key == kComma || key == kColon || key == kSemiColon)) {
Expand Down Expand Up @@ -181,7 +190,7 @@ MathMLOperatorDictionaryCategory FindCategory(
case 0x1:
case 0x2:
case 0xC:
return MathMLOperatorDictionaryCategory::kDorEorL;
return MathMLOperatorDictionaryCategory::kDorEorK;
case 0x5:
case 0x6:
return MathMLOperatorDictionaryCategory::kForG;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@ namespace blink {

enum class MathMLOperatorDictionaryCategory : uint8_t {
kNone,
kForceDefault,
kA,
kB,
kC,
kDorEorL,
kDorEorK,
kForG,
kH,
kI,
kJ,
kK,
kL,
kM,
kUndefined = 15
};
Expand Down

0 comments on commit 324b75d

Please sign in to comment.