From 43a97878ce14b72f0981164f87f2e35e14151312 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:22:09 +0200 Subject: Adding upstream version 110.0.1. Signed-off-by: Daniel Baumann --- .../tests/mathml/tools/operator-dictionary.py | 124 +++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100755 testing/web-platform/tests/mathml/tools/operator-dictionary.py (limited to 'testing/web-platform/tests/mathml/tools/operator-dictionary.py') 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) -- cgit v1.2.3