summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/mathml/tools/operator-dictionary.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/mathml/tools/operator-dictionary.py
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/mathml/tools/operator-dictionary.py')
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/operator-dictionary.py124
1 files changed, 124 insertions, 0 deletions
diff --git a/testing/web-platform/tests/mathml/tools/operator-dictionary.py b/testing/web-platform/tests/mathml/tools/operator-dictionary.py
new file mode 100755
index 0000000000..22009c9efc
--- /dev/null
+++ b/testing/web-platform/tests/mathml/tools/operator-dictionary.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python3
+
+from lxml import etree
+from utils.misc import downloadWithProgressBar, UnicodeXMLURL, InlineAxisOperatorsURL
+import json, re
+from utils import mathfont
+
+NonBreakingSpace = 0x00A0
+
+def parseHexaNumber(string):
+ return int("0x%s" % string, 16)
+
+def parseHexaSequence(string):
+ return tuple(map(parseHexaNumber, string[1:].split("-")))
+
+def parseSpaces(value, entry, names):
+ for name in names:
+ attributeValue = entry.get(name)
+ if attributeValue is not None:
+ value[name] = int(attributeValue)
+
+def parseProperties(value, entry, names):
+ attributeValue = entry.get("properties")
+ if attributeValue is not None:
+ for name in names:
+ if attributeValue.find(name) >= 0:
+ value[name] = True
+
+def buildKeyAndValueFrom(characters, form):
+ # Concatenate characters and form to build the key.
+ key = ""
+ for c in characters:
+ key += chr(c)
+ key += " " + form
+ # But save characters as an individual property for easier manipulation in
+ # this Python script.
+ value = {
+ "characters": characters,
+ }
+ return key, value
+
+
+# Retrieve the spec files.
+inlineAxisOperatorsTXT = downloadWithProgressBar(InlineAxisOperatorsURL)
+unicodeXML = downloadWithProgressBar(UnicodeXMLURL)
+
+# Extract the operator dictionary.
+xsltTransform = etree.XSLT(etree.parse("./operator-dictionary.xsl"))
+
+# Put the operator dictionary into a Python structure.
+inlineAxisOperators = {}
+with open(inlineAxisOperatorsTXT, mode="r") as f:
+ for line in f:
+ hexaString = re.match("^U\+([0-9A-F]+)", line).group(1)
+ inlineAxisOperators[parseHexaNumber(hexaString)] = True
+
+operatorDictionary = {}
+root = xsltTransform(etree.parse(unicodeXML)).getroot()
+for entry in root:
+ characters = parseHexaSequence(entry.get("unicode"))
+ assert characters != (NonBreakingSpace)
+ key, value = buildKeyAndValueFrom(characters, entry.get("form"))
+ # There is no dictionary-specified minsize/maxsize values, so no need to
+ # parse them.
+ # The fence, separator and priority properties don't have any effect on math
+ # layout, so they are not added to the JSON file.
+ parseSpaces(value, entry, ["lspace", "rspace"])
+ parseProperties(value, entry, ["stretchy", "symmetric", "largeop",
+ "movablelimits", "accent"])
+ if (len(characters) == 1 and characters[0] in inlineAxisOperators):
+ value["horizontal"] = True
+ operatorDictionary[key] = value
+
+# Create entries for the non-breaking space in all forms in order to test the
+# default for operators outside the official dictionary.
+for form in ["infix", "prefix", "suffix"]:
+ key, value = buildKeyAndValueFrom(tuple([NonBreakingSpace]), form)
+ operatorDictionary[key] = value
+
+# Create a WOFF font with glyphs for all the operator strings.
+font = mathfont.create("operators", "Copyright (c) 2019 Igalia S.L.")
+
+# Set parameters for largeop and stretchy tests.
+font.math.DisplayOperatorMinHeight = 2 * mathfont.em
+font.math.MinConnectorOverlap = mathfont.em // 2
+
+# Set parameters for accent tests so that we only have large gap when
+# overscript is an accent.
+font.math.UpperLimitBaselineRiseMin = 0
+font.math.StretchStackTopShiftUp = 0
+font.math.AccentBaseHeight = 2 * mathfont.em
+font.math.OverbarVerticalGap = 0
+
+mathfont.createSizeVariants(font, True)
+
+# Ensure a glyph exists for the combining characters that are handled specially
+# in the specification:
+# U+0338 COMBINING LONG SOLIDUS OVERLAY
+# U+20D2 COMBINING LONG VERTICAL LINE OVERLAY
+for combining_character in [0x338, 0x20D2]:
+ mathfont.createSquareGlyph(font, combining_character)
+
+for key in operatorDictionary:
+ value = operatorDictionary[key]
+ for c in value["characters"]:
+ if c in font:
+ continue
+ if c == NonBreakingSpace:
+ g = font.createChar(c)
+ mathfont.drawRectangleGlyph(g, mathfont.em, mathfont.em // 3, 0)
+ else:
+ mathfont.createSquareGlyph(font, c)
+ mathfont.createStretchy(font, c, c in inlineAxisOperators)
+mathfont.save(font)
+
+# Generate the python file.
+for key in operatorDictionary:
+ del operatorDictionary[key]["characters"] # Remove this temporary value.
+JSON = {
+ "comment": "This file was automatically generated by operator-dictionary.py. Do not edit.",
+ "dictionary": operatorDictionary
+}
+with open('../support/operator-dictionary.json', 'w') as fp:
+ json.dump(JSON, fp, sort_keys=True, ensure_ascii=True)