diff options
Diffstat (limited to 'testing/web-platform/tests/mathml/tools')
20 files changed, 1675 insertions, 0 deletions
diff --git a/testing/web-platform/tests/mathml/tools/axisheight.py b/testing/web-platform/tests/mathml/tools/axisheight.py new file mode 100755 index 0000000000..f27333132a --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/axisheight.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 + +from utils import mathfont +import fontforge + +verticalArrowCodePoint = 0x21A8 +v1 = 5 * mathfont.em +v2 = 14 * mathfont.em +f = mathfont.create("axisheight%d-verticalarrow%d" % (v1, v2), + "Copyright (c) 2016 MathML Association") +f.math.AxisHeight = v1 +f.math.MinConnectorOverlap = 0 +mathfont.createSquareGlyph(f, verticalArrowCodePoint) +g = f.createChar(-1, "size1") +mathfont.drawRectangleGlyph(g, mathfont.em, v2 / 2, 0) +g = f.createChar(-1, "size2") +mathfont.drawRectangleGlyph(g, mathfont.em, v2, 0) +g = f.createChar(-1, "bot") +mathfont.drawRectangleGlyph(g, mathfont.em, v2 + v1, 0) +g = f.createChar(-1, "ext") +mathfont.drawRectangleGlyph(g, mathfont.em, mathfont.em, 0) +f[verticalArrowCodePoint].verticalVariants = "uni21A8 size1 size2" +# Part: (glyphName, isExtender, startConnector, endConnector, fullAdvance) +f[verticalArrowCodePoint].verticalComponents = \ + (("bot", False, 0, mathfont.em, v2 + v1), ("ext", True, mathfont.em, mathfont.em, mathfont.em)); +mathfont.save(f) diff --git a/testing/web-platform/tests/mathml/tools/fractions.py b/testing/web-platform/tests/mathml/tools/fractions.py new file mode 100755 index 0000000000..bd39fc2fdb --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/fractions.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python3 + +from utils import mathfont +import fontforge + +v1 = 7 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("fraction-axisheight%d-rulethickness%d" % (v1, v2), + "Copyright (c) 2016 MathML Association") +f.math.AxisHeight = v1 +f.math.FractionDenominatorDisplayStyleGapMin = 0 +f.math.FractionDenominatorDisplayStyleShiftDown = 0 +f.math.FractionDenominatorGapMin = 0 +f.math.FractionDenominatorShiftDown = 0 +f.math.FractionNumeratorDisplayStyleGapMin = 0 +f.math.FractionNumeratorDisplayStyleShiftUp = 0 +f.math.FractionNumeratorGapMin = 0 +f.math.FractionNumeratorShiftUp = 0 +f.math.FractionRuleThickness = v2 +mathfont.save(f) + +v1 = 5 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("fraction-denominatordisplaystylegapmin%d-rulethickness%d" % (v1, v2), + "Copyright (c) 2016 MathML Association") +f.math.AxisHeight = 0 +f.math.FractionDenominatorDisplayStyleGapMin = v1 +f.math.FractionDenominatorDisplayStyleShiftDown = 0 +f.math.FractionDenominatorGapMin = 0 +f.math.FractionDenominatorShiftDown = 0 +f.math.FractionNumeratorDisplayStyleGapMin = 0 +f.math.FractionNumeratorDisplayStyleShiftUp = 0 +f.math.FractionNumeratorGapMin = 0 +f.math.FractionNumeratorShiftUp = 0 +f.math.FractionRuleThickness = v2 +mathfont.save(f) + +v1 = 6 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("fraction-denominatordisplaystyleshiftdown%d-axisheight%d-rulethickness%d" % (v1, v2, v2), + "Copyright (c) 2016 MathML Association") +f.math.AxisHeight = v2 +f.math.FractionDenominatorDisplayStyleGapMin = 0 +f.math.FractionDenominatorDisplayStyleShiftDown = v1 +f.math.FractionDenominatorGapMin = 0 +f.math.FractionDenominatorShiftDown = 0 +f.math.FractionNumeratorDisplayStyleGapMin = 0 +f.math.FractionNumeratorDisplayStyleShiftUp = 0 +f.math.FractionNumeratorGapMin = 0 +f.math.FractionNumeratorShiftUp = 0 +f.math.FractionRuleThickness = v2 +mathfont.save(f) + +v1 = 4 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("fraction-denominatorgapmin%d-rulethickness%d" % (v1, v2), + "Copyright (c) 2016 MathML Association") +f.math.AxisHeight = 0 +f.math.FractionDenominatorDisplayStyleGapMin = 0 +f.math.FractionDenominatorDisplayStyleShiftDown = 0 +f.math.FractionDenominatorGapMin = v1 +f.math.FractionDenominatorShiftDown = 0 +f.math.FractionNumeratorDisplayStyleGapMin = 0 +f.math.FractionNumeratorDisplayStyleShiftUp = 0 +f.math.FractionNumeratorGapMin = 0 +f.math.FractionNumeratorShiftUp = 0 +f.math.FractionRuleThickness = v2 +mathfont.save(f) + +v1 = 3 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("fraction-denominatorshiftdown%d-axisheight%d-rulethickness%d" % (v1, v2, v2), + "Copyright (c) 2016 MathML Association") +f.math.AxisHeight = v2 +f.math.FractionDenominatorDisplayStyleGapMin = 0 +f.math.FractionDenominatorDisplayStyleShiftDown = 0 +f.math.FractionDenominatorGapMin = 0 +f.math.FractionDenominatorShiftDown = v1 +f.math.FractionNumeratorDisplayStyleGapMin = 0 +f.math.FractionNumeratorDisplayStyleShiftUp = 0 +f.math.FractionNumeratorGapMin = 0 +f.math.FractionNumeratorShiftUp = 0 +f.math.FractionRuleThickness = v2 +mathfont.save(f) + +v1 = 8 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("fraction-numeratordisplaystylegapmin%d-rulethickness%d" % (v1, v2), + "Copyright (c) 2016 MathML Association") +f.math.AxisHeight = 0 +f.math.FractionDenominatorDisplayStyleGapMin = 0 +f.math.FractionDenominatorDisplayStyleShiftDown = 0 +f.math.FractionDenominatorGapMin = 0 +f.math.FractionDenominatorShiftDown = 0 +f.math.FractionNumeratorDisplayStyleGapMin = v1 +f.math.FractionNumeratorDisplayStyleShiftUp = 0 +f.math.FractionNumeratorGapMin = 0 +f.math.FractionNumeratorShiftUp = 0 +f.math.FractionRuleThickness = v2 +mathfont.save(f) + +v1 = 2 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("fraction-numeratordisplaystyleshiftup%d-axisheight%d-rulethickness%d" % (v1, v2, v2), + "Copyright (c) 2016 MathML Association") +f.math.AxisHeight = v2 +f.math.FractionDenominatorDisplayStyleGapMin = 0 +f.math.FractionDenominatorDisplayStyleShiftDown = 0 +f.math.FractionDenominatorGapMin = 0 +f.math.FractionDenominatorShiftDown = 0 +f.math.FractionNumeratorDisplayStyleGapMin = 0 +f.math.FractionNumeratorDisplayStyleShiftUp = v1 +f.math.FractionNumeratorGapMin = 0 +f.math.FractionNumeratorShiftUp = 0 +f.math.FractionRuleThickness = v2 +mathfont.save(f) + +v1 = 9 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("fraction-numeratorgapmin%d-rulethickness%d" % (v1, v2), + "Copyright (c) 2016 MathML Association") +f.math.AxisHeight = 0 +f.math.FractionDenominatorDisplayStyleGapMin = 0 +f.math.FractionDenominatorDisplayStyleShiftDown = 0 +f.math.FractionDenominatorGapMin = 0 +f.math.FractionDenominatorShiftDown = 0 +f.math.FractionNumeratorDisplayStyleGapMin = 0 +f.math.FractionNumeratorDisplayStyleShiftUp = 0 +f.math.FractionNumeratorGapMin = v1 +f.math.FractionNumeratorShiftUp = 0 +f.math.FractionRuleThickness = v2 +mathfont.save(f) + +v1 = 11 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("fraction-numeratorshiftup%d-axisheight%d-rulethickness%d" % (v1, v2, v2), + "Copyright (c) 2016 MathML Association") +f.math.AxisHeight = v2 +f.math.FractionDenominatorDisplayStyleGapMin = 0 +f.math.FractionDenominatorDisplayStyleShiftDown = 0 +f.math.FractionDenominatorGapMin = 0 +f.math.FractionDenominatorShiftDown = 0 +f.math.FractionNumeratorDisplayStyleGapMin = 0 +f.math.FractionNumeratorDisplayStyleShiftUp = 0 +f.math.FractionNumeratorGapMin = 0 +f.math.FractionNumeratorShiftUp = v1 +f.math.FractionRuleThickness = v2 +mathfont.save(f) + +v1 = 10 * mathfont.em +f = mathfont.create("fraction-rulethickness%d" % v1, + "Copyright (c) 2016 MathML Association") +f.math.AxisHeight = 0 +f.math.FractionDenominatorDisplayStyleGapMin = 0 +f.math.FractionDenominatorDisplayStyleShiftDown = 0 +f.math.FractionDenominatorGapMin = 0 +f.math.FractionDenominatorShiftDown = 0 +f.math.FractionNumeratorDisplayStyleGapMin = 0 +f.math.FractionNumeratorDisplayStyleShiftUp = 0 +f.math.FractionNumeratorGapMin = 0 +f.math.FractionNumeratorShiftUp = 0 +f.math.FractionRuleThickness = v1 +mathfont.save(f) diff --git a/testing/web-platform/tests/mathml/tools/largeop.py b/testing/web-platform/tests/mathml/tools/largeop.py new file mode 100755 index 0000000000..a4955e1f6c --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/largeop.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +from utils import mathfont +import fontforge + +nAryWhiteVerticalBarCodePoint = 0x2AFF +v1 = 5 * mathfont.em +f = mathfont.create("largeop-displayoperatorminheight%d" % v1, + "Copyright (c) 2016 MathML Association") +f.math.DisplayOperatorMinHeight = v1 +mathfont.createSquareGlyph(f, nAryWhiteVerticalBarCodePoint) +g = f.createChar(-1, "uni2AFF.display") +mathfont.drawRectangleGlyph(g, mathfont.em, v1, 0) +f[nAryWhiteVerticalBarCodePoint].verticalVariants = "uni2AFF uni2AFF.display" +mathfont.save(f) + +v1 = 2 * mathfont.em +v2 = 3 * mathfont.em +f = mathfont.create("largeop-displayoperatorminheight%d-2AFF-italiccorrection%d" % (v1, v2), + "Copyright (c) 2018 Igalia S.L.") +f.math.DisplayOperatorMinHeight = v1 +mathfont.createSquareGlyph(f, nAryWhiteVerticalBarCodePoint) +g = f.createChar(-1, "uni2AFF.display") +p = g.glyphPen() +p.moveTo(0, 0) +p.lineTo(v2, v1) +p.lineTo(v2 + mathfont.em, v1) +p.lineTo(mathfont.em, 0) +p.closePath(); +g.width = mathfont.em + v2 +g.italicCorrection = v2 +f[nAryWhiteVerticalBarCodePoint].verticalVariants = "uni2AFF uni2AFF.display" +mathfont.save(f) + +v1 = 7 * mathfont.em +v2 = 5 * mathfont.em +f = mathfont.create("largeop-displayoperatorminheight%d-2AFF-italiccorrection%d" % (v1, v2), + "Copyright (c) 2020 Igalia S.L.") +f.math.DisplayOperatorMinHeight = v1 +f.math.MinConnectorOverlap = 0 +mathfont.createSquareGlyph(f, nAryWhiteVerticalBarCodePoint) +g = f.createChar(-1, "uni2AFF.bot") +mathfont.drawRectangleGlyph(g, + width = 2 * mathfont.em, + ascent = mathfont.em) +g = f.createChar(-1, "uni2AFF.ext") +mathfont.drawRectangleGlyph(g, + width = mathfont.em, + ascent = 2 * mathfont.em, + padding_left = mathfont.em) +g = f.createChar(-1, "uni2AFF.top") +mathfont.drawRectangleGlyph(g, + width = v2 + mathfont.em, + ascent = mathfont.em, + padding_left = mathfont.em) +f[nAryWhiteVerticalBarCodePoint].verticalVariants = "uni2AFF" +# Part: (glyphName, isExtender, startConnector, endConnector, fullAdvance) +f[nAryWhiteVerticalBarCodePoint].verticalComponents = \ + (("uni2AFF.bot", False, 0, mathfont.em // 2, mathfont.em), + ("uni2AFF.ext", True, mathfont.em // 2, mathfont.em // 2, 2 * mathfont.em), + ("uni2AFF.top", False, mathfont.em // 2, 0, mathfont.em) + ); +f[nAryWhiteVerticalBarCodePoint].verticalComponentItalicCorrection = v2 +mathfont.save(f) diff --git a/testing/web-platform/tests/mathml/tools/limits.py b/testing/web-platform/tests/mathml/tools/limits.py new file mode 100755 index 0000000000..6abd2bc23e --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/limits.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 + +from utils import mathfont +import fontforge + +nArySumCodePoint = 0x2211 # largeop operator + +v = 3 * mathfont.em +f = mathfont.create("limits-lowerlimitbaselinedropmin%d" % v, + "Copyright (c) 2016 MathML Association") +mathfont.createSquareGlyph(f, nArySumCodePoint) +f.math.LowerLimitBaselineDropMin = v +f.math.LowerLimitGapMin = 0 +f.math.OverbarExtraAscender = 0 +f.math.OverbarVerticalGap = 0 +f.math.StretchStackBottomShiftDown = 0 +f.math.StretchStackGapAboveMin = 0 +f.math.StretchStackGapBelowMin = 0 +f.math.StretchStackTopShiftUp = 0 +f.math.UnderbarExtraDescender = 0 +f.math.UnderbarVerticalGap = 0 +f.math.UpperLimitBaselineRiseMin = 0 +f.math.UpperLimitGapMin = 0 +mathfont.save(f) + +v = 11 * mathfont.em +f = mathfont.create("limits-lowerlimitgapmin%d" % v, + "Copyright (c) 2016 MathML Association") +mathfont.createSquareGlyph(f, nArySumCodePoint) +f.math.LowerLimitBaselineDropMin = 0 +f.math.LowerLimitGapMin = v +f.math.OverbarExtraAscender = 0 +f.math.OverbarVerticalGap = 0 +f.math.StretchStackBottomShiftDown = 0 +f.math.StretchStackGapAboveMin = 0 +f.math.StretchStackGapBelowMin = 0 +f.math.StretchStackTopShiftUp = 0 +f.math.UnderbarExtraDescender = 0 +f.math.UnderbarVerticalGap = 0 +f.math.UpperLimitBaselineRiseMin = 0 +f.math.UpperLimitGapMin = 0 +mathfont.save(f) + +v = 5 * mathfont.em +f = mathfont.create("limits-upperlimitbaselinerisemin%d" % v, + "Copyright (c) 2016 MathML Association") +mathfont.createSquareGlyph(f, nArySumCodePoint) +f.math.LowerLimitBaselineDropMin = 0 +f.math.LowerLimitGapMin = 0 +f.math.OverbarExtraAscender = 0 +f.math.OverbarVerticalGap = 0 +f.math.StretchStackBottomShiftDown = 0 +f.math.StretchStackGapAboveMin = 0 +f.math.StretchStackGapBelowMin = 0 +f.math.StretchStackTopShiftUp = 0 +f.math.UnderbarExtraDescender = 0 +f.math.UnderbarVerticalGap = 0 +f.math.UpperLimitBaselineRiseMin = v +f.math.UpperLimitGapMin = 0 +mathfont.save(f) + +v = 7 * mathfont.em +f = mathfont.create("limits-upperlimitgapmin%d" % v, + "Copyright (c) 2016 MathML Association") +mathfont.createSquareGlyph(f, nArySumCodePoint) +f.math.LowerLimitBaselineDropMin = 0 +f.math.LowerLimitGapMin = 0 +f.math.OverbarExtraAscender = 0 +f.math.OverbarVerticalGap = 0 +f.math.StretchStackBottomShiftDown = 0 +f.math.StretchStackGapAboveMin = 0 +f.math.StretchStackGapBelowMin = 0 +f.math.StretchStackTopShiftUp = 0 +f.math.UnderbarExtraDescender = 0 +f.math.UnderbarVerticalGap = 0 +f.math.UpperLimitBaselineRiseMin = 0 +f.math.UpperLimitGapMin = v +mathfont.save(f) diff --git a/testing/web-platform/tests/mathml/tools/math-text.py b/testing/web-platform/tests/mathml/tools/math-text.py new file mode 100755 index 0000000000..1deb9bd591 --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/math-text.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +import fontforge + +font = fontforge.font() +font.em = 1000 +lineHeight = 5000 +name = "math-text" +font.fontname = name +font.familyname = name +font.fullname = name +font.copyright = "Copyright (c) 2019 Igalia" + +glyph = font.createChar(ord(" "), "space") +glyph.width = 1000 +glyph = font.createChar(ord("A")) +pen = glyph.glyphPen() +pen.moveTo(0, -500) +pen.lineTo(0, 500) +pen.lineTo(1000, 500) +pen.lineTo(1000, -500) +pen.closePath(); + +glyph = font.createChar(ord("B")) +pen = glyph.glyphPen() +pen.moveTo(0, 0) +pen.lineTo(0, 1000) +pen.lineTo(1000, 1000) +pen.lineTo(1000, 0) +pen.closePath(); + +glyph = font.createChar(ord("C")) +pen = glyph.glyphPen() +pen.moveTo(0, -1000) +pen.lineTo(0, 0) +pen.lineTo(1000, 0) +pen.lineTo(1000, -1000) +pen.closePath(); + +font.os2_typoascent_add = False +font.os2_typoascent = lineHeight // 2 +font.os2_typodescent_add = False +font.os2_typodescent = -lineHeight // 2 +font.os2_typolinegap = 0 +font.hhea_ascent = lineHeight // 2 +font.hhea_ascent_add = False +font.hhea_descent = -lineHeight // 2 +font.hhea_descent_add = False +font.hhea_linegap = 0 +font.os2_winascent = lineHeight // 2 +font.os2_winascent_add = False +font.os2_windescent = lineHeight // 2 +font.os2_windescent_add = False + +font.os2_use_typo_metrics = True + +path = "../../fonts/math/math-text.woff" +print("Generating %s..." % path, end="") +font.generate(path) +if font.validate() == 0: + print(" done.") +else: + print(" validation error!") + exit(1) diff --git a/testing/web-platform/tests/mathml/tools/mathvariant-transforms.py b/testing/web-platform/tests/mathml/tools/mathvariant-transforms.py new file mode 100755 index 0000000000..49c20876a3 --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/mathvariant-transforms.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python3 + +from lxml import etree +from utils.misc import downloadWithProgressBar, UnicodeXMLURL +from utils import mathfont + +# Retrieve the unicode.xml file if necessary. +unicodeXML = downloadWithProgressBar(UnicodeXMLURL) + +# Extract the mathvariants transformation. +xsltTransform = etree.XSLT(etree.XML('''\ +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + <xsl:strip-space elements="*"/> + <xsl:template match="charlist"> + <root><xsl:apply-templates select="character"/></root> + </xsl:template> + <xsl:template match="character"> + <xsl:if test="surrogate"> + <entry> + <xsl:attribute name="mathvariant"> + <xsl:value-of select="surrogate/@mathvariant"/> + </xsl:attribute> + <xsl:attribute name="baseChar"> + <xsl:value-of select="surrogate/@ref"/> + </xsl:attribute> + <xsl:attribute name="transformedChar"> + <xsl:choose> + <xsl:when test="bmp"> + <xsl:value-of select="bmp/@ref"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@id"/> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </entry> + </xsl:if> + </xsl:template> +</xsl:stylesheet>''')) + +# Put the mathvariant transforms into a Python structure. +mathvariantTransforms = {} +root = xsltTransform(etree.parse(unicodeXML)).getroot() +def parseCodePoint(aHexaString): + return int("0x%s" % aHexaString[1:], 16) +for entry in root: + mathvariant = entry.get("mathvariant") + baseChar = parseCodePoint(entry.get("baseChar")) + transformedChar = parseCodePoint(entry.get("transformedChar")) + if mathvariant not in mathvariantTransforms: + mathvariantTransforms[mathvariant] = {} + mathvariantTransforms[mathvariant][baseChar] = transformedChar + +# There is no "isolated" mathvariant. +del mathvariantTransforms["isolated"] + +# Automatic mathvariant uses the same transform as italic. +# It is handled specially (see below). +mathvariantTransforms["auto"] = mathvariantTransforms["italic"] + +# Create a WOFF font for each mathvariant. +for mathvariant in mathvariantTransforms: + if mathvariant == "auto": + continue + font = mathfont.create("mathvariant-%s" % mathvariant, "Copyright (c) 2016 MathML Association") + for baseChar in mathvariantTransforms[mathvariant]: + if baseChar not in font: + mathfont.createGlyphFromValue(font, baseChar) + transformedChar = mathvariantTransforms[mathvariant][baseChar] + mathfont.createGlyphFromValue(font, transformedChar) + mathfont.save(font) + +# Create a MathML and CSS test for each mathvariant. +for mathvariant in mathvariantTransforms: + print("Generating tests for %s..." % mathvariant, end="") + reftest = open("../relations/css-styling/mathvariant-%s.html" % mathvariant, "w") + reftestReference = open("../relations/css-styling/mathvariant-%s-ref.html" % mathvariant, "w") + CSSreftest = open("../../css/css-text/text-transform/math/text-transform-math-%s-001.tentative.html" % mathvariant, "w") + CSSreftestReference = open("../../css/css-text/text-transform/math/text-transform-math-%s-001.tentative-ref.html" % mathvariant, "w") + source = '\ +<!DOCTYPE html>\n\ +<html>\n\ +<head>\n\ +<meta charset="utf-8"/>\n\ +<title>%s</title>\n' + reftest.write(source % ("mathvariant %s" % mathvariant)) + reftestReference.write(source % ("mathvariant %s (reference)" % mathvariant)) + CSSreftest.write(source % ("text-transform math-%s" % mathvariant)) + CSSreftestReference.write(source % ("text-transform math-%s (reference)" % mathvariant)) + if mathvariant == "auto": + mathAssert = "Verify that a single-char <mi> is equivalent to an <mi> with the transformed italic unicode character." + mapping = "italic" + else: + mathAssert = "Verify that a single-char <mtext> with a %s mathvariant is equivalent to an <mtext> with the transformed unicode character." % mathvariant + mapping = mathvariant + source ='\ +<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">\n\ +<link rel="help" href="https://w3c.github.io/mathml-core/#the-mathvariant-attribute">\n\ +<link rel="help" href="https://w3c.github.io/mathml-core/#new-text-transform-values">\n\ +<link rel="help" href="https://w3c.github.io/mathml-core/#%s-mappings">\n\ +<link rel="match" href="mathvariant-%s-ref.html"/>\n\ +<meta name="assert" content="%s">\n' + reftest.write(source % (mapping, mathvariant, mathAssert)) + source = '\ +<link rel="help" href="https://github.com/w3c/csswg-drafts/issues/3745"/>\n\ +<link rel="help" href="https://w3c.github.io/mathml-core/#new-text-transform-values">\n\ +<link rel="help" href="https://w3c.github.io/mathml-core/#%s-mappings">\n\ +<link rel="match" href="text-transform-math-%s-001.tentative-ref.html"/>\n\ +<meta name="assert" content="Verify that a character with \'text-transform: math-%s\' renders the same as the transformed unicode character.">\n' + CSSreftest.write(source % (mapping, mathvariant, mathvariant)) + WOFFfont = "mathvariant-%s.woff" % mapping + source = '\ +<style>\n\ + @font-face {\n\ + font-family: TestFont;\n\ + src: url("/fonts/math/%s");\n\ + }\n\ + body > span {\n\ + padding: 10px;\n\ + }\n\ + span > span {\n\ + font-family: monospace;\n\ + font-size: 10px;\n\ + }\n\ + .testfont {\n\ + font-family: TestFont;\n\ + font-size: 10px;\n\ + }\n\ +</style>\n\ +<body>\n\ + <!-- Generated by mathml/tools/mathvariant.py; DO NOT EDIT. -->\n\ + <p>Test passes if all the equalities below are true.</p>\n' % WOFFfont + reftest.write(source) + reftestReference.write(source) + CSSreftest.write(source) + CSSreftestReference.write(source) + charIndex = 0 + for baseChar in mathvariantTransforms[mathvariant]: + transformedChar = mathvariantTransforms[mathvariant][baseChar] + if mathvariant == "auto": + tokenTag = '<mi>&#x%0X;</mi>' % baseChar + tokenTagRef = '<mi>&#x%0X;</mi>' % transformedChar + else: + tokenTag = '<mtext mathvariant="%s">&#x%0X;</mtext>' % (mathvariant, baseChar) + tokenTagRef = '<mtext>&#x%0X;</mtext>' % transformedChar + reftest.write(' <span><math class="testfont">%s</math>=<span>%05X</span></span>' % (tokenTag, transformedChar)) + reftestReference.write(' <span><math class="testfont">%s</math>=<span>%05X</span></span>' % (tokenTagRef, transformedChar)) + CSSreftest.write(' <span><span class="testfont" style="text-transform: math-%s">&#x%0X;</span>=<span>%05X</span></span>' % (mathvariant, baseChar, transformedChar)) + CSSreftestReference.write(' <span><span class="testfont">&#x%0X;</span>=<span>%05X</span></span>' % (transformedChar, transformedChar)) + charIndex += 1 + if charIndex % 10 == 0: + reftest.write('<br/>') + reftestReference.write('<br/>') + CSSreftest.write('<br/>') + CSSreftestReference.write('<br/>') + reftest.write('\n') + reftestReference.write('\n') + CSSreftest.write('\n') + CSSreftestReference.write('\n') + source = '</body>\n</html>\n' + reftest.write(source) + reftestReference.write(source) + CSSreftest.write(source) + CSSreftestReference.write(source) + reftest.close() + reftestReference.close() + CSSreftest.close() + CSSreftestReference.close() + print(" done.") 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) diff --git a/testing/web-platform/tests/mathml/tools/operator-dictionary.xsl b/testing/web-platform/tests/mathml/tools/operator-dictionary.xsl new file mode 100644 index 0000000000..8c75317672 --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/operator-dictionary.xsl @@ -0,0 +1,73 @@ +<!-- -*- Mode: nXML; tab-width: 2; indent-tabs-mode: nil; -*- --> +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + + <xsl:strip-space elements="*"/> + + <xsl:template match="charlist"> + <root><xsl:apply-templates select="character"/></root> + </xsl:template> + + <xsl:template match="character"> + <xsl:if test="operator-dictionary"> + <xsl:for-each select="operator-dictionary"> + <entry> + + <xsl:attribute name="unicode"> + <xsl:value-of select="../@id"/> + </xsl:attribute> + + <xsl:attribute name="form"> + <xsl:value-of select="@form"/> + </xsl:attribute> + + <!-- begin operator-dictionary --> + <xsl:if test="@lspace"> + <xsl:attribute name="lspace"> + <xsl:value-of select="@lspace"/> + </xsl:attribute> + </xsl:if> + <xsl:if test="@rspace"> + <xsl:attribute name="rspace"> + <xsl:value-of select="@rspace"/> + </xsl:attribute> + </xsl:if> + <xsl:if test="@minsize"> + <xsl:attribute name="minsize"> + <xsl:value-of select="@minsize"/> + </xsl:attribute> + </xsl:if> + <xsl:if test="@*[.='true']"> + <xsl:attribute name="properties"> + <!-- largeop, movablelimits, stretchy, separator, accent, fence, + symmetric --> + <xsl:for-each select="@*[.='true']"> + <xsl:value-of select="name()"/> + <xsl:text> </xsl:text> + </xsl:for-each> + <xsl:if test="../unicodedata/@mirror = 'Y'"> + <xsl:text>mirrorable </xsl:text> + </xsl:if> + </xsl:attribute> + </xsl:if> + <xsl:if test="@priority"> + <xsl:attribute name="priority"> + <xsl:value-of select="@priority"/> + </xsl:attribute> + </xsl:if> + <xsl:if test="@linebreakstyle"> + <xsl:attribute name="linebreakstyle"> + <xsl:value-of select="@linebreakstyle"/> + </xsl:attribute> + </xsl:if> + <!-- end operator-dictionary --> + + <xsl:attribute name="description"> + <xsl:value-of select="../description"/> + </xsl:attribute> + + </entry> + </xsl:for-each> + </xsl:if> + </xsl:template> + +</xsl:stylesheet> diff --git a/testing/web-platform/tests/mathml/tools/percentscaledown.py b/testing/web-platform/tests/mathml/tools/percentscaledown.py new file mode 100755 index 0000000000..ef40d1fd87 --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/percentscaledown.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +from utils import mathfont +import fontforge + +v1 = 80 +v2 = 40 +f = mathfont.create("scriptpercentscaledown%d-scriptscriptpercentscaledown%d" % (v1, v2), + "Copyright (c) 2019 Igalia S.L.") +f.math.ScriptPercentScaleDown = v1 +f.math.ScriptScriptPercentScaleDown = v2 +mathfont.save(f) + +f = mathfont.create("scriptpercentscaledown0-scriptscriptpercentscaledown%d" % v2, + "Copyright (c) 2019 Igalia S.L.") +f.math.ScriptPercentScaleDown = 0 +f.math.ScriptScriptPercentScaleDown = v2 +mathfont.save(f) + +f = mathfont.create("scriptpercentscaledown%d-scriptscriptpercentscaledown0" % v1, + "Copyright (c) 2019 Igalia S.L.") +f.math.ScriptPercentScaleDown = v1 +f.math.ScriptScriptPercentScaleDown = 0 +mathfont.save(f) diff --git a/testing/web-platform/tests/mathml/tools/radicals.py b/testing/web-platform/tests/mathml/tools/radicals.py new file mode 100755 index 0000000000..95dc3345a9 --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/radicals.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 + +from utils import mathfont +import fontforge + +def createStretchyRadical(aFont): + radicalCodePoint = 0x221a + mathfont.createSquareGlyph(aFont, radicalCodePoint) + g = aFont.createChar(-1, "size1") + mathfont.drawRectangleGlyph(g, mathfont.em, 2 * mathfont.em, 0) + g = aFont.createChar(-1, "size2") + mathfont.drawRectangleGlyph(g, mathfont.em, 3 * mathfont.em, 0) + g = aFont.createChar(-1, "size3") + mathfont.drawRectangleGlyph(g, mathfont.em, 4 * mathfont.em, 0) + aFont[radicalCodePoint].verticalVariants = "radical size1 size2 size3" + # Part: (glyphName, isExtender, startConnector, endConnector, fullAdvance) + aFont.math.MinConnectorOverlap = 0 + aFont[radicalCodePoint].verticalComponents = \ + (("size2", False, 0, mathfont.em, 3 * mathfont.em), \ + ("size1", True, mathfont.em, mathfont.em, 2 * mathfont.em)) + +v1 = 25 +v2 = 1 * mathfont.em +f = mathfont.create("radical-degreebottomraisepercent%d-rulethickness%d" % (v1, v2), + "Copyright (c) 2016 MathML Association") +createStretchyRadical(f) +f.math.RadicalDegreeBottomRaisePercent = v1 +f.math.RadicalDisplayStyleVerticalGap = 0 +f.math.RadicalExtraAscender = 0 +f.math.RadicalKernAfterDegree = 0 +f.math.RadicalKernBeforeDegree = 0 +f.math.RadicalRuleThickness = v2 +f.math.RadicalVerticalGap = 0 +mathfont.save(f) + +v1 = 7 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("radical-displaystyleverticalgap%d-rulethickness%d" % (v1, v2), + "Copyright (c) 2016 MathML Association") +createStretchyRadical(f) +f.math.RadicalDegreeBottomRaisePercent = 0 +f.math.RadicalDisplayStyleVerticalGap = v1 +f.math.RadicalExtraAscender = 0 +f.math.RadicalKernAfterDegree = 0 +f.math.RadicalKernBeforeDegree = 0 +f.math.RadicalRuleThickness = v2 +f.math.RadicalVerticalGap = 0 +mathfont.save(f) + +v1 = 3 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("radical-extraascender%d-rulethickness%d" % (v1, v2), + "Copyright (c) 2016 MathML Association") +createStretchyRadical(f) +f.math.RadicalDegreeBottomRaisePercent = 0 +f.math.RadicalDisplayStyleVerticalGap = 0 +f.math.RadicalExtraAscender = v1 +f.math.RadicalKernAfterDegree = 0 +f.math.RadicalKernBeforeDegree = 0 +f.math.RadicalRuleThickness = v2 +f.math.RadicalVerticalGap = 0 +mathfont.save(f) + +v1 = 5 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("radical-kernafterdegreeminus%d-rulethickness%d" % (v1, v2), + "Copyright (c) 2016 MathML Association") +createStretchyRadical(f) +f.math.RadicalDegreeBottomRaisePercent = 0 +f.math.RadicalDisplayStyleVerticalGap = 0 +f.math.RadicalExtraAscender = 0 +f.math.RadicalKernAfterDegree = -v1 +f.math.RadicalKernBeforeDegree = 0 +f.math.RadicalRuleThickness = v2 +f.math.RadicalVerticalGap = 0 +mathfont.save(f) + +v1 = 4 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("radical-kernbeforedegree%d-rulethickness%d" % (v1, v2), + "Copyright (c) 2016 MathML Association") +createStretchyRadical(f) +f.math.RadicalDegreeBottomRaisePercent = 0 +f.math.RadicalDisplayStyleVerticalGap = 0 +f.math.RadicalExtraAscender = 0 +f.math.RadicalKernAfterDegree = 0 +f.math.RadicalKernBeforeDegree = v1 +f.math.RadicalRuleThickness = v2 +f.math.RadicalVerticalGap = 0 +mathfont.save(f) + +v = 8 * mathfont.em +f = mathfont.create("radical-rulethickness%d" % v, + "Copyright (c) 2016 MathML Association") +createStretchyRadical(f) +f.math.RadicalDegreeBottomRaisePercent = 0 +f.math.RadicalDisplayStyleVerticalGap = 0 +f.math.RadicalExtraAscender = 0 +f.math.RadicalKernAfterDegree = 0 +f.math.RadicalKernBeforeDegree = 0 +f.math.RadicalRuleThickness = v +f.math.RadicalVerticalGap = 0 +mathfont.save(f) + +v1 = 6 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("radical-verticalgap%d-rulethickness%d" % (v1, v2), + "Copyright (c) 2016 MathML Association") +createStretchyRadical(f) +f.math.RadicalDegreeBottomRaisePercent = 0 +f.math.RadicalDisplayStyleVerticalGap = 0 +f.math.RadicalExtraAscender = 0 +f.math.RadicalKernAfterDegree = 0 +f.math.RadicalKernBeforeDegree = 0 +f.math.RadicalRuleThickness = v2 +f.math.RadicalVerticalGap = v1 +mathfont.save(f) + +v1 = 1 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("radical-negativekernbeforedegree%d-rulethickness%d" % (v1, v2), "Copyright (c) 2020 Igalia S.L.") +createStretchyRadical(f) +f.math.RadicalDegreeBottomRaisePercent = 0 +f.math.RadicalDisplayStyleVerticalGap = 0 +f.math.RadicalExtraAscender = 0 +f.math.RadicalKernAfterDegree = 0 +f.math.RadicalKernBeforeDegree = -v1 +f.math.RadicalRuleThickness = v2 +f.math.RadicalVerticalGap = 0 +mathfont.save(f) diff --git a/testing/web-platform/tests/mathml/tools/scripts.py b/testing/web-platform/tests/mathml/tools/scripts.py new file mode 100755 index 0000000000..e1da482a00 --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/scripts.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 + +from utils import mathfont +import fontforge + +v = 3 * mathfont.em +f = mathfont.create("scripts-spaceafterscript%d" % v, + "Copyright (c) 2016 MathML Association") +f.math.SpaceAfterScript = v +f.math.SubSuperscriptGapMin = 0 +f.math.SubscriptBaselineDropMin = 0 +f.math.SubscriptShiftDown = 0 +f.math.SubscriptTopMax = 0 +f.math.SuperscriptBaselineDropMax = 0 +f.math.SuperscriptBottomMaxWithSubscript = 0 +f.math.SuperscriptBottomMin = 0 +f.math.SuperscriptShiftUp = 0 +f.math.SuperscriptShiftUpCramped = 0 +mathfont.save(f) + +v = 7 * mathfont.em +f = mathfont.create("scripts-superscriptshiftup%d" % v, + "Copyright (c) 2016 MathML Association") +f.math.SpaceAfterScript = 0 +f.math.SubSuperscriptGapMin = 0 +f.math.SubscriptBaselineDropMin = 0 +f.math.SubscriptShiftDown = 0 +f.math.SubscriptTopMax = 0 +f.math.SuperscriptBaselineDropMax = 0 +f.math.SuperscriptBottomMaxWithSubscript = 0 +f.math.SuperscriptBottomMin = 0 +f.math.SuperscriptShiftUp = v +f.math.SuperscriptShiftUpCramped = 0 +mathfont.save(f) + +v = 5 * mathfont.em +f = mathfont.create("scripts-superscriptshiftupcramped%d" % v, + "Copyright (c) 2016 MathML Association") +f.math.SpaceAfterScript = 0 +f.math.SubSuperscriptGapMin = 0 +f.math.SubscriptBaselineDropMin = 0 +f.math.SubscriptShiftDown = 0 +f.math.SubscriptTopMax = 0 +f.math.SuperscriptBaselineDropMax = 0 +f.math.SuperscriptBottomMaxWithSubscript = 0 +f.math.SuperscriptBottomMin = 0 +f.math.SuperscriptShiftUp = 0 +f.math.SuperscriptShiftUpCramped = v +mathfont.save(f) + +v = 6 * mathfont.em +f = mathfont.create("scripts-subscriptshiftdown%d" % v, + "Copyright (c) 2016 MathML Association") +f.math.SpaceAfterScript = 0 +f.math.SubSuperscriptGapMin = 0 +f.math.SubscriptBaselineDropMin = 0 +f.math.SubscriptShiftDown = v +f.math.SubscriptTopMax = 0 +f.math.SuperscriptBaselineDropMax = 0 +f.math.SuperscriptBottomMaxWithSubscript = 0 +f.math.SuperscriptBottomMin = 0 +f.math.SuperscriptShiftUp = 0 +f.math.SuperscriptShiftUpCramped = 0 +mathfont.save(f) + +v = 11 * mathfont.em +f = mathfont.create("scripts-subsuperscriptgapmin%d" % v, + "Copyright (c) 2016 MathML Association") +f.math.SpaceAfterScript = 0 +f.math.SubSuperscriptGapMin = v +f.math.SubscriptBaselineDropMin = 0 +f.math.SubscriptShiftDown = 0 +f.math.SubscriptTopMax = 0 +f.math.SuperscriptBaselineDropMax = 0 +f.math.SuperscriptBottomMaxWithSubscript = 0 +f.math.SuperscriptBottomMin = 0 +f.math.SuperscriptShiftUp = 0 +f.math.SuperscriptShiftUpCramped = 0 +mathfont.save(f) + +v1 = 11 * mathfont.em +v2 = 3 * mathfont.em +f = mathfont.create("scripts-subsuperscriptgapmin%d-superscriptbottommaxwithsubscript%d" % (v1, v2), + "Copyright (c) 2016 MathML Association") +f.math.SpaceAfterScript = 0 +f.math.SubSuperscriptGapMin = v1 +f.math.SubscriptBaselineDropMin = 0 +f.math.SubscriptShiftDown = 0 +f.math.SubscriptTopMax = 0 +f.math.SuperscriptBaselineDropMax = 0 +f.math.SuperscriptBottomMaxWithSubscript = v2 +f.math.SuperscriptBottomMin = 0 +f.math.SuperscriptShiftUp = 0 +f.math.SuperscriptShiftUpCramped = 0 +mathfont.save(f) + +v = 4 * mathfont.em +f = mathfont.create("scripts-subscripttopmax%d" % v, + "Copyright (c) 2016 MathML Association") +f.math.SpaceAfterScript = 0 +f.math.SubSuperscriptGapMin = 0 +f.math.SubscriptBaselineDropMin = 0 +f.math.SubscriptShiftDown = 0 +f.math.SubscriptTopMax = v +f.math.SuperscriptBaselineDropMax = 0 +f.math.SuperscriptBottomMaxWithSubscript = 0 +f.math.SuperscriptBottomMin = 0 +f.math.SuperscriptShiftUp = 0 +f.math.SuperscriptShiftUpCramped = 0 +mathfont.save(f) + +v = 8 * mathfont.em +f = mathfont.create("scripts-superscriptbottommin%d" % v, + "Copyright (c) 2016 MathML Association") +f.math.SpaceAfterScript = 0 +f.math.SubSuperscriptGapMin = 0 +f.math.SubscriptBaselineDropMin = 0 +f.math.SubscriptShiftDown = 0 +f.math.SubscriptTopMax = 0 +f.math.SuperscriptBaselineDropMax = 0 +f.math.SuperscriptBottomMaxWithSubscript = 0 +f.math.SuperscriptBottomMin = v +f.math.SuperscriptShiftUp = 0 +f.math.SuperscriptShiftUpCramped = 0 +mathfont.save(f) + +v = 9 * mathfont.em +f = mathfont.create("scripts-subscriptbaselinedropmin%d" % v, + "Copyright (c) 2016 MathML Association") +f.math.SpaceAfterScript = 0 +f.math.SubSuperscriptGapMin = 0 +f.math.SubscriptBaselineDropMin = v +f.math.SubscriptShiftDown = 0 +f.math.SubscriptTopMax = 0 +f.math.SuperscriptBaselineDropMax = 0 +f.math.SuperscriptBottomMaxWithSubscript = 0 +f.math.SuperscriptBottomMin = 0 +f.math.SuperscriptShiftUp = 0 +f.math.SuperscriptShiftUpCramped = 0 +mathfont.save(f) + +v = 10 * mathfont.em +f = mathfont.create("scripts-superscriptbaselinedropmax%d" % v, + "Copyright (c) 2016 MathML Association") +f.math.SpaceAfterScript = 0 +f.math.SubSuperscriptGapMin = 0 +f.math.SubscriptBaselineDropMin = 0 +f.math.SubscriptShiftDown = 0 +f.math.SubscriptTopMax = 0 +f.math.SuperscriptBaselineDropMax = v +f.math.SuperscriptBottomMaxWithSubscript = 0 +f.math.SuperscriptBottomMin = 0 +f.math.SuperscriptShiftUp = 0 +f.math.SuperscriptShiftUpCramped = 0 +mathfont.save(f) diff --git a/testing/web-platform/tests/mathml/tools/stacks.py b/testing/web-platform/tests/mathml/tools/stacks.py new file mode 100755 index 0000000000..b2ecec5386 --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/stacks.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 + +from utils import mathfont +import fontforge + +v1 = 5 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("stack-bottomdisplaystyleshiftdown%d-axisheight%d" % (v1, v2), + "Copyright (c) 2016 MathML Association") +f.math.AxisHeight = v2 +f.math.StackBottomDisplayStyleShiftDown = v1 +f.math.StackBottomShiftDown = 0 +f.math.StackDisplayStyleGapMin = 0 +f.math.StackGapMin = 0 +f.math.StackTopDisplayStyleShiftUp = 0 +f.math.StackTopShiftUp = 0 +mathfont.save(f) + +v1 = 6 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("stack-bottomshiftdown%d-axisheight%d" % (v1, v2), + "Copyright (c) 2016 MathML Association") +f.math.AxisHeight = v2 +f.math.StackBottomDisplayStyleShiftDown = 0 +f.math.StackBottomShiftDown = v1 +f.math.StackDisplayStyleGapMin = 0 +f.math.StackGapMin = 0 +f.math.StackTopDisplayStyleShiftUp = 0 +f.math.StackTopShiftUp = 0 +mathfont.save(f) + +v = 4 * mathfont.em +f = mathfont.create("stack-displaystylegapmin%d" % v, + "Copyright (c) 2016 MathML Association") +f.math.AxisHeight = 0 +f.math.StackBottomDisplayStyleShiftDown = 0 +f.math.StackBottomShiftDown = 0 +f.math.StackDisplayStyleGapMin = v +f.math.StackGapMin = 0 +f.math.StackTopDisplayStyleShiftUp = 0 +f.math.StackTopShiftUp = 0 +mathfont.save(f) + +v = 8 * mathfont.em +f = mathfont.create("stack-gapmin%d" % v, + "Copyright (c) 2016 MathML Association") +f.math.AxisHeight = 0 +f.math.StackBottomDisplayStyleShiftDown = 0 +f.math.StackBottomShiftDown = 0 +f.math.StackDisplayStyleGapMin = 0 +f.math.StackGapMin = v +f.math.StackTopDisplayStyleShiftUp = 0 +f.math.StackTopShiftUp = 0 +mathfont.save(f) + +v1 = 3 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("stack-topdisplaystyleshiftup%d-axisheight%d" % (v1, v2), + "Copyright (c) 2016 MathML Association") +f.math.AxisHeight = v2 +f.math.StackBottomDisplayStyleShiftDown = 0 +f.math.StackBottomShiftDown = 0 +f.math.StackDisplayStyleGapMin = 0 +f.math.StackGapMin = 0 +f.math.StackTopDisplayStyleShiftUp = v1 +f.math.StackTopShiftUp = 0 +mathfont.save(f) + +v1 = 9 * mathfont.em +v2 = 1 * mathfont.em +f = mathfont.create("stack-topshiftup%d-axisheight%d" % (v1, v2), + "Copyright (c) 2016 MathML Association") +f.math.AxisHeight = v2 +f.math.StackBottomDisplayStyleShiftDown = 0 +f.math.StackBottomShiftDown = 0 +f.math.StackDisplayStyleGapMin = 0 +f.math.StackGapMin = 0 +f.math.StackTopDisplayStyleShiftUp = 0 +f.math.StackTopShiftUp = v1 +mathfont.save(f) diff --git a/testing/web-platform/tests/mathml/tools/stretchstacks.py b/testing/web-platform/tests/mathml/tools/stretchstacks.py new file mode 100755 index 0000000000..f112a70769 --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/stretchstacks.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 + +from utils import mathfont +import fontforge + +arrowCodePoint = 0x2192 # horizontal stretch operator + +v = 3 * mathfont.em +f = mathfont.create("stretchstack-bottomshiftdown%d" % v, + "Copyright (c) 2016 MathML Association") +mathfont.createSquareGlyph(f, arrowCodePoint) +f.math.LowerLimitBaselineDropMin = 0 +f.math.LowerLimitGapMin = 0 +f.math.OverbarExtraAscender = 0 +f.math.OverbarVerticalGap = 0 +f.math.StretchStackBottomShiftDown = v +f.math.StretchStackGapAboveMin = 0 +f.math.StretchStackGapBelowMin = 0 +f.math.StretchStackTopShiftUp = 0 +f.math.UnderbarExtraDescender = 0 +f.math.UnderbarVerticalGap = 0 +f.math.UpperLimitBaselineRiseMin = 0 +f.math.UpperLimitGapMin = 0 +mathfont.save(f) + +v = 11 * mathfont.em +f = mathfont.create("stretchstack-gapbelowmin%d" % v, + "Copyright (c) 2016 MathML Association") +mathfont.createSquareGlyph(f, arrowCodePoint) +f.math.LowerLimitBaselineDropMin = 0 +f.math.LowerLimitGapMin = 0 +f.math.OverbarExtraAscender = 0 +f.math.OverbarVerticalGap = 0 +f.math.StretchStackBottomShiftDown = 0 +f.math.StretchStackGapAboveMin = 0 +f.math.StretchStackGapBelowMin = v +f.math.StretchStackTopShiftUp = 0 +f.math.UnderbarExtraDescender = 0 +f.math.UnderbarVerticalGap = 0 +f.math.UpperLimitBaselineRiseMin = 0 +f.math.UpperLimitGapMin = 0 +mathfont.save(f) + +v = 5 * mathfont.em +f = mathfont.create("stretchstack-topshiftup%d" % v, + "Copyright (c) 2016 MathML Association") +mathfont.createSquareGlyph(f, arrowCodePoint) +f.math.LowerLimitBaselineDropMin = 0 +f.math.LowerLimitGapMin = 0 +f.math.OverbarExtraAscender = 0 +f.math.OverbarVerticalGap = 0 +f.math.StretchStackBottomShiftDown = 0 +f.math.StretchStackGapAboveMin = 0 +f.math.StretchStackGapBelowMin = 0 +f.math.StretchStackTopShiftUp = v +f.math.UnderbarExtraDescender = 0 +f.math.UnderbarVerticalGap = 0 +f.math.UpperLimitBaselineRiseMin = 0 +f.math.UpperLimitGapMin = 0 +mathfont.save(f) + +v = 7 * mathfont.em +f = mathfont.create("stretchstack-gapabovemin%d" % v, + "Copyright (c) 2016 MathML Association") +mathfont.createSquareGlyph(f, arrowCodePoint) +f.math.LowerLimitBaselineDropMin = 0 +f.math.LowerLimitGapMin = 0 +f.math.OverbarExtraAscender = 0 +f.math.OverbarVerticalGap = 0 +f.math.StretchStackBottomShiftDown = 0 +f.math.StretchStackGapAboveMin = v +f.math.StretchStackGapBelowMin = 0 +f.math.StretchStackTopShiftUp = 0 +f.math.UnderbarExtraDescender = 0 +f.math.UnderbarVerticalGap = 0 +f.math.UpperLimitBaselineRiseMin = 0 +f.math.UpperLimitGapMin = 0 +mathfont.save(f) diff --git a/testing/web-platform/tests/mathml/tools/stretchy.py b/testing/web-platform/tests/mathml/tools/stretchy.py new file mode 100755 index 0000000000..b93dbcee74 --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/stretchy.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + +from utils import mathfont +import fontforge + +# Create a WOFF font with glyphs for all the operator strings. +font = mathfont.create("stretchy", "Copyright (c) 2021 Igalia S.L.") + +# Set parameters for stretchy tests. +font.math.MinConnectorOverlap = mathfont.em // 2 + +# Make sure that underover parameters don't add extra spacing. +font.math.LowerLimitBaselineDropMin = 0 +font.math.LowerLimitGapMin = 0 +font.math.StretchStackBottomShiftDown = 0 +font.math.StretchStackGapAboveMin = 0 +font.math.UnderbarVerticalGap = 0 +font.math.UnderbarExtraDescender = 0 +font.math.UpperLimitBaselineRiseMin = 0 +font.math.UpperLimitGapMin = 0 +font.math.StretchStackTopShiftUp = 0 +font.math.StretchStackGapBelowMin = 0 +font.math.OverbarVerticalGap = 0 +font.math.AccentBaseHeight = 0 +font.math.OverbarExtraAscender = 0 + +# These two characters will be stretchable in both directions. +horizontalArrow = 0x295A # LEFTWARDS HARPOON WITH BARB UP FROM BAR +verticalArrow = 0x295C # UPWARDS HARPOON WITH BARB RIGHT FROM BAR + +mathfont.createSizeVariants(font) + +# Add stretchy vertical and horizontal constructions for the horizontal arrow. +mathfont.createSquareGlyph(font, horizontalArrow) +mathfont.createStretchy(font, horizontalArrow, True) +mathfont.createStretchy(font, horizontalArrow, False) + +# Add stretchy vertical and horizontal constructions for the vertical arrow. +mathfont.createSquareGlyph(font, verticalArrow) +mathfont.createStretchy(font, verticalArrow, True) +mathfont.createStretchy(font, verticalArrow, False) + +mathfont.save(font) diff --git a/testing/web-platform/tests/mathml/tools/underover.py b/testing/web-platform/tests/mathml/tools/underover.py new file mode 100755 index 0000000000..25e1479bdb --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/underover.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 + +from utils import mathfont +import fontforge + +breveCodePoint = 0x2D8 # accent operator +degreeCodePoint = 0xB0 # nonaccent operator +accentBaseHeight = 4 * mathfont.em + +v = 3 * mathfont.em +f = mathfont.create("underover-accentbaseheight%d-overbarextraascender%d" % (accentBaseHeight, v), + "Copyright (c) 2016 MathML Association") +mathfont.createSquareGlyph(f, breveCodePoint) +mathfont.createSquareGlyph(f, degreeCodePoint) +f.math.AccentBaseHeight = accentBaseHeight +f.math.LowerLimitBaselineDropMin = 0 +f.math.LowerLimitGapMin = 0 +f.math.OverbarExtraAscender = v +f.math.OverbarVerticalGap = 0 +f.math.StretchStackBottomShiftDown = 0 +f.math.StretchStackGapAboveMin = 0 +f.math.StretchStackGapBelowMin = 0 +f.math.StretchStackTopShiftUp = 0 +f.math.UnderbarExtraDescender = 0 +f.math.UnderbarVerticalGap = 0 +f.math.UpperLimitBaselineRiseMin = 0 +f.math.UpperLimitGapMin = 0 +mathfont.save(f) + +v = 11 * mathfont.em +f = mathfont.create("underover-accentbaseheight%d-overbarverticalgap%d" % (accentBaseHeight, v), + "Copyright (c) 2016 MathML Association") +mathfont.createSquareGlyph(f, breveCodePoint) +mathfont.createSquareGlyph(f, degreeCodePoint) +f.math.AccentBaseHeight = accentBaseHeight +f.math.LowerLimitBaselineDropMin = 0 +f.math.LowerLimitGapMin = 0 +f.math.OverbarExtraAscender = 0 +f.math.OverbarVerticalGap = v +f.math.StretchStackBottomShiftDown = 0 +f.math.StretchStackGapAboveMin = 0 +f.math.StretchStackGapBelowMin = 0 +f.math.StretchStackTopShiftUp = 0 +f.math.UnderbarExtraDescender = 0 +f.math.UnderbarVerticalGap = 0 +f.math.UpperLimitBaselineRiseMin = 0 +f.math.UpperLimitGapMin = 0 +mathfont.save(f) + +v = 5 * mathfont.em +f = mathfont.create("underover-accentbaseheight%d-underbarextradescender%d" % (accentBaseHeight, v), + "Copyright (c) 2016 MathML Association") +mathfont.createSquareGlyph(f, breveCodePoint) +mathfont.createSquareGlyph(f, degreeCodePoint) +f.math.AccentBaseHeight = accentBaseHeight +f.math.LowerLimitBaselineDropMin = 0 +f.math.LowerLimitGapMin = 0 +f.math.OverbarExtraAscender = 0 +f.math.OverbarVerticalGap = 0 +f.math.StretchStackBottomShiftDown = 0 +f.math.StretchStackGapAboveMin = 0 +f.math.StretchStackGapBelowMin = 0 +f.math.StretchStackTopShiftUp = 0 +f.math.UnderbarExtraDescender = v +f.math.UnderbarVerticalGap = 0 +f.math.UpperLimitBaselineRiseMin = 0 +f.math.UpperLimitGapMin = 0 +mathfont.save(f) + +v = 7 * mathfont.em +f = mathfont.create("underover-accentbaseheight%d-underbarverticalgap%d" % (accentBaseHeight, v), + "Copyright (c) 2016 MathML Association") +mathfont.createSquareGlyph(f, breveCodePoint) +mathfont.createSquareGlyph(f, degreeCodePoint) +f.math.AccentBaseHeight = accentBaseHeight +f.math.LowerLimitBaselineDropMin = 0 +f.math.LowerLimitGapMin = 0 +f.math.OverbarExtraAscender = 0 +f.math.OverbarVerticalGap = 0 +f.math.StretchStackBottomShiftDown = 0 +f.math.StretchStackGapAboveMin = 0 +f.math.StretchStackGapBelowMin = 0 +f.math.StretchStackTopShiftUp = 0 +f.math.UnderbarExtraDescender = 0 +f.math.UnderbarVerticalGap = v +f.math.UpperLimitBaselineRiseMin = 0 +f.math.UpperLimitGapMin = 0 +mathfont.save(f) diff --git a/testing/web-platform/tests/mathml/tools/use-typo-lineheight.py b/testing/web-platform/tests/mathml/tools/use-typo-lineheight.py new file mode 100755 index 0000000000..d0e4cf7f37 --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/use-typo-lineheight.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 + +import fontforge + +font = fontforge.font() +font.em = 1000 +typoLineHeight = 2300 +winHeight = 5000 +name = "font-lineheight%d-typolineheight%d" % (winHeight, typoLineHeight) +font.fontname = name +font.familyname = name +font.fullname = name +font.copyright = "Copyright (c) 2016 MathML Association" + +glyph = font.createChar(ord(" "), "space") +glyph.width = 1000 +glyph = font.createChar(ord("O")) +pen = glyph.glyphPen() +pen.moveTo(0, -200) +pen.lineTo(0, 800) +pen.lineTo(1000, 800) +pen.lineTo(1000, -200) +pen.closePath(); + +font.os2_typoascent_add = False +font.os2_typoascent = 800 +font.os2_typodescent_add = False +font.os2_typodescent = -200 +font.os2_typolinegap = typoLineHeight - \ + (font.os2_typoascent - font.os2_typodescent) + +font.hhea_ascent = winHeight // 2 +font.hhea_ascent_add = False +font.hhea_descent = -winHeight // 2 +font.hhea_descent_add = False +font.hhea_linegap = 0 + +font.os2_winascent = winHeight // 2 +font.os2_winascent_add = False +font.os2_windescent = winHeight // 2 +font.os2_windescent_add = False + +font.os2_use_typo_metrics = True + +path = "../../fonts/math/lineheight%d-typolineheight%d.woff" % (winHeight, typoLineHeight) +print("Generating %s..." % path, end="") +font.generate(path) +if font.validate() == 0: + print(" done.") +else: + print(" validation error!") + exit(1) diff --git a/testing/web-platform/tests/mathml/tools/utils/__init__.py b/testing/web-platform/tests/mathml/tools/utils/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/utils/__init__.py diff --git a/testing/web-platform/tests/mathml/tools/utils/mathfont.py b/testing/web-platform/tests/mathml/tools/utils/mathfont.py new file mode 100644 index 0000000000..d030c9f2ce --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/utils/mathfont.py @@ -0,0 +1,218 @@ +import fontforge + +PUA_startCodePoint = 0xE000 +em = 1000 + +def create(aName, aCopyRight): + print("Generating %s.woff..." % aName, end="") + mathFont = fontforge.font() + mathFont.fontname = aName + mathFont.familyname = aName + mathFont.fullname = aName + mathFont.copyright = aCopyRight + mathFont.encoding = "UnicodeFull" + + # Create a space character. Also force the creation of some MATH subtables + # so that OTS will not reject the MATH table. + g = mathFont.createChar(ord(" "), "space") + g.width = em + g.italicCorrection = 0 + g.topaccent = 0 + g.mathKern.bottomLeft = tuple([(0,0)]) + g.mathKern.bottomRight = tuple([(0,0)]) + g.mathKern.topLeft = tuple([(0,0)]) + g.mathKern.topRight = tuple([(0,0)]) + mathFont[ord(" ")].horizontalVariants = "space" + mathFont[ord(" ")].verticalVariants = "space" + return mathFont + +def drawRectangleGlyph(glyph, width, ascent, descent = 0, padding_left = 0): + p = glyph.glyphPen() + p.moveTo(padding_left, -descent) + p.lineTo(padding_left, ascent) + p.lineTo(padding_left + width, ascent) + p.lineTo(padding_left + width, -descent) + p.closePath(); + glyph.width = padding_left + width + +def createSquareGlyph(aFont, aCodePoint): + g = aFont.createChar(aCodePoint) + drawRectangleGlyph(g, em, em, 0) + +def drawHexaDigit(aGlyph, aX, aValue): + t = em / 10 + p = aGlyph.glyphPen(replace = False) + if aValue == 0: + p.moveTo(aX + t, t) + p.lineTo(aX + t, em - t) + p.lineTo(aX + em / 2 - t, em - t) + p.lineTo(aX + em / 2 - t, t) + p.closePath() + elif aValue == 1: + p.moveTo(aX + em / 2 - t, em - t) + p.lineTo(aX + em / 2 - t, t) + p.endPath() + elif aValue == 2: + p.moveTo(aX + t, em - t) + p.lineTo(aX + em / 2 - t, em - t) + p.lineTo(aX + em / 2 - t, em / 2) + p.lineTo(aX + t, em / 2) + p.lineTo(aX + t, t) + p.lineTo(aX + em / 2 - t, t) + p.endPath() + elif aValue == 3: + p.moveTo(aX + t, em - t) + p.lineTo(aX + em / 2 - t, em - t) + p.lineTo(aX + em / 2 - t, t) + p.lineTo(aX + t, t) + p.endPath() + p.moveTo(aX + t, em / 2) + p.lineTo(aX + em / 2 - 2.5 * t, em / 2) + p.endPath() + elif aValue == 4: + p.moveTo(aX + em / 2 - t, em - t) + p.lineTo(aX + em / 2 - t, t) + p.endPath() + p.moveTo(aX + t, em - t) + p.lineTo(aX + t, em / 2) + p.lineTo(aX + em / 2 - 2.5 * t, em / 2) + p.endPath() + elif aValue == 5: + p.moveTo(aX + em / 2 - t, em - t) + p.lineTo(aX + t, em - t) + p.lineTo(aX + t, em / 2) + p.lineTo(aX + em / 2 - t, em / 2) + p.lineTo(aX + em / 2 - t, t) + p.lineTo(aX + t, t) + p.endPath() + elif aValue == 6: + p.moveTo(aX + em / 2 - t, em - t) + p.lineTo(aX + t, em - t) + p.lineTo(aX + t, t) + p.lineTo(aX + em / 2 - t, t) + p.lineTo(aX + em / 2 - t, em / 2) + p.lineTo(aX + 2.5 * t, em / 2) + p.endPath() + elif aValue == 7: + p.moveTo(aX + t, em - t) + p.lineTo(aX + em / 2 - t, em - t) + p.lineTo(aX + em / 2 - t, t) + p.endPath() + elif aValue == 8: + p.moveTo(aX + t, t) + p.lineTo(aX + t, em - t) + p.lineTo(aX + em / 2 - t, em - t) + p.lineTo(aX + em / 2 - t, t) + p.closePath() + p.moveTo(aX + 2.5 * t, em / 2) + p.lineTo(aX + em / 2 - 2.5 * t, em / 2) + p.endPath() + elif aValue == 9: + p.moveTo(aX + t, t) + p.lineTo(aX + em / 2 - t, t) + p.lineTo(aX + em / 2 - t, em - t) + p.lineTo(aX + t, em - t) + p.lineTo(aX + t, em / 2) + p.lineTo(aX + em / 2 - 2.5 * t, em / 2) + p.endPath() + elif aValue == 10: # A + p.moveTo(aX + t, t) + p.lineTo(aX + t, em - t) + p.lineTo(aX + em / 2 - t, em - t) + p.lineTo(aX + em / 2 - t, t) + p.endPath() + p.moveTo(aX + 2.5 * t, em / 2) + p.lineTo(aX + em / 2 - 2.5 * t, em / 2) + p.endPath() + elif aValue == 11: # b + p.moveTo(aX + t, em - t) + p.lineTo(aX + t, t) + p.lineTo(aX + em / 2 - t, t) + p.lineTo(aX + em / 2 - t, em / 2) + p.lineTo(aX + 2.5 * t, em / 2) + p.endPath() + elif aValue == 12: # C + p.moveTo(aX + em / 2 - t, em - t) + p.lineTo(aX + t, em - t) + p.lineTo(aX + t, t) + p.lineTo(aX + em / 2 - t, t) + p.endPath() + elif aValue == 13: # d + p.moveTo(aX + em / 2 - t, em - t) + p.lineTo(aX + em / 2 - t, t) + p.lineTo(aX + t, t) + p.lineTo(aX + t, em / 2) + p.lineTo(aX + em / 2 - 2.5 * t, em / 2) + p.endPath() + elif aValue == 14: # E + p.moveTo(aX + em / 2 - t, em - t) + p.lineTo(aX + t, em - t) + p.lineTo(aX + t, t) + p.lineTo(aX + em / 2 - t, t) + p.endPath() + p.moveTo(aX + em / 2 - t, em / 2) + p.lineTo(aX + 2.5 * t, em / 2) + p.endPath() + elif aValue == 15: # F + p.moveTo(aX + em / 2 - t, em - t) + p.lineTo(aX + t, em - t) + p.lineTo(aX + t, t) + p.endPath() + p.moveTo(aX + em / 2 - t, em / 2) + p.lineTo(aX + 2.5 * t, em / 2) + p.endPath() + +def createGlyphFromValue(aFont, aCodePoint): + g = aFont.createChar(aCodePoint) + value = aCodePoint + for i in range(0, 5): + drawHexaDigit(g, (5 - (i + 1)) * em / 2, value % 16) + value /= 16 + g.width = 5 * em / 2 + g.stroke("circular", em / 10, "square", "miter", "cleanup") + +def createSizeVariants(aFont, aUsePUA = False): + if aUsePUA: + codePoint = PUA_startCodePoint + else: + codePoint = -1 + for size in (0, 1, 2, 3): + g = aFont.createChar(codePoint, "v%d" % size) + drawRectangleGlyph(g, em, (size + 1) * em, 0) + if aUsePUA: + codePoint += 1 + g = aFont.createChar(codePoint, "h%d" % size) + drawRectangleGlyph(g, (size + 1) * em, em, 0) + if aUsePUA: + codePoint += 1 + +def createStretchy(aFont, codePoint, isHorizontal): + if isHorizontal: + aFont[codePoint].horizontalVariants = "h0 h1 h2 h3" + # Part: (glyphName, isExtender, startConnector, endConnector, fullAdvance) + aFont[codePoint].horizontalComponents = \ + (("h2", False, 0, em, 3 * em), \ + ("h1", True, em, em, 2 * em)) + else: + aFont[codePoint].verticalVariants = "v0 v1 v2 v3" + # Part: (glyphName, isExtender, startConnector, endConnector, fullAdvance) + aFont[codePoint].verticalComponents = \ + (("v2", False, 0, em, 3 * em), \ + ("v1", True, em, em, 2 * em)) + +def save(aFont): + aFont.em = em + aFont.ascent = aFont.hhea_ascent = aFont.os2_typoascent = em + aFont.descent = aFont.hhea_descent = aFont.os2_typodescent = 0 + # aFont.os2_winascent, aFont.os2_windescent should be the maximum of + # ascent/descent for all glyphs. Does fontforge compute them automatically? + aFont.hhea_ascent_add = aFont.hhea_descent_add = 0 + aFont.os2_typoascent_add = aFont.os2_typodescent_add = 0 + aFont.os2_winascent_add = aFont.os2_windescent_add = 0 + aFont.os2_use_typo_metrics = True + aFont.generate("../../fonts/math/%s.woff" % aFont.fontname) + if aFont.validate() == 0: + print(" done.") + else: + print(" validation error!") + exit(1) diff --git a/testing/web-platform/tests/mathml/tools/utils/misc.py b/testing/web-platform/tests/mathml/tools/utils/misc.py new file mode 100644 index 0000000000..89ec1bdf80 --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/utils/misc.py @@ -0,0 +1,33 @@ +import os +import progressbar +from urllib.request import urlopen + +UnicodeXMLURL = "https://raw.githubusercontent.com/w3c/xml-entities/gh-pages/unicode.xml" +InlineAxisOperatorsURL = "https://w3c.github.io/mathml-core/tables/inline-axis-operators.txt" + +def downloadWithProgressBar(url, outputDirectory="./", forceDownload=False): + + baseName = os.path.basename(url) + fileName = os.path.join(outputDirectory, baseName) + + if not forceDownload and os.path.exists(fileName): + return fileName + + request = urlopen(url) + totalSize = int(request.info().get('Content-Length').strip()) + bar = progressbar.ProgressBar(maxval=totalSize).start() + + chunkSize = 16 * 1024 + downloaded = 0 + print("Downloading %s" % url) + os.umask(0o002) + with open(fileName, 'wb') as fp: + while True: + chunk = request.read(chunkSize) + downloaded += len(chunk) + bar.update(downloaded) + if not chunk: break + fp.write(chunk) + bar.finish() + + return fileName diff --git a/testing/web-platform/tests/mathml/tools/xHeight.py b/testing/web-platform/tests/mathml/tools/xHeight.py new file mode 100755 index 0000000000..ad0f8b9e02 --- /dev/null +++ b/testing/web-platform/tests/mathml/tools/xHeight.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 + +from utils import mathfont +import fontforge + +v = mathfont.em / 2 +f = mathfont.create("xheight%d" % v, + "Copyright (c) 2016 MathML Association") +g = f.createChar(ord('x')) +mathfont.drawRectangleGlyph(g, mathfont.em, v, 0) +assert f.xHeight == v, "Bad x-height value!" +mathfont.save(f) |