mathvariant-transforms.py (8671B)
1 #!/usr/bin/env python3 2 3 from lxml import etree 4 from utils.misc import downloadWithProgressBar, UnicodeXMLURL 5 from utils import mathfont 6 7 # Retrieve the unicode.xml file if necessary. 8 unicodeXML = downloadWithProgressBar(UnicodeXMLURL) 9 10 # Extract the mathvariants transformation. 11 xsltTransform = etree.XSLT(etree.XML('''\ 12 <xsl:stylesheet version="1.0" 13 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 14 <xsl:strip-space elements="*"/> 15 <xsl:template match="charlist"> 16 <root><xsl:apply-templates select="character"/></root> 17 </xsl:template> 18 <xsl:template match="character"> 19 <xsl:if test="surrogate"> 20 <entry> 21 <xsl:attribute name="mathvariant"> 22 <xsl:value-of select="surrogate/@mathvariant"/> 23 </xsl:attribute> 24 <xsl:attribute name="baseChar"> 25 <xsl:value-of select="surrogate/@ref"/> 26 </xsl:attribute> 27 <xsl:attribute name="transformedChar"> 28 <xsl:choose> 29 <xsl:when test="bmp"> 30 <xsl:value-of select="bmp/@ref"/> 31 </xsl:when> 32 <xsl:otherwise> 33 <xsl:value-of select="@id"/> 34 </xsl:otherwise> 35 </xsl:choose> 36 </xsl:attribute> 37 </entry> 38 </xsl:if> 39 </xsl:template> 40 </xsl:stylesheet>''')) 41 42 # Put the mathvariant transforms into a Python structure. 43 mathvariantTransforms = {} 44 root = xsltTransform(etree.parse(unicodeXML)).getroot() 45 46 47 def parseCodePoint(aHexaString): 48 return int("0x%s" % aHexaString[1:], 16) 49 50 51 for entry in root: 52 mathvariant = entry.get("mathvariant") 53 baseChar = parseCodePoint(entry.get("baseChar")) 54 transformedChar = parseCodePoint(entry.get("transformedChar")) 55 if mathvariant not in mathvariantTransforms: 56 mathvariantTransforms[mathvariant] = {} 57 mathvariantTransforms[mathvariant][baseChar] = transformedChar 58 59 # There is no "isolated" mathvariant. 60 del mathvariantTransforms["isolated"] 61 62 # Automatic mathvariant uses the same transform as italic. 63 # It is handled specially (see below). 64 mathvariantTransforms["auto"] = mathvariantTransforms["italic"] 65 66 # Create a WOFF font for each mathvariant. 67 for mathvariant in mathvariantTransforms: 68 if mathvariant == "auto": 69 continue 70 font = mathfont.create("mathvariant-%s" % mathvariant, 71 "Copyright (c) 2016 MathML Association") 72 for baseChar in mathvariantTransforms[mathvariant]: 73 if baseChar not in font: 74 mathfont.createGlyphFromValue(font, baseChar) 75 transformedChar = mathvariantTransforms[mathvariant][baseChar] 76 mathfont.createGlyphFromValue(font, transformedChar) 77 mathfont.save(font) 78 79 # Common function to generate test for MathML mathvariant / CSS text-transform. 80 81 82 def generateTestFor(mathvariant, mathml): 83 assert mathml or mathvariant == "auto", "These tests have been removed!" 84 print("Generating tests for %s..." % mathvariant, end="") 85 if mathml: 86 reftest = open( 87 "../relations/css-styling/mathvariant-%s.html" % mathvariant, "w") 88 reftestReference = open( 89 "../relations/css-styling/mathvariant-%s-ref.html" % mathvariant, "w") 90 else: 91 reftest = open( 92 "../../css/css-text/text-transform/math/text-transform-math-%s-001.html" % mathvariant, "w") 93 reftestReference = open( 94 "../../css/css-text/text-transform/math/text-transform-math-%s-001-ref.html" % mathvariant, "w") 95 source = '\ 96 <!DOCTYPE html>\n\ 97 <html>\n\ 98 <head>\n\ 99 <meta charset="utf-8"/>\n\ 100 <title>%s</title>\n' 101 if mathml: 102 reftest.write(source % ("mathvariant %s" % mathvariant)) 103 reftestReference.write( 104 source % ("mathvariant %s (reference)" % mathvariant)) 105 else: 106 reftest.write(source % ("text-transform math-%s" % mathvariant)) 107 reftestReference.write( 108 source % ("text-transform math-%s (reference)" % mathvariant)) 109 if mathvariant == "auto": 110 mathAssert = "Verify that a single-char <mi> is equivalent to an <mi> with the transformed italic unicode character." 111 mapping = "italic" 112 else: 113 mathAssert = "Verify that a single-char <mtext> with a %s mathvariant is equivalent to an <mtext> with the transformed unicode character." % mathvariant 114 mapping = mathvariant 115 if mathml: 116 source = '\ 117 <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">\n\ 118 <link rel="help" href="https://w3c.github.io/mathml-core/#the-mathvariant-attribute">\n\ 119 <link rel="help" href="https://w3c.github.io/mathml-core/#math-auto-transform">\n\ 120 <link rel="help" href="https://w3c.github.io/mathml-core/#%s-mappings">\n\ 121 <link rel="match" href="mathvariant-%s-ref.html"/>\n\ 122 <meta name="assert" content="%s">\n' 123 reftest.write(source % (mapping, mathvariant, mathAssert)) 124 else: 125 source = '\ 126 <link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>\n\ 127 <link rel="help" href="https://w3c.github.io/mathml-core/#math-auto-transform">\n\ 128 <link rel="help" href="https://w3c.github.io/mathml-core/#%s-mappings">\n\ 129 <link rel="match" href="text-transform-math-%s-001-ref.html"/>\n\ 130 <meta name="assert" content="Verify that a character with \'text-transform: math-%s\' renders the same as the transformed unicode character.">\n' 131 reftest.write(source % (mapping, mathvariant, mathvariant)) 132 WOFFfont = "mathvariant-%s.woff" % mapping 133 source = '\ 134 <style>\n\ 135 @font-face {\n\ 136 font-family: TestFont;\n\ 137 src: url("/fonts/math/%s");\n\ 138 }\n\ 139 body > span {\n\ 140 padding: 10px;\n\ 141 }\n\ 142 span > span {\n\ 143 font-family: monospace;\n\ 144 font-size: 10px;\n\ 145 }\n\ 146 .testfont {\n\ 147 font-family: TestFont;\n\ 148 font-size: 10px;\n\ 149 }\n\ 150 </style>\n\ 151 <body>\n\ 152 <!-- Generated by mathml/tools/mathvariant.py; DO NOT EDIT. -->\n\ 153 <p>Test passes if all the equalities below are true.</p>\n' % WOFFfont 154 if mathml: 155 reftest.write(source) 156 reftestReference.write(source) 157 else: 158 reftest.write(source) 159 reftestReference.write(source) 160 charIndex = 0 161 for baseChar in mathvariantTransforms[mathvariant]: 162 transformedChar = mathvariantTransforms[mathvariant][baseChar] 163 if mathvariant == "auto": 164 tokenTag = '<mi>&#x%0X;</mi>' % baseChar 165 tokenTagRef = '<mi>&#x%0X;</mi>' % transformedChar 166 else: 167 tokenTag = '<mtext mathvariant="%s">&#x%0X;</mtext>' % ( 168 mathvariant, baseChar) 169 tokenTagRef = '<mtext>&#x%0X;</mtext>' % transformedChar 170 if mathml: 171 reftest.write(' <span><math class="testfont">%s</math>=<span>%05X</span></span>' % 172 (tokenTag, transformedChar)) 173 reftestReference.write( 174 ' <span><math class="testfont">%s</math>=<span>%05X</span></span>' % (tokenTagRef, transformedChar)) 175 else: 176 reftest.write(' <span><span class="testfont" style="text-transform: math-%s">&#x%0X;</span>=<span>%05X</span></span>' % 177 (mathvariant, baseChar, transformedChar)) 178 reftestReference.write( 179 ' <span><span class="testfont">&#x%0X;</span>=<span>%05X</span></span>' % (transformedChar, transformedChar)) 180 charIndex += 1 181 if charIndex % 10 == 0: 182 reftest.write('<br/>') 183 reftestReference.write('<br/>') 184 reftest.write('\n') 185 reftestReference.write('\n') 186 source = '</body>\n</html>\n' 187 reftest.write(source) 188 reftestReference.write(source) 189 reftest.close() 190 reftestReference.close() 191 print(" done.") 192 193 194 # Generate css/css-text/text-transform/math/text-transform-math-auto-001.html 195 generateTestFor(mathvariant="auto", mathml=False) 196 generateTestFor(mathvariant="auto", mathml=True) 197 198 # Generate italic_mapping.js file used by selection tests. 199 print("Generating italic_mapping.js...", end="") 200 italic_mapping = open("../../css/css-text/text-transform/math/italic-mapping.js", "w") 201 italic_mapping.write("// Generated by mathml/tools/mathvariant.py; DO NOT EDIT.\n"); 202 italic_mapping.write("let italic_mapping = {\n"); 203 for baseChar in mathvariantTransforms["italic"]: 204 transformedChar = mathvariantTransforms[mathvariant][baseChar] 205 italic_mapping.write(" 0x%0X: 0x%0X,\n" % (baseChar, transformedChar)); 206 italic_mapping.write("}\n"); 207 italic_mapping.close() 208 print(" done.") 209 210 # Other mathvariant tests can be generated by the following command. They are 211 # still use internally by browsers implementing full mathvariant support. 212 # See https://github.com/w3c/mathml-core/issues/182 213 # for mathvariant in mathvariantTransforms: 214 # generateTestFor(mathvariant, mathml=True)