summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/mathml
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
commit0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch)
treea31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /testing/web-platform/tests/mathml
parentInitial commit. (diff)
downloadfirefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz
firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/mathml')
-rw-r--r--testing/web-platform/tests/mathml/META.yml3
-rw-r--r--testing/web-platform/tests/mathml/README.md12
-rw-r--r--testing/web-platform/tests/mathml/crashtests/children-with-negative-block-sizes.html142
-rw-r--r--testing/web-platform/tests/mathml/crashtests/children-with-negative-inline-sizes.html142
-rw-r--r--testing/web-platform/tests/mathml/crashtests/chrome-bug-1287843.html12
-rw-r--r--testing/web-platform/tests/mathml/crashtests/display-and-column-properties.html30
-rw-r--r--testing/web-platform/tests/mathml/crashtests/dynamic-height-within-table-cell.html33
-rw-r--r--testing/web-platform/tests/mathml/crashtests/fixed-pos-children.html25
-rw-r--r--testing/web-platform/tests/mathml/crashtests/math-depth-overflow.html10
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mathml-in-svg-001.html3
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mmultiscripts-with-two-prescripts.html8
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/1028521-1.xhtml5
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/1061027.html12
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/1221888-1.html15
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/1373767-1.html22
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/1376158.html6
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/151054-1.xml15
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/1600635.html16
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/289180-1.xml16
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/307826-1.xhtml30
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/307839-1.xhtml15
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/307839-2.xhtml24
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/323733-1.xml7
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/323737-1.xml9
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/323738-1.xml11
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/323741-1.xml13
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/323742-1.xml16
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/336074-1.xhtml25
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/347355-1-inner.xhtml28
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/347355-1.gifbin0 -> 980 bytes
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/347355-1.html9
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/347495-1.xhtml10
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/347507-1.xhtml29
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/348492-1.xhtml31
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/348709-1.xhtml20
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/348811-1.xhtml26
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/348811-2.xhtml31
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/353612-1.xhtml17
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/355986-1.xhtml34
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/364685-1.xhtml19
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/366012-1.xhtml23
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/366564-1.xhtml44
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/367107-1.html22
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/368430-1.xhtml5
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/370791-1.xhtml33
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/370862-1.xhtml27
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/372483-1.xhtml7
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/373472-1.xhtml20
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/373472-2.xhtml9
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/375562-1.xhtml38
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/377824-1.xhtml5
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/379418-1.xhtml7
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/385226-1.xhtml29
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/393760-1.xhtml16
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/397518-1.xhtml15
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/398038-1.html8
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/400475-1.xhtml16
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/402400-1.xhtml41
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/403156-1.xhtml12
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/404485-1.xhtml9
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/405187-1.xhtml10
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/405271-1.xml36
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/412237-1.xml11
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/413063-1.xhtml21
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/416907-1.xhtml5
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/420420-1.xhtml7
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/431072-1.xhtml25
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/443089-1.xhtml7
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/462929-1.html12
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/463763-1.xhtml10
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/463763-2.xhtml12
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/476547-1.xhtml5
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/541620-1.xhtml6
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/557474-1.html11
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/654928-1.html3
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/655451-1.xhtml15
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/713606-1.html24
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/716349-1.html13
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/767251.xhtml1
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/770710-1.html25
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/848725-1.html17
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/848725-2.html17
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/947557-1.html21
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mozilla/973322-1.xhtml8
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mspace-mpadded-negative-dimensions.html13
-rw-r--r--testing/web-platform/tests/mathml/crashtests/mtd-as-multicol.html9
-rw-r--r--testing/web-platform/tests/mathml/crashtests/multicol-inside-ms.html4
-rw-r--r--testing/web-platform/tests/mathml/crashtests/multicol-on-token-elements.html11
-rw-r--r--testing/web-platform/tests/mathml/crashtests/operator-and-first-letter.html9
-rw-r--r--testing/web-platform/tests/mathml/crashtests/scrollbar-caching-assert.html17
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/direction/direction-006-ref.html74
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/direction/direction-006.html82
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/direction/direction-007-ref.html42
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/direction/direction-007.html53
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/direction/direction-008-ref.html27
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/direction/direction-008.html36
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/direction/direction-010-ref.html44
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/direction/direction-010.html54
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/direction/direction-overall-ref.html40
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/direction/direction-overall.html53
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/direction/direction-token-ref.html16
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/direction/direction-token.html28
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/direction/direction.html39
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-1.html191
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-001-ref.html21
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-001.html56
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-002-ref.html23
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-002.html83
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-003-ref.html21
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-003.html46
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-color-001-notref.html16
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-color-001.html20
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-color-002-ref.html14
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-color-002.html34
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-2-ref.html17
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-2.html44
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-3-ref.html16
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-3.html36
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-ref.html16
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically.html39
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-default-padding-ref.html19
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-default-padding.html37
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-2-ref.html15
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-2.html18
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-3-ref.html17
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-3.html20
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-ref.html14
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid.html17
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-legacy-bevelled-attribute.tentative-ref.html18
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-legacy-bevelled-attribute.tentative.html28
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-001-ref.html42
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-001.html47
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-002.html131
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-003-notref.html16
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-003.html19
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-004-ref.html27
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-004.html32
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-mrow-001-ref.html16
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-mrow-001.html28
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-numalign-denomalign-001-ref.html75
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-numalign-denomalign-001.html56
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-1.html440
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-2.html290
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-3.html168
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-001-ref.html63
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-001.html90
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-002-ref.html63
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-002.html90
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-003-ref.html63
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-003.html90
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-004-ref.html63
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-004.html90
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-005-ref.html63
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-005.html90
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-006-ref.html63
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-006.html90
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-rendering-from-in-flow-ref.html15
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-rendering-from-in-flow.html40
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-visibility-001-ref.html12
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/fractions/frac-visibility-001.html24
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/menclose/legacy-menclose-radical-notation-ref.html23
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/menclose/legacy-menclose-radical-notation.html30
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mpadded/legacy-orthogonal-pseudo-units.html101
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-001.html147
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-002.html164
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-003.html230
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-percentage-001-ref.html18
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-percentage-001.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-percentage-002.html81
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/dynamic-mrow-like-001-ref.html41
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/dynamic-mrow-like-001.html72
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/inferred-mrow-baseline.html57
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/inferred-mrow-stretchy.html64
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mfenced-element-001-ref.html24
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mfenced-element-001.html34
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mrow-like-elements-001.html188
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mrow-like-elements-002-ref.html44
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mrow-like-elements-002.html57
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mstyle-attributes.html164
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/merror-001.html43
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/mrow-fallback.html125
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/mrow-painting-order-ref.html83
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/mrow-painting-order.html42
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/mrow-preferred-width.html121
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/no-spacing.html139
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/spacing.html54
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/mrow/stretch-along-block-axis-001.html176
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-001-crash.html10
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-001.html521
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-002.html559
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-003.html394
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-dynamic-001-ref.html95
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-dynamic-001.html123
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-dynamic-002.html185
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/largeop-hit-testing.html64
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-axis-height-1.html75
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-font-relative-lengths-001.html114
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-dynamic-002-ref.html48
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-dynamic-002.html66
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-dynamic-ref.html26
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-dynamic.html51
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-fallback-ref.html15
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-fallback.html28
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-minus-plus-ref.html84
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-minus-plus.html89
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-ref.html25
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-form.html30
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-2-ref.html363
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-2.html363
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-3-ref.html41
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-3.html61
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-4-ref.html20
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-4.html19
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-dynamic-ref.html48
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-dynamic.html64
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-ref.html41
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace.html38
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-minsize-maxsize-001.html143
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-and-embellished-operator-ref.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-and-embellished-operator.html39
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-default-ref.html18
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-default.html24
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-dynamic-ref.html15
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-dynamic.html27
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-from-in-flow-ref.html30
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-from-in-flow.html53
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-ref.html29
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits.html34
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-not-in-dictionary-lspace-rspace-ref.html47
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-not-in-dictionary-lspace-rspace.html52
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-not-in-dictionary-movablelimits-ref.html47
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-not-in-dictionary-movablelimits.html52
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-paint-lspace-rspace-ref.html78
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-paint-lspace-rspace.html71
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-single-char-and-children-ref.html30
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-single-char-and-children.html51
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-stretch-properties-001.html68
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/mo-stretch-properties-dynamic-001.html154
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-1-notref.html15
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-1.html15
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-12-ref.html14
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-12.html15
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-13-notref.html14
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-13.html15
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-2-ref.html14
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-2.html15
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-3-notref.html14
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-3.html15
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-4-ref.html18
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-4.html19
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-5-notref.html18
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-5.html19
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-6-ref.html13
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-6.html14
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-7-notref.html13
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-7.html14
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-8-ref.html13
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-8.html14
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-9-notref.html15
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-9.html14
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-arabic-001-ref.html20
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-arabic-001.html28
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-arabic-002-ref.html30
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-arabic-002.html39
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-combining.html159
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-empty-and-three-chars-ref.html32
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-empty-and-three-chars.html39
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-001.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-002.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-003.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-004.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-005.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-006.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-001.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-002.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-003.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-004.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-005.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-006.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-001.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-002.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-003.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-004.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-005.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-006.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-001.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-002.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-003.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-004.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-005.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-006.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-001.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-002.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-003.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-004.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-005.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-006.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/painting-stretchy-operator-001-ref.html22
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/painting-stretchy-operator-001.html73
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/support/operator-dictionary-tests.css10
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/operators/support/operator-dictionary-tests.js226
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/radicals/dynamic-radical-paint-invalidation-001-ref.html125
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/radicals/dynamic-radical-paint-invalidation-001.html167
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/radicals/radical-rendering-from-in-flow-ref.html18
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/radicals/radical-rendering-from-in-flow.html49
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/radicals/root-parameters-1.html222
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/radicals/root-parameters-2.html79
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/cramped-001.html627
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/empty-underover.html68
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/mover-accent-dynamic-change-ref.html9
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/mover-accent-dynamic-change.html16
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/mprescripts-001-ref.html19
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/mprescripts-001.html26
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/none-001-ref.html19
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/none-001.html26
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/none-002-ref.html73
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/none-002.html76
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-1.html114
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-2.html173
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-3.html192
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-4.html129
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-5.html97
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-6.html120
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-legacy-scriptshift-attributes-001.tentative-ref.html35
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-legacy-scriptshift-attributes-001.tentative.html48
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-parameters-1.html354
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-parameters-2.html181
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/underover-1.html175
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/underover-legacy-align-attribute-001-ref.html61
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/underover-legacy-align-attribute-001.html72
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-1.html151
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-2.html151
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-3.html452
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-4.tentative.html335
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-and-embellished-operator-1.html151
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-and-embellished-operator-2.html151
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-001-ref.html167
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-001.html270
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-002-ref.html167
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-002.html272
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-003-ref.html167
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-003.html272
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-children-ref.html11
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-children.html13
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-percentage-001-ref.html18
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-percentage-001.html33
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-width-height-001.html113
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/spaces/space-1.html150
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/spaces/space-2-ref.html15
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/spaces/space-2.html42
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/spaces/space-like-001.html340
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/spaces/space-like-002.html174
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/spaces/space-like-003.html252
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/spaces/space-like-004.html446
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/spaces/space-vertical-align.tentative-ref.html15
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/spaces/space-vertical-align.tentative.html22
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/tables/dynamic-table-001.html301
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/tables/table-001.html286
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/tables/table-002.html146
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/tables/table-003.html146
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/tables/table-axis-height.html55
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/tables/table-cell-mrow-layout.html74
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/tables/table-default-styles-001.html49
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/tokens/dynamic-mtext-like-001-ref.html43
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/tokens/dynamic-mtext-like-001.html70
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/tokens/ms-001-ref.html22
-rw-r--r--testing/web-platform/tests/mathml/presentation-markup/tokens/ms-001.html30
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/attribute-mapping-001.html111
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/attribute-mapping-002.html118
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/blur-filter-ref.html13
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/blur-filter.html21
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/clip-path-ref.html13
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/clip-path.html21
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/clip-ref.html13
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/clip.html21
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/color-001-ref.html12
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/color-001.html34
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/color-002-ref.html12
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/color-002.html29
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/color-003-ref.html12
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/color-003.html31
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/color-004.tentative-ref.html12
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/color-004.tentative.html55
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/color-005-ref.html12
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/color-005.html88
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/default-font-family.html36
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/default-properties-on-semantics-and-maction.html47
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/default-properties-on-the-math-root.html57
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/display-1-ref.html12
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/display-1.html18
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/display-2.html139
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/display-contents.html36
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/display-with-overflow-ref.html20
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/display-with-overflow.html19
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/displaystyle-011-ref.html155
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/displaystyle-011.html168
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/displaystyle-012-ref.html30
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/displaystyle-012.html37
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/displaystyle-013-ref.html58
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/displaystyle-013.html80
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/displaystyle-014-ref.html35
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/displaystyle-014.html55
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/displaystyle-015-ref.html58
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/displaystyle-015.html83
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/displaystyle-1.html136
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/displaystyle-2.html208
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/displaystyle-3.html84
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/dynamic-dir-1-ref.html75
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/dynamic-dir-1.html105
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/floats/floating-inside-mathml-with-block-display-ref.html15
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/floats/floating-inside-mathml-with-block-display.html20
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/floats/floating-math-ref.html14
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/floats/floating-math.html19
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/floats/not-floating-001.html74
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/ignored-properties-001.html79
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/legacy-scriptminsize-attribute-ref.html27
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/legacy-scriptminsize-attribute.html32
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/legacy-scriptsizemultiplier-attribute-ref.html27
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/legacy-scriptsizemultiplier-attribute.html32
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/lengths-1-ref.html14
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/lengths-1.html122
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/lengths-2.html266
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathbackground-001-notref.html9
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathbackground-001.html14
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathbackground-002-notref.html9
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathbackground-002.html14
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathbackground-003-notref.html7
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathbackground-003.html11
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathbackground-004-notref.html9
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathbackground-004.html14
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathcolor-001-notref.html9
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathcolor-001.html13
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathcolor-002-notref.html9
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathcolor-002.html14
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathcolor-003-notref.html7
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathcolor-003.html11
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathcolor-004-notref.html9
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathcolor-004.html14
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathcolor-mathbackground-css-ref.html23
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathcolor-mathbackground-css.html27
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-css-keywords-ref.html26
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-css-keywords.html33
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-legacy-values-ref.html16
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-legacy-values.html23
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-ref.html19
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute.html22
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathvariant-auto-ref.html139
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathvariant-auto.html145
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathvariant-font-style-font-weight-ref.html44
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mathvariant-font-style-font-weight.html49
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mi-fontstyle-fontweight-ref.html22
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/mi-fontstyle-fontweight.html27
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/multi-column-layout.html56
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/not-participating-to-parent-layout.html77
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/absolutely-positioned-001-ref.html18
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/absolutely-positioned-001.html25
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/all-mathml-containers.html103
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/fixed-positioned-001-ref.html28
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/fixed-positioned-001.html35
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/overflow/computed-value-001.html45
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/border-001.html179
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/border-002.html72
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/margin-001.html179
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/margin-002.html86
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/margin-003.html93
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-001.html179
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-002.html71
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-001-ref.html17
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-001.html22
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-002-ref.html18
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-002.html34
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-003-ref.html18
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-003.html33
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/presentational-hints-001-ref.html62
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/presentational-hints-001.html63
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/presentational-hints-002-ref.html59
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/presentational-hints-002.html84
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/scriptlevel-001.html219
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/transform-ref.html13
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/transform.html21
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/visibility-001-ref.html12
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/visibility-001.html34
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/visibility-002-ref.html12
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/visibility-002.html29
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/visibility-003-ref.html12
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/visibility-003.html31
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/visibility-004.tentative-ref.html12
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/visibility-004.tentative.html55
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/visibility-005-ref.html12
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/visibility-005.html88
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/width-height-001.html62
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/width-height-002-ref.html162
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/width-height-002.html135
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/width-height-003-ref.html178
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/width-height-003.html150
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/width-height-004.html133
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/writing-mode/force-horizontal-tb.html50
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/writing-mode/reset-and-logicial-property-ref.html15
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/writing-mode/reset-and-logicial-property.html20
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/writing-mode/writing-mode-001.html69
-rw-r--r--testing/web-platform/tests/mathml/relations/css-styling/writing-mode/writing-mode-002.html82
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/class-1-ref.html15
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/class-1.html24
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/class-2.html42
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/clipboard-event-handlers.tentative.html119
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/color-attributes-1-ref.html26
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/color-attributes-1.html38
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/content-editable.html51
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/css-inline-style-dynamic.tentative-ref.html18
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/css-inline-style-dynamic.tentative.html46
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/css-inline-style-interface.tentative.html54
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/display-1.html175
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/display-2-ref.html31
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/display-2.html37
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/dynamic-1-ref.html16
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/dynamic-1.html30
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/dynamic-2-ref.html16
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/dynamic-2.html27
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/dynamic-childlist-001.html630
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/dynamic-childlist-002.html119
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/href-click-1-ref.html15
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/href-click-1.html36
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/href-click-2-ref.html15
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/href-click-2.html40
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/href-click-3.html38
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/html-or-foreign-element-interfaces.tentative.html111
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/integration-point-1-ref.html13
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/integration-point-1.html25
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/integration-point-2-ref.html15
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/integration-point-2.html72
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/integration-point-3-ref.html17
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/integration-point-3.html63
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/integration-point-4.html59
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/integration-point-5.html57
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/math-global-event-handlers.tentative.html155
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/required-extensions-2-ref.html13
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/required-extensions-2.html23
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/tabindex-001.html58
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/tabindex-002.html71
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-1-iframe-1.html18
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-1-iframe-2.html15
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-1-ref.html16
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-1.html19
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-2.html30
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-3-ref.html15
-rw-r--r--testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-3.html24
-rw-r--r--testing/web-platform/tests/mathml/relations/text-and-math/basic-mathematical-alphanumeric-symbols-with-default-font.html39
-rw-r--r--testing/web-platform/tests/mathml/relations/text-and-math/use-typo-metrics-1-ref.html19
-rw-r--r--testing/web-platform/tests/mathml/relations/text-and-math/use-typo-metrics-1.html51
-rw-r--r--testing/web-platform/tests/mathml/support/attribute-values.js31
-rw-r--r--testing/web-platform/tests/mathml/support/box-comparison.js107
-rw-r--r--testing/web-platform/tests/mathml/support/box-navigation.js29
-rw-r--r--testing/web-platform/tests/mathml/support/feature-detection-operators.js86
-rw-r--r--testing/web-platform/tests/mathml/support/feature-detection.js325
-rw-r--r--testing/web-platform/tests/mathml/support/fonts.js9
-rw-r--r--testing/web-platform/tests/mathml/support/layout-comparison.js112
-rw-r--r--testing/web-platform/tests/mathml/support/mathml-fragments.js189
-rw-r--r--testing/web-platform/tests/mathml/support/operator-dictionary.js42
-rw-r--r--testing/web-platform/tests/mathml/support/operator-dictionary.json1
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/axisheight.py27
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/fractions.py163
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/largeop.py64
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/limits.py78
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/math-text.py64
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/mathvariant-transforms.py202
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/operator-dictionary.py130
-rw-r--r--testing/web-platform/tests/mathml/tools/operator-dictionary.xsl73
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/percentscaledown.py24
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/radicals.py133
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/scripts.py155
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/stacks.py80
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/stretchstacks.py78
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/stretchy-centered-on-baseline.py44
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/stretchy.py43
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/underover.py88
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/use-typo-lineheight.py53
-rw-r--r--testing/web-platform/tests/mathml/tools/utils/__init__.py1
-rw-r--r--testing/web-platform/tests/mathml/tools/utils/mathfont.py232
-rw-r--r--testing/web-platform/tests/mathml/tools/utils/misc.py35
-rwxr-xr-xtesting/web-platform/tests/mathml/tools/xHeight.py12
580 files changed, 36168 insertions, 0 deletions
diff --git a/testing/web-platform/tests/mathml/META.yml b/testing/web-platform/tests/mathml/META.yml
new file mode 100644
index 0000000000..ee5c81bfb6
--- /dev/null
+++ b/testing/web-platform/tests/mathml/META.yml
@@ -0,0 +1,3 @@
+spec: https://w3c.github.io/mathml-core/
+suggested_reviewers:
+ - fred-wang
diff --git a/testing/web-platform/tests/mathml/README.md b/testing/web-platform/tests/mathml/README.md
new file mode 100644
index 0000000000..4511b3e7df
--- /dev/null
+++ b/testing/web-platform/tests/mathml/README.md
@@ -0,0 +1,12 @@
+# Tests for the MathML Core specification
+
+This directory contains tests for the
+[MathML Core specification](https://w3c.github.io/mathml-core/).
+Many of the tests verify OpenType features and require specific Web fonts for
+that purpose. WOFF fonts are generated by scripts in the `tools/` folder using
+the Python API of
+[fontforge](https://github.com/fontforge/fontforge/). A recent enough version
+of FontForge is necessary so that it includes fixes for
+[WOFF checkSumAdjustment](https://github.com/fontforge/fontforge/issues/926),
+[USE_TYPO_METRICS flag](https://github.com/fontforge/fontforge/pull/2274) and
+for other various bugs.
diff --git a/testing/web-platform/tests/mathml/crashtests/children-with-negative-block-sizes.html b/testing/web-platform/tests/mathml/crashtests/children-with-negative-block-sizes.html
new file mode 100644
index 0000000000..c50f9be153
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/children-with-negative-block-sizes.html
@@ -0,0 +1,142 @@
+<!DOCTYPE html>
+<style>
+ /* These are children with negative block sizes. Absolute values are chosen
+ large enough compared to math layout constants. */
+ span { display: inline-block; }
+ mspace, span {
+ margin-block-start: -10em;
+ margin-block-end: -10em;
+ }
+ /* Override display: none; from UA style sheet for the following children. */
+ maction > :not(:first-child),
+ semantics > annotation,
+ semantics > annotation-xml {
+ display: math;
+ }
+</style>
+<math>
+ <mi><span></span></mi>
+ <mn><span></span></mn>
+ <mo><span></span></mo>
+ <ms><span></span></ms>
+ <mtext><span></span></mtext>
+</math>
+<math>
+ <semantics>
+ <mspace/>
+ <annotation><span></span></annotation>
+ <annotation-xml><span></span></annotation-xml>
+ </semantics>
+</math>
+<math>
+ <mtable>
+ <mtr>
+ <mtd><mspace/></mtd>
+ <mtd><mspace/></mtd>
+ <mtd><mspace/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace/></mtd>
+ <mtd><mspace/></mtd>
+ <mtd><mspace/></mtd>
+ </mtr>
+ </mtable>
+</math>
+<math>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+</math>
+<math>
+ <maction>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ </maction>
+ <merror>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ </merror>
+ <mpadded>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ </mpadded>
+ <mphantom>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ </mphantom>
+ <mstyle>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ </mstyle>
+</math>
+<math>
+ <mfrac>
+ <mspace/>
+ <mspace/>
+ </mfrac>
+ <mfrac linethickness="0">
+ <mspace/>
+ <mspace/>
+ </mfrac>
+</math>
+<math>
+ <msqrt>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ </msqrt>
+ <mroot>
+ <mspace/>
+ <mspace/>
+ </mroot>
+</math>
+<math>
+ <msup>
+ <mspace/>
+ <mspace/>
+ </msup>
+ <msub>
+ <mspace/>
+ <mspace/>
+ </msub>
+ <msubsup>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ </msubsup>
+ <mmultiscripts>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ <mprescripts/>
+ <mspace/>
+ <mspace/>
+ </mmultiscripts>
+</math>
+<math>
+ <mover>
+ <mspace/>
+ <mspace/>
+ </mover>
+ <munder>
+ <mspace/>
+ <mspace/>
+ </munder>
+ <munderover>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ </munderover>
+</math>
diff --git a/testing/web-platform/tests/mathml/crashtests/children-with-negative-inline-sizes.html b/testing/web-platform/tests/mathml/crashtests/children-with-negative-inline-sizes.html
new file mode 100644
index 0000000000..5c41fc8969
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/children-with-negative-inline-sizes.html
@@ -0,0 +1,142 @@
+<!DOCTYPE html>
+<style>
+ /* These are children with negative block sizes. Absolute values are chosen
+ large enough compared to math layout constants. */
+ span { display: inline-block; }
+ mspace, span {
+ margin-inline-start: -10em;
+ margin-inline-end: -10em;
+ }
+ /* Override display: none; from UA style sheet for the following children. */
+ maction > :not(:first-child),
+ semantics > annotation,
+ semantics > annotation-xml {
+ display: math;
+ }
+</style>
+<math>
+ <mi><span></span></mi>
+ <mn><span></span></mn>
+ <mo><span></span></mo>
+ <ms><span></span></ms>
+ <mtext><span></span></mtext>
+</math>
+<math>
+ <semantics>
+ <mspace/>
+ <annotation><span></span></annotation>
+ <annotation-xml><span></span></annotation-xml>
+ </semantics>
+</math>
+<math>
+ <mtable>
+ <mtr>
+ <mtd><mspace/></mtd>
+ <mtd><mspace/></mtd>
+ <mtd><mspace/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace/></mtd>
+ <mtd><mspace/></mtd>
+ <mtd><mspace/></mtd>
+ </mtr>
+ </mtable>
+</math>
+<math>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+</math>
+<math>
+ <maction>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ </maction>
+ <merror>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ </merror>
+ <mpadded>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ </mpadded>
+ <mphantom>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ </mphantom>
+ <mstyle>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ </mstyle>
+</math>
+<math>
+ <mfrac>
+ <mspace/>
+ <mspace/>
+ </mfrac>
+ <mfrac linethickness="0">
+ <mspace/>
+ <mspace/>
+ </mfrac>
+</math>
+<math>
+ <msqrt>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ </msqrt>
+ <mroot>
+ <mspace/>
+ <mspace/>
+ </mroot>
+</math>
+<math>
+ <msup>
+ <mspace/>
+ <mspace/>
+ </msup>
+ <msub>
+ <mspace/>
+ <mspace/>
+ </msub>
+ <msubsup>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ </msubsup>
+ <mmultiscripts>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ <mprescripts/>
+ <mspace/>
+ <mspace/>
+ </mmultiscripts>
+</math>
+<math>
+ <mover>
+ <mspace/>
+ <mspace/>
+ </mover>
+ <munder>
+ <mspace/>
+ <mspace/>
+ </munder>
+ <munderover>
+ <mspace/>
+ <mspace/>
+ <mspace/>
+ </munderover>
+</math>
diff --git a/testing/web-platform/tests/mathml/crashtests/chrome-bug-1287843.html b/testing/web-platform/tests/mathml/crashtests/chrome-bug-1287843.html
new file mode 100644
index 0000000000..6fc95fc12e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/chrome-bug-1287843.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1287843">
+<div style="columns:2;">
+ <math>
+ <mtd>
+ <mtable>
+ <mtr></mtr>
+ </mtable>
+ </mtd>
+ </math>
+</div>
diff --git a/testing/web-platform/tests/mathml/crashtests/display-and-column-properties.html b/testing/web-platform/tests/mathml/crashtests/display-and-column-properties.html
new file mode 100644
index 0000000000..c40a2a0549
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/display-and-column-properties.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html class="test-wait">
+ <head>
+ <title>MathML elements with display and column properties</title>
+ <meta charset="utf-8"/>
+ <style>
+ math {
+ column-width: 100px;
+ }
+ </style>
+ </head>
+ <body>
+ <math></math>
+ <math style="display: list-item"></math>
+ <script>
+ window.addEventListener("load", function() {
+ // Force initial layout.
+ document.documentElement.getBoundingClientRect();
+
+ // Change display and reforce layout.
+ let maths = document.getElementsByTagName("math");
+ maths[0].setAttribute("style", "display: list-item");
+ maths[1].removeAttribute("style");
+ document.documentElement.getBoundingClientRect();
+
+ document.documentElement.classList.remove("test-wait");
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/dynamic-height-within-table-cell.html b/testing/web-platform/tests/mathml/crashtests/dynamic-height-within-table-cell.html
new file mode 100644
index 0000000000..cf42101bc8
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/dynamic-height-within-table-cell.html
@@ -0,0 +1,33 @@
+<!DOCTYPE>
+<html class="test-wait">
+ <head>
+ <title>Dynamic height within table cell</title>
+ <meta charset="utf-8"/>
+ <link rel="author" title="Frédéric Wang" href="mailto:fwang@igalia.com">
+ <link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1254572">
+ <style>
+ #cell {
+ position: relative;
+ }
+ #elementToResize {
+ position: absolute;
+ height: 50px;
+ }
+ </style>
+ </head>
+ <body>
+ <math>
+ <mtd id="cell">
+ <mrow id="elementToResize"></mrow>
+ </mtd>
+ </math>
+ <script>
+ window.addEventListener("load", () => {
+ window.requestAnimationFrame(() => {
+ elementToResize.style.height = "0px";
+ document.documentElement.classList.remove('test-wait');
+ });
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/fixed-pos-children.html b/testing/web-platform/tests/mathml/crashtests/fixed-pos-children.html
new file mode 100644
index 0000000000..773439d6f3
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/fixed-pos-children.html
@@ -0,0 +1,25 @@
+<style>
+ * {
+ border-bottom: hsla(115.49088416259553deg 12% 15% / 18%) groove thin;
+ -webkit-text-stroke: InactiveCaptionText thin;
+ scale: -121
+ }
+
+ * * {
+ padding-inline: 69%;
+ }
+</style>
+<script>
+ document.addEventListener('DOMContentLoaded', () => {
+ const style = document.createElement('style')
+ document.head.appendChild(style)
+ style.sheet.insertRule('* {-webkit-mask-image:url(', 0)
+ })
+</script>
+<math>
+ <mmultiscripts>
+ <mglyph>
+ <maligngroup style='position:fixed'></maligngroup>
+ </mglyph>
+ </mmultiscripts>
+</math> \ No newline at end of file
diff --git a/testing/web-platform/tests/mathml/crashtests/math-depth-overflow.html b/testing/web-platform/tests/mathml/crashtests/math-depth-overflow.html
new file mode 100644
index 0000000000..e096dbb558
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/math-depth-overflow.html
@@ -0,0 +1,10 @@
+<script>
+document.addEventListener('DOMContentLoaded', () => {
+ let a = document.createElementNS('http://www.w3.org/1998/Math/MathML', 'math')
+ a.setAttribute('scriptlevel', '127')
+ let b = document.createElementNS('http://www.w3.org/1998/Math/MathML', 'mstyle')
+ b.setAttribute('scriptlevel', '+2147483645')
+ a.appendChild(b)
+ document.documentElement.appendChild(a)
+})
+</script>
diff --git a/testing/web-platform/tests/mathml/crashtests/mathml-in-svg-001.html b/testing/web-platform/tests/mathml/crashtests/mathml-in-svg-001.html
new file mode 100644
index 0000000000..94a905f3b0
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mathml-in-svg-001.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1262555">
+<svg><foreignObject><math><mn>42</mn></math></foreignObject></svg>
diff --git a/testing/web-platform/tests/mathml/crashtests/mmultiscripts-with-two-prescripts.html b/testing/web-platform/tests/mathml/crashtests/mmultiscripts-with-two-prescripts.html
new file mode 100644
index 0000000000..54f9384606
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mmultiscripts-with-two-prescripts.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<math>
+ <mmultiscripts>
+ <mrow></mrow>
+ <mprescripts></mprescripts>
+ <mprescripts></mprescripts>
+ </mmultiscripts>
+</math>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/1028521-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/1028521-1.xhtml
new file mode 100644
index 0000000000..b8d0947741
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/1028521-1.xhtml
@@ -0,0 +1,5 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body>
+<mstyle xmlns="http://www.w3.org/1998/Math/MathML"><li xmlns="http://www.w3.org/1999/xhtml" dir="rtl"></li></mstyle>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/1061027.html b/testing/web-platform/tests/mathml/crashtests/mozilla/1061027.html
new file mode 100644
index 0000000000..3187f500a3
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/1061027.html
@@ -0,0 +1,12 @@
+<style>
+.c1 { transform-style: preserve-3d; display: table-row-group;</style><script>
+var docElement = document.documentElement;
+function init() {
+test1 = document.createElementNS("http://www.w3.org/1999/xhtml", "defs");
+test1.setAttribute("class", "c1");
+docElement.appendChild(test1);
+test2 = document.createElementNS("http://www.w3.org/1998/Math/MathML", "msub");
+test1.appendChild(test2);
+}
+document.addEventListener("DOMContentLoaded", init);
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/1221888-1.html b/testing/web-platform/tests/mathml/crashtests/mozilla/1221888-1.html
new file mode 100644
index 0000000000..741daa7503
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/1221888-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE htm>
+<html>
+<head>
+<meta charset="UTF-8">
+</head>
+<body>
+
+ <div>
+ <math>
+ <mspace height="50px" width="100px" style="outline-style: dotted;"></mspace>
+ </math>
+ </div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/1373767-1.html b/testing/web-platform/tests/mathml/crashtests/mozilla/1373767-1.html
new file mode 100644
index 0000000000..a159cec7be
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/1373767-1.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<style>
+math {
+ position: fixed;
+}
+div {
+ transform: translateZ(0px);
+}
+body {
+ display: -moz-box;
+}
+</style>
+</head>
+<body>
+<div>
+<math></math>
+</div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/1376158.html b/testing/web-platform/tests/mathml/crashtests/mozilla/1376158.html
new file mode 100644
index 0000000000..42b6dd73c8
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/1376158.html
@@ -0,0 +1,6 @@
+<math>
+<munderover>
+></ms>
+<munder accentunder="true">
+<mo>)</mo>
+<mscarry>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/151054-1.xml b/testing/web-platform/tests/mathml/crashtests/mozilla/151054-1.xml
new file mode 100644
index 0000000000..f634d089f3
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/151054-1.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="Content-Type" content="text/html" />
+ <title>Math with position: absolute</title>
+ <style>
+ math { position: absolute; }
+ </style>
+</head>
+<body>
+ <math xmlns="http://www.w3.org/1998/Math/MathML">
+ <infinity/>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/1600635.html b/testing/web-platform/tests/mathml/crashtests/mozilla/1600635.html
new file mode 100644
index 0000000000..d6ad315885
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/1600635.html
@@ -0,0 +1,16 @@
+<style>
+ * {
+ overflow-inline: scroll;
+ }
+</style>
+<script>
+ window.addEventListener('load', () => {
+ const mbsubsup = document.createElementNS('http://www.w3.org/1998/Math/MathML', 'msubsup')
+ const m = document.createElementNS('http://www.w3.org/1998/Math/MathML', 'm')
+ const ms = document.createElementNS('http://www.w3.org/1998/Math/MathML', 'ms')
+ mbsubsup.appendChild(m)
+ ms.innerHTML = '<figure>'
+ mbsubsup.appendChild(ms)
+ document.documentElement.appendChild(mbsubsup)
+ })
+</script>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/289180-1.xml b/testing/web-platform/tests/mathml/crashtests/mozilla/289180-1.xml
new file mode 100644
index 0000000000..8d1f2e843c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/289180-1.xml
@@ -0,0 +1,16 @@
+
+
+ <math xmlns="http://www.w3.org/1998/Math/MathML" mode="inline">
+ <mfrac>
+ <mi>x</mi>
+ <mi>y</mi>
+ </mfrac>
+ </math>
+ <math xmlns="http://www.w3.org/1998/Math/MathML" mode="display">
+ <mfrac>
+
+ <mi>x</mi>
+ <mi>y</mi>
+ </mfrac>
+ </math>
+
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/307826-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/307826-1.xhtml
new file mode 100644
index 0000000000..02d436e825
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/307826-1.xhtml
@@ -0,0 +1,30 @@
+<html xmlns="http://www.w3.org/1999/xhtml" class="test-wait">
+
+<head>
+
+<title>Testcase for MathML crash</title>
+
+<script><![CDATA[
+
+function boom() {
+ var div = document.getElementById("div");
+ var mi = document.getElementById("mi");
+ mi.appendChild(div);
+ mi.removeChild(div);
+
+ document.documentElement.removeAttribute("class");
+}
+
+]]></script>
+
+</head>
+
+
+<body onload="setTimeout(boom, 30);">
+
+<div style="float: right;" id="div">Floated div</div>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mi id="mi">mi</mi></math>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/307839-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/307839-1.xhtml
new file mode 100644
index 0000000000..a26e58ac07
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/307839-1.xhtml
@@ -0,0 +1,15 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>Testcase</title>
+ </head>
+ <body onload="document.getElementById('B').appendChild(document.getElementById('A'));">
+ <div style="position: relative;">
+ <math xmlns="http://www.w3.org/1998/Math/MathML">
+ <mover>
+ <mrow id="A"/>
+ <mn id="B"/>
+ </mover>
+ </math>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/307839-2.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/307839-2.xhtml
new file mode 100644
index 0000000000..05dc08a78f
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/307839-2.xhtml
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" "http://www.w3.org/TR/MathML2/dtd/xhtml-math11-f.dtd" [
+ <!ENTITY mathml "http://www.w3.org/1998/Math/MathML">
+]>
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+<title>Testcase bug - Evil mrow:hover testcase crashes Mozilla</title>
+<style type="text/css">
+#h:hover{display:block;}
+</style>
+</head>
+<body onload="document.getElementById('mrow').setAttribute('id', 'h');">
+<math mode="display" xmlns="http://www.w3.org/1998/Math/MathML">
+<mover>
+ <mrow id="mrow">hovering over this should not crash Mozilla</mrow>
+ <mover>
+ <mo>10</mo>
+ <mrow>times</mrow>
+ </mover>
+</mover>
+</math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/323733-1.xml b/testing/web-platform/tests/mathml/crashtests/mozilla/323733-1.xml
new file mode 100644
index 0000000000..5551d8588c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/323733-1.xml
@@ -0,0 +1,7 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <div>
+ <math xmlns="http://www.w3.org/1998/Math/MathML" display="inline">
+ <ms />
+ </math>
+ </div>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/323737-1.xml b/testing/web-platform/tests/mathml/crashtests/mozilla/323737-1.xml
new file mode 100644
index 0000000000..ad673f9460
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/323737-1.xml
@@ -0,0 +1,9 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <div>
+ <math xmlns="http://www.w3.org/1998/Math/MathML" display="inline">
+ <mtable>
+ <mroot />
+ </mtable>
+ </math>
+ </div>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/323738-1.xml b/testing/web-platform/tests/mathml/crashtests/mozilla/323738-1.xml
new file mode 100644
index 0000000000..318aa93b4e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/323738-1.xml
@@ -0,0 +1,11 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <div>
+ <math xmlns="http://www.w3.org/1998/Math/MathML" display="inline">
+ <msub>
+ <mo>
+ <factorial />
+ </mo>
+ </msub>
+ </math>
+ </div>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/323741-1.xml b/testing/web-platform/tests/mathml/crashtests/mozilla/323741-1.xml
new file mode 100644
index 0000000000..8527c1a783
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/323741-1.xml
@@ -0,0 +1,13 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <div>
+ <math xmlns="http://www.w3.org/1998/Math/MathML" display="inline">
+ <notin>
+ <mspace>
+ <mfenced />
+ </mspace>
+
+ f
+ </notin>
+ </math>
+ </div>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/323742-1.xml b/testing/web-platform/tests/mathml/crashtests/mozilla/323742-1.xml
new file mode 100644
index 0000000000..2cd225990d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/323742-1.xml
@@ -0,0 +1,16 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <div>
+ <math xmlns="http://www.w3.org/1998/Math/MathML" display="inline">
+
+ <eulergamma>
+ <arcsech>
+ <mrow>
+ <mtable>
+ <maction/>
+ </mtable>
+ </mrow>
+ </arcsech>
+ </eulergamma>
+ </math>
+ </div>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/336074-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/336074-1.xhtml
new file mode 100644
index 0000000000..3d1f5b4223
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/336074-1.xhtml
@@ -0,0 +1,25 @@
+<html xmlns="http://www.w3.org/1999/xhtml" class="test-wait">
+
+<head>
+
+<script>
+<![CDATA[
+
+function init()
+{
+ var k = document.getElementById("k");
+ k.remove();
+ document.documentElement.removeAttribute("class");
+}
+
+]]>
+</script>
+
+</head>
+
+<body onload="setTimeout(init, 30);">
+
+<mo xmlns='http://www.w3.org/1998/Math/MathML'><mi id="k">z</mi></mo>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/347355-1-inner.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/347355-1-inner.xhtml
new file mode 100644
index 0000000000..22689c3c12
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/347355-1-inner.xhtml
@@ -0,0 +1,28 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script>
+
+function foo()
+{
+ var mrow = document.getElementById("mrow")
+
+ mrow.parentNode.removeChild(mrow);
+}
+
+</script>
+</head>
+
+<body onload="setTimeout(foo, 100)">
+
+<div>
+<math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
+ <mrow id="mrow">
+ <mtd><img xmlns="http://www.w3.org/1999/xhtml" src="347355-1.gif" /></mtd>
+ <mtable> <mtr> <mtd><mi>t</mi></mtd> </mtr> </mtable>
+ </mrow>
+</math>
+</div>
+
+</body>
+
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/347355-1.gif b/testing/web-platform/tests/mathml/crashtests/mozilla/347355-1.gif
new file mode 100644
index 0000000000..475ea8c164
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/347355-1.gif
Binary files differ
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/347355-1.html b/testing/web-platform/tests/mathml/crashtests/mozilla/347355-1.html
new file mode 100644
index 0000000000..0d61fb9d4a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/347355-1.html
@@ -0,0 +1,9 @@
+<html class="test-wait">
+<head>
+<script>
+setTimeout('document.documentElement.className = ""', 1000);
+</script>
+<body>
+<iframe src="347355-1-inner.xhtml"></iframe>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/347495-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/347495-1.xhtml
new file mode 100644
index 0000000000..4a65b8f34d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/347495-1.xhtml
@@ -0,0 +1,10 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body>
+
+<div><math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
+ <munderover> <mo>&#x0220F;</mo> <mn>1</mn> </munderover>
+</math></div>
+
+</body>
+
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/347507-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/347507-1.xhtml
new file mode 100644
index 0000000000..274ae48ff2
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/347507-1.xhtml
@@ -0,0 +1,29 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script>
+
+function foo()
+{
+ var div = document.getElementById("div");
+ div.appendChild(div.firstChild);
+
+ var td = document.getElementById("td");
+ td.setAttribute('rowspan', -2);
+}
+
+</script>
+
+</head>
+
+<body onload="foo()">
+
+
+<div id="div"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
+
+ <mtable> <mtr> <mtd id="td"><mi>y</mi></mtd> </mtr> </mtable>
+
+</math></div>
+
+</body>
+
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/348492-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/348492-1.xhtml
new file mode 100644
index 0000000000..f59c9353a4
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/348492-1.xhtml
@@ -0,0 +1,31 @@
+<html xmlns="http://www.w3.org/1999/xhtml" class="test-wait">
+<head>
+
+<script>
+var MATHML_NS = "http://www.w3.org/1998/Math/MathML";
+
+function foo()
+{
+ var mmultiscripts = document.createElementNS(MATHML_NS, 'mmultiscripts');
+ var mtd = document.createElementNS(MATHML_NS, 'mtd');
+
+
+ document.body.appendChild(mmultiscripts);
+ aC(mmultiscripts, mtd);
+ aC(mmultiscripts, document.createTextNode('foo'));
+
+ document.documentElement.removeAttribute("class");
+}
+
+function aC(q1, q2) { q1.appendChild(q2); }
+
+</script>
+</head>
+
+<body onload="setTimeout(foo, 30)">
+
+
+
+</body>
+
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/348709-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/348709-1.xhtml
new file mode 100644
index 0000000000..907ede6abb
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/348709-1.xhtml
@@ -0,0 +1,20 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+
+<script>
+function foo()
+{
+ document.getElementById("mtr").appendChild(document.createTextNode("a"));
+}
+</script>
+</head>
+
+<body onload="foo()">
+
+<div><math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
+<mrow> <mfenced open="[" close="]"> <mtable> <mtr id="mtr"> <mtd><mi>x</mi></mtd> <mtd><mi>y</mi></mtd> </mtr> </mtable> </mfenced> </mrow>
+</math></div>
+
+</body>
+
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/348811-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/348811-1.xhtml
new file mode 100644
index 0000000000..f6557e5a67
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/348811-1.xhtml
@@ -0,0 +1,26 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script>
+function foo()
+{
+ var newTable = document.createElementNS("http://www.w3.org/1998/Math/MathML", "mtable")
+
+ document.getElementById("mtr").appendChild(newTable);
+}
+</script>
+</head>
+
+<body onload="foo()">
+
+
+<div>
+ <math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
+ <mtable> <mtr id="mtr"> <mtd>
+ <mi>x</mi>
+ </mtd> </mtr> </mtable> </math>
+</div>
+
+
+</body>
+
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/348811-2.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/348811-2.xhtml
new file mode 100644
index 0000000000..d6a741765a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/348811-2.xhtml
@@ -0,0 +1,31 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script>
+function foo()
+{
+ var m = "http://www.w3.org/1998/Math/MathML";
+ var newTable = document.createElementNS(m, "mtable")
+ document.getElementById("mtable").appendChild(newTable);
+}
+</script>
+</head>
+
+<body onload="foo()">
+
+
+<div>
+ <math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
+ <mtable id="mtable">
+ <mtr id="mtr">
+ <mtd>
+ <mi>x</mi>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+</div>
+
+
+</body>
+
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/353612-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/353612-1.xhtml
new file mode 100644
index 0000000000..386e66f933
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/353612-1.xhtml
@@ -0,0 +1,17 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script>
+function foo()
+{
+ document.getElementById("ms").setAttribute("lquote", "'");
+}
+</script>
+</head>
+
+<body onload="foo()">
+
+<mtr xmlns="http://www.w3.org/1998/Math/MathML" />
+<mstyle xmlns="http://www.w3.org/1998/Math/MathML" id="ms" />
+</body>
+
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/355986-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/355986-1.xhtml
new file mode 100644
index 0000000000..787e1f6772
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/355986-1.xhtml
@@ -0,0 +1,34 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+
+<head>
+<style>
+
+body * {
+ display: table-footer-group;
+ overflow: hidden scroll;
+}
+
+</style>
+</head>
+
+
+
+<body onload="document.getElementById('eee').style.display = 'inline';">
+
+
+
+
+<div id="eee">
+ <math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
+ <mtable>
+ <mtr>
+ <mtd><mi>x</mi></mtd>
+ </mtr>
+ </mtable>
+ </math>
+</div>
+
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/364685-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/364685-1.xhtml
new file mode 100644
index 0000000000..ab2b56a2f8
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/364685-1.xhtml
@@ -0,0 +1,19 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:math="http://www.w3.org/1998/Math/MathML">
+
+<body onload="boom();">
+
+<script>
+function boom()
+{
+ document.getElementById("merror").appendChild(document.getElementById("s"));
+}
+</script>
+
+<math:merror id="merror"></math:merror>
+
+<span id="s" />
+
+</body>
+</html>
+
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/366012-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/366012-1.xhtml
new file mode 100644
index 0000000000..55f29f3ac3
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/366012-1.xhtml
@@ -0,0 +1,23 @@
+<html xmlns="http://www.w3.org/1999/xhtml" class="test-wait">
+
+<head>
+<script>
+
+function boom()
+{
+ var doom = document.getElementById("doom");
+ doom.parentNode.removeChild(doom);
+ document.documentElement.removeAttribute("class");
+}
+
+</script>
+</head>
+
+<body onload="setTimeout(boom, 30);">
+ <div>
+ <p id="doom">This paragraph disappears.</p>
+ <math xmlns='http://www.w3.org/1998/Math/MathML' display='block'><msub><mi>y</mi><mn>0</mn><frameset xmlns="http://www.w3.org/1999/xhtml" /></msub></math>
+ </div>
+</body>
+
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/366564-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/366564-1.xhtml
new file mode 100644
index 0000000000..8bb112a30d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/366564-1.xhtml
@@ -0,0 +1,44 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/xhtml-math11-f.dtd" >
+<html xmlns="http://www.w3.org/1999/xhtml" class="test-wait">
+<head>
+<script>
+function boom1()
+{
+ document.getElementById("mfenced3").appendChild(document.getElementById("div4"));
+ setTimeout(boom2, 30);
+}
+
+function boom2()
+{
+ document.getElementById("sup1").appendChild(document.getElementById("mo2"));
+ document.documentElement.removeAttribute("class");
+}
+
+</script>
+</head>
+
+<body onload="setTimeout(boom1, 30);">
+
+<div><math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
+ <msup id="sup1">
+ <mi>b</mi>
+ <mn>2</mn>
+ </msup>
+</math></div>
+
+<div><math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
+ <mi>j</mi>
+ <mo id="mo2">=</mo>
+ <mfenced id="mfenced3" open="[" close="]">
+ <mn>55</mn>
+ </mfenced>
+</math></div>
+
+<div id="div4"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
+ <mo> &int; </mo>
+</math></div>
+
+</body>
+
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/367107-1.html b/testing/web-platform/tests/mathml/crashtests/mozilla/367107-1.html
new file mode 100644
index 0000000000..775ace87e0
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/367107-1.html
@@ -0,0 +1,22 @@
+<html>
+<head>
+<script>
+
+function boom()
+{
+ var MATHML_NS = "http://www.w3.org/1998/Math/MathML";
+
+ var mtr = document.createElementNS(MATHML_NS, 'mtr');
+ var mtable = document.createElementNS(MATHML_NS, 'mtable');
+
+ document.body.appendChild(mtr);
+ mtr.appendChild(mtable);
+}
+
+</script>
+</head>
+
+<body onload="boom()">
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/368430-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/368430-1.xhtml
new file mode 100644
index 0000000000..79e10c46ac
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/368430-1.xhtml
@@ -0,0 +1,5 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body>
+<maction xmlns="http://www.w3.org/1998/Math/MathML">Foo Bar</maction>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/370791-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/370791-1.xhtml
new file mode 100644
index 0000000000..d72eb5f709
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/370791-1.xhtml
@@ -0,0 +1,33 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:math="http://www.w3.org/1998/Math/MathML" class="test-wait">
+<head>
+<script>
+
+function boom()
+{
+ var mi = document.getElementById("mi");
+ var textA = mi.firstChild;
+ var textB = document.createTextNode("b");
+ var textSpace = document.createTextNode(" ");
+
+ var floater = document.getElementById("floater");
+
+ mi.appendChild(textB);
+ mi.appendChild(textSpace);
+ mi.removeChild(textA);
+ mi.removeChild(textSpace);
+
+ floater.parentNode.removeChild(floater);
+
+ document.documentElement.removeAttribute("class");
+}
+
+</script>
+</head>
+
+<body onload="setTimeout(boom, 30);">
+
+<math:mi id="mi">a<p><span style="float: right;" id="floater" /></p></math:mi>
+
+</body>
+
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/370862-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/370862-1.xhtml
new file mode 100644
index 0000000000..fa2f1a4d67
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/370862-1.xhtml
@@ -0,0 +1,27 @@
+<html xmlns="http://www.w3.org/1999/xhtml" class="test-wait">
+
+<head>
+<script>
+function boom()
+{
+ var math = document.getElementById("math");
+ var div = document.getElementById("div")
+
+ math.setAttribute("color", "g");
+ document.body.appendChild(div);
+
+ document.documentElement.removeAttribute("class");
+}
+</script>
+</head>
+
+<body onload="setTimeout(boom, 30);">
+
+<div id="div">
+
+<mo xmlns='http://www.w3.org/1998/Math/MathML'>+<math id="math"><mn>1</mn></math></mo>
+
+</div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/372483-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/372483-1.xhtml
new file mode 100644
index 0000000000..41edd7d9b7
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/372483-1.xhtml
@@ -0,0 +1,7 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body>
+
+<div><munder xmlns="http://www.w3.org/1998/Math/MathML"/></div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/373472-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/373472-1.xhtml
new file mode 100644
index 0000000000..6c6a304a73
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/373472-1.xhtml
@@ -0,0 +1,20 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script>
+function boom()
+{
+ document.getElementById("mo").appendChild(document.getElementById("mo2"));
+ document.body.offsetWidth;
+ document.getElementById("span").appendChild(document.createTextNode("baz"));
+}
+</script>
+</head>
+
+<body onload="boom();">
+
+<p>Foo <math xmlns="http://www.w3.org/1998/Math/MathML"><mo id="mo2">-</mo></math></p>
+
+<p><math xmlns="http://www.w3.org/1998/Math/MathML"><msub id="msub"><mo id="mo">+</mo></msub></math> <span id="span">bar</span></p>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/373472-2.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/373472-2.xhtml
new file mode 100644
index 0000000000..1c7e1c7ade
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/373472-2.xhtml
@@ -0,0 +1,9 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+</head>
+<body>
+
+<p><math xmlns="http://www.w3.org/1998/Math/MathML"><mroot><mo>k</mo></mroot></math></p>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/375562-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/375562-1.xhtml
new file mode 100644
index 0000000000..7b00d1f91a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/375562-1.xhtml
@@ -0,0 +1,38 @@
+<html xmlns="http://www.w3.org/1999/xhtml" class="test-wait">
+<head>
+<script>
+
+var HTML_NS = "http://www.w3.org/1999/xhtml";
+
+function boom()
+{
+ var a = document.getElementById("a");
+ var plus = document.getElementById("plus");
+ var frameset = document.createElementNS(HTML_NS, "frameset");
+
+ document.body.style.width = "300px";
+
+ a.parentNode.removeChild(a);
+
+ plus.appendChild(frameset);
+
+ document.documentElement.removeAttribute("class");
+}
+
+</script>
+</head>
+
+<body onload="setTimeout(boom, 30);">
+
+<div><math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
+ <msup>
+ <mi id="a">a</mi>
+ <mo id="plus">+</mo>
+ <mi>b</mi>
+ <mi>c</mi>
+ </msup>
+</math></div>
+
+</body>
+
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/377824-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/377824-1.xhtml
new file mode 100644
index 0000000000..ddbe7da664
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/377824-1.xhtml
@@ -0,0 +1,5 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:math="http://www.w3.org/1998/Math/MathML">
+<body>
+<math:mtable />
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/379418-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/379418-1.xhtml
new file mode 100644
index 0000000000..dc6e9e5711
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/379418-1.xhtml
@@ -0,0 +1,7 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body>
+<math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
+ע</math>
+</body>
+</html>
+
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/385226-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/385226-1.xhtml
new file mode 100644
index 0000000000..b1d261eb38
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/385226-1.xhtml
@@ -0,0 +1,29 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:html="http://www.w3.org/1999/xhtml">
+
+<head>
+<style>
+[class="capleft"] { caption-side: left; }
+[class="collapse"] { visibility: collapse; }
+</style>
+</head>
+
+<body>
+
+<div>
+ <math xmlns="http://www.w3.org/1998/Math/MathML" display="block" class="collapse">
+ <mtable>
+ <mtr>
+ <mtd><mi>x</mi></mtd>
+ <mtd><mi>y</mi></mtd>
+ </mtr>
+ <html:caption class="capleft">
+ <mtd><mi>z</mi></mtd>
+ <mtd><mi>w</mi></mtd>
+ </html:caption>
+ </mtable>
+ </math>
+</div>
+
+</body>
+
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/393760-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/393760-1.xhtml
new file mode 100644
index 0000000000..cb5c2d7a12
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/393760-1.xhtml
@@ -0,0 +1,16 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:math="http://www.w3.org/1998/Math/MathML">
+<head>
+<script>
+function boom()
+{
+ document.getElementById("mfenced").setAttribute("mathbackground", "yellow");
+}
+</script>
+</head>
+
+<body onload="boom();">
+
+<math:mfenced id="mfenced" />
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/397518-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/397518-1.xhtml
new file mode 100644
index 0000000000..bc460ead11
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/397518-1.xhtml
@@ -0,0 +1,15 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:math="http://www.w3.org/1998/Math/MathML">
+<head>
+<script>
+function boom()
+{
+ var span = document.getElementById("s");
+ var newSpan = document.createElementNS("http://www.w3.org/1999/xhtml", "span");
+ span.appendChild(newSpan);
+}
+</script>
+</head>
+<body onload="boom();">
+<math:math><span id="s"><div/></span></math:math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/398038-1.html b/testing/web-platform/tests/mathml/crashtests/mozilla/398038-1.html
new file mode 100644
index 0000000000..b383141c45
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/398038-1.html
@@ -0,0 +1,8 @@
+<html>
+<head><title>Crashtest for bug 398038</title></head>
+<body>
+ <math><mpadded height="20 10"/></math>
+ <math><mpadded height="10 0000000000em"/></math>
+ <math><mpadded height="10 1.2em"/></math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/400475-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/400475-1.xhtml
new file mode 100644
index 0000000000..13ff2fcb63
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/400475-1.xhtml
@@ -0,0 +1,16 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script>
+function foo()
+{
+ document.getElementById("ms").setAttribute("foo", "x");
+}
+</script>
+</head>
+
+<body onload="foo()">
+
+<mstyle xmlns="http://www.w3.org/1998/Math/MathML" id="ms" />
+</body>
+
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/402400-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/402400-1.xhtml
new file mode 100644
index 0000000000..5212d67f16
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/402400-1.xhtml
@@ -0,0 +1,41 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script type="text/javascript">
+
+function boom()
+{
+ var textB = document.createTextNode("b");
+ var textC = document.createTextNode("c");
+ var textN = document.createTextNode("n");
+ var textP = document.createTextNode("p");
+
+ var blv = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
+ var odj = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
+ var tr = document.createElementNS("http://www.w3.org/1999/xhtml", "tr");
+ var td = document.createElementNS("http://www.w3.org/1999/xhtml", "td");
+ var mathMO = document.createElementNS("http://www.w3.org/1998/Math/MathML", "mo");
+
+ td.appendChild(textB);
+ document.body.appendChild(blv);
+ blv.appendChild(tr);
+ blv.appendChild(mathMO);
+ mathMO.appendChild(textP);
+ odj.appendChild(td);
+ odj.appendChild(textN);
+
+ blv.removeChild(tr);
+ mathMO.appendChild(odj);
+ td.removeChild(textB);
+ blv.appendChild(textC);
+ document.body.appendChild(odj);
+ odj.insertBefore(mathMO, textN);
+ document.body.appendChild(mathMO);
+ mathMO.appendChild(odj);
+}
+
+</script>
+</head>
+
+<body onload="boom();"></body>
+
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/403156-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/403156-1.xhtml
new file mode 100644
index 0000000000..b49bff7d04
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/403156-1.xhtml
@@ -0,0 +1,12 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:m="http://www.w3.org/1998/Math/MathML">
+
+<head>
+<style>
+maction { height: 12em; }
+</style>
+</head>
+
+<body>
+<m:maction>&#x499a;<span>c<div>t&#x499a;</div></span>&#x499a;x&#x499a;&#x499a;2</m:maction>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/404485-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/404485-1.xhtml
new file mode 100644
index 0000000000..fea18cbd59
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/404485-1.xhtml
@@ -0,0 +1,9 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:math="http://www.w3.org/1998/Math/MathML">
+
+<body onload="document.getElementById('s').firstChild.splitText(1);">
+
+<math:msqrt><span xmlns="http://www.w3.org/1999/xhtml" id="s">x <math:mo/></span></math:msqrt>
+
+</body>
+
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/405187-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/405187-1.xhtml
new file mode 100644
index 0000000000..537512e629
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/405187-1.xhtml
@@ -0,0 +1,10 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:m="http://www.w3.org/1998/Math/MathML">
+<head>
+<style id="s">
+[class="fx"] { position: fixed; }
+</style>
+</head>
+<body onload="document.getElementById('s').textContent = '* { color: magenta; }'">
+<m:mrow><m:mrow class="fx" /><span class="fx" /></m:mrow>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/405271-1.xml b/testing/web-platform/tests/mathml/crashtests/mozilla/405271-1.xml
new file mode 100644
index 0000000000..c94525c638
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/405271-1.xml
@@ -0,0 +1,36 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:m="http://www.w3.org/1998/Math/MathML">
+<head>
+
+<style type="text/css">
+#q { width: 16px; height: 16px; }
+#a, #b { counter-increment: chicken; }
+</style>
+
+<style id="s" type="text/css">
+#a { content: 'x'; }
+</style>
+
+<script type="text/javascript">
+
+function boom()
+{
+ remove(document.getElementById("s"));
+ remove(document.getElementById("b"));
+}
+
+function remove(n)
+{
+ n.parentNode.removeChild(n);
+}
+
+</script>
+
+</head>
+
+<body onload="boom();">
+
+<m:mrow id="a"/><m:mo id="q"><m:malignmark><m:msubsup/><m:munderover/><m:munder id="b"/></m:malignmark></m:mo>
+
+</body>
+
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/412237-1.xml b/testing/web-platform/tests/mathml/crashtests/mozilla/412237-1.xml
new file mode 100644
index 0000000000..2e8f13b73e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/412237-1.xml
@@ -0,0 +1,11 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+</head>
+<body>
+
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <ms fontsize="-2%"><mfrac><mi>x</mi><mi>y</mi></mfrac></ms>
+</math>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/413063-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/413063-1.xhtml
new file mode 100644
index 0000000000..b595acd1ce
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/413063-1.xhtml
@@ -0,0 +1,21 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:m="http://www.w3.org/1998/Math/MathML">
+<head>
+<script type="text/javascript">
+
+function boom()
+{
+ var mtd = document.getElementById("mtd");
+ var ns = document.createElementNS("http://www.w3.org/1999/xhtml", "span");
+ var nt = document.createTextNode("foo");
+ ns.appendChild(nt);
+ mtd.appendChild(ns);
+ mtd.setAttribute("rowspan", "0");
+}
+
+
+</script>
+</head>
+
+<body onload="boom();"><m:mtd id="mtd" style="display: table-footer-group"><m:mi /></m:mtd></body>
+
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/416907-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/416907-1.xhtml
new file mode 100644
index 0000000000..94a9abde21
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/416907-1.xhtml
@@ -0,0 +1,5 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:mathml="http://www.w3.org/1998/Math/MathML">
+<mathml:mroot>
+<frameset/>
+</mathml:mroot>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/420420-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/420420-1.xhtml
new file mode 100644
index 0000000000..db17b277a7
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/420420-1.xhtml
@@ -0,0 +1,7 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/xhtml-math11-f.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:m="http://www.w3.org/1998/Math/MathML">
+<body>
+<m:math><span><m:mfenced><m:mo>&ApplyFunction;</m:mo></m:mfenced></span></m:math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/431072-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/431072-1.xhtml
new file mode 100644
index 0000000000..f25ce28f14
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/431072-1.xhtml
@@ -0,0 +1,25 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+
+<script type="text/javascript">
+
+function boom()
+{
+ document.getElementById("math").setAttribute("class", "li");
+ document.documentElement.offsetHeight;
+ document.documentElement.appendChild(document.createTextNode("\n"));
+}
+
+</script>
+
+<style type="text/css">
+
+[class="li"] { display: list-item; }
+
+</style>
+
+</head>
+
+<body onload="boom();"><math xmlns="http://www.w3.org/1998/Math/MathML" id="math"/></body>
+
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/443089-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/443089-1.xhtml
new file mode 100644
index 0000000000..2630cea131
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/443089-1.xhtml
@@ -0,0 +1,7 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+</head>
+<body>
+<mtd xmlns="http://www.w3.org/1998/Math/MathML" id="mtd" rowspan="1073741825"/>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/462929-1.html b/testing/web-platform/tests/mathml/crashtests/mozilla/462929-1.html
new file mode 100644
index 0000000000..386d8e138f
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/462929-1.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script type="text/javascript">
+
+var a = document.createElementNS("http://www.w3.org/2000/svg", "foo");
+var b = document.createElementNS("http://www.w3.org/1998/Math/MathML", "math");
+
+</script>
+</head>
+<body></body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/463763-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/463763-1.xhtml
new file mode 100644
index 0000000000..61df8ff0c3
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/463763-1.xhtml
@@ -0,0 +1,10 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body>
+<math xmlns="http://www.w3.org/1998/Math/MathML"
+ xmlns:h="http://www.w3.org/1999/xhtml">
+<msup style="display:block"><mo><h:frameset/></mo></msup>
+<msub style="display:block"><mo><h:frameset/></mo></msub>
+<msubsup style="display:block"><mo><h:frameset/></mo></msubsup>
+</math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/463763-2.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/463763-2.xhtml
new file mode 100644
index 0000000000..8d41abade0
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/463763-2.xhtml
@@ -0,0 +1,12 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<body>
+<math xmlns="http://www.w3.org/1998/Math/MathML"
+ xmlns:h="http://www.w3.org/1999/xhtml">
+<mstyle displaystyle="false">
+<munder style="display:block"><mo movablelimits="true"><h:frameset/></mo></munder>
+<mover style="display:block"><mo movablelimits="true"><h:frameset/></mo></mover>
+<munderover style="display:block"><mo movablelimits="true"><h:frameset/></mo></munderover>
+</mstyle>
+</math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/476547-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/476547-1.xhtml
new file mode 100644
index 0000000000..0cece35eaa
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/476547-1.xhtml
@@ -0,0 +1,5 @@
+<html xmlns="http://www.w3.org/1999/xhtml" style="quotes: '&lt;1&gt;' '';">
+<body onload="document.getElementById('ms').setAttribute('lquote', '');" style="direction: rtl;">
+<span><ms id="ms" xmlns="http://www.w3.org/1998/Math/MathML"><mstyle/></ms></span>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/541620-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/541620-1.xhtml
new file mode 100644
index 0000000000..ccef762e48
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/541620-1.xhtml
@@ -0,0 +1,6 @@
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:m="http://www.w3.org/1998/Math/MathML">
+<body>
+<m:ms><m:mfenced/></m:ms>
+</body>
+</html>
+
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/557474-1.html b/testing/web-platform/tests/mathml/crashtests/mozilla/557474-1.html
new file mode 100644
index 0000000000..1bf8d534ca
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/557474-1.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Test mpadded</title>
+ </head>
+ <body>
+ <math>
+ <mpadded width="-100px" height="-100px" depth="-100px"></mpadded>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/654928-1.html b/testing/web-platform/tests/mathml/crashtests/mozilla/654928-1.html
new file mode 100644
index 0000000000..da52f34b45
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/654928-1.html
@@ -0,0 +1,3 @@
+<html>
+ <math><maction selection="2">A<mo>B</mo></maction></math>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/655451-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/655451-1.xhtml
new file mode 100644
index 0000000000..0d5fb687b7
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/655451-1.xhtml
@@ -0,0 +1,15 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script>
+
+function boom()
+{
+ document.documentElement.style.fontStyle = "oblique";
+ var c = document.getElementById("c");
+ c.parentNode.removeChild(c);
+}
+
+</script>
+</head>
+<body onload="boom();"><math xmlns="http://www.w3.org/1998/Math/MathML"><frameset xmlns="http://www.w3.org/1999/xhtml"></frameset><msubsup id="c"/><mo><frameset xmlns="http://www.w3.org/1999/xhtml"></frameset></mo></math>x</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/713606-1.html b/testing/web-platform/tests/mathml/crashtests/mozilla/713606-1.html
new file mode 100644
index 0000000000..a0d4939a83
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/713606-1.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Crashtest bug 713606</title>
+ </head>
+ <body onload="document.querySelector('mstyle').setAttribute('scriptminsize', '0%');">
+ <math>
+ <msubsup>
+ <mtext>X</mtext>
+ <mtable displaystyle="true"></mstyle>
+ </mtext>Y</mtext>
+ </msubsup>
+ </math>
+ <math>
+ <msubsup>
+ <mtext>X</mtext>
+ <mstyle displaystyle="true"></mstyle>
+ </mtext>Y</mtext>
+ </msubsup>
+ </math>
+ <math><mfrac><mstyle displaystyle="true"></mstyle></mfrac></math>
+ </body>
+</html>
+
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/716349-1.html b/testing/web-platform/tests/mathml/crashtests/mozilla/716349-1.html
new file mode 100644
index 0000000000..9b5895ad64
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/716349-1.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Crashtest bug 716349</title>
+ </head>
+ <body>
+ <math>
+ <mspace width="-10px"/>
+ <mspace height="-10px"/>
+ </math>
+ </body>
+</html>
+
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/767251.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/767251.xhtml
new file mode 100644
index 0000000000..aa3632a6ba
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/767251.xhtml
@@ -0,0 +1 @@
+<html xmlns="http://www.w3.org/1999/xhtml" dir="rtl"><tr><span><math xmlns="http://www.w3.org/1998/Math/MathML"/><tr>n</tr></span></tr></html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/770710-1.html b/testing/web-platform/tests/mathml/crashtests/mozilla/770710-1.html
new file mode 100644
index 0000000000..2171966769
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/770710-1.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+function boom()
+{
+ var mo = document.createElementNS("http://www.w3.org/1998/Math/MathML", "mo");
+ var text = document.createTextNode(" ");
+ mo.appendChild(text);
+ document.body.appendChild(mo);
+
+ window.getSelection().removeAllRanges();
+ var r = document.createRange();
+ r.setStart(mo.firstChild, 0);
+ r.setEnd(mo.firstChild, 1);
+ window.getSelection().addRange(r);
+
+ window.getSelection().toString();
+}
+
+</script>
+</head>
+<body onload="boom();"></body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/848725-1.html b/testing/web-platform/tests/mathml/crashtests/mozilla/848725-1.html
new file mode 100644
index 0000000000..7ce9c434cc
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/848725-1.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Bug 848725</title>
+ <meta charset="utf-8"/>
+ </head>
+ <body>
+ <div>
+ <math>
+ <mover>
+ <mo>&#x21A0;</mo>
+ <mspace width="500px"></mspace>
+ </mover>
+ </math>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/848725-2.html b/testing/web-platform/tests/mathml/crashtests/mozilla/848725-2.html
new file mode 100644
index 0000000000..b6362f9bf2
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/848725-2.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Bug 848725</title>
+ <meta charset="utf-8"/>
+ </head>
+ <body>
+ <div>
+ <math>
+ <mover>
+ <mo>&#x21A1;</mo>
+ <mspace height="500px"></mspace>
+ </mover>
+ </math>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/947557-1.html b/testing/web-platform/tests/mathml/crashtests/mozilla/947557-1.html
new file mode 100644
index 0000000000..3ddfb7b984
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/947557-1.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<body>
+ <math>
+ <mmultiscripts>
+ <mo>A</mo>
+ <mprescripts/>
+ <mmultiscripts>
+ <mo>A</mo>
+ <mprescripts/>
+ <mo>A</mo>
+ <mo>A</mo>
+ </mmultiscripts>
+ <mmultiscripts>
+ <mo>A</mo>
+ <mprescripts/>
+ <mo>A</mo>
+ <mo>A</mo>
+ </mmultiscripts>
+ </mmultiscripts>
+ </math>
+</body>
diff --git a/testing/web-platform/tests/mathml/crashtests/mozilla/973322-1.xhtml b/testing/web-platform/tests/mathml/crashtests/mozilla/973322-1.xhtml
new file mode 100644
index 0000000000..dfac127fb4
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mozilla/973322-1.xhtml
@@ -0,0 +1,8 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <body onload="document.getElementById('f').setAttribute('class', 'e');">
+ <math xmlns="http://www.w3.org/1998/Math/MathML">
+ <mfenced id="f"/>
+ </math>
+ <p style="overflow: scroll; position: sticky;"></p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/crashtests/mspace-mpadded-negative-dimensions.html b/testing/web-platform/tests/mathml/crashtests/mspace-mpadded-negative-dimensions.html
new file mode 100644
index 0000000000..97ae5b89b8
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mspace-mpadded-negative-dimensions.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1421195">
+<math><mspace width="-1px"/></math>
+<math><mspace height="-1px"/></math>
+<math><mspace depth="-1px"/></math>
+<math><mspace height="-2px" depth="1px"/></math>
+<math><mspace height="1px" depth="-2px"/></math>
+<math><mpadded width="-1px"/></math>
+<math><mpadded height="-1px"/></math>
+<math><mpadded depth="-1px"/></math>
+<math><mpadded height="-2px" depth="1px"></mpadded></math>
+<math><mpadded height="1px" depth="-2px"></mpadded></math>
+<math><mpadded lspace="-1px"/></math>
diff --git a/testing/web-platform/tests/mathml/crashtests/mtd-as-multicol.html b/testing/web-platform/tests/mathml/crashtests/mtd-as-multicol.html
new file mode 100644
index 0000000000..f00fa48815
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/mtd-as-multicol.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1354561">
+<div id="container"></div>
+<script>
+ mtd = document.createElementNS("http://www.w3.org/1998/Math/MathML", "mtd");
+ mtd.style.columns = "2";
+ container.appendChild(mtd);
+</script>
diff --git a/testing/web-platform/tests/mathml/crashtests/multicol-inside-ms.html b/testing/web-platform/tests/mathml/crashtests/multicol-inside-ms.html
new file mode 100644
index 0000000000..b7d481e1fb
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/multicol-inside-ms.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mailto:mstensho@chromium.org">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1178979">
+<math><ms><span><span style="columns:3;">
diff --git a/testing/web-platform/tests/mathml/crashtests/multicol-on-token-elements.html b/testing/web-platform/tests/mathml/crashtests/multicol-on-token-elements.html
new file mode 100644
index 0000000000..9fc00eb691
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/multicol-on-token-elements.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<math><mi style="column-count: 10">mi</mi></math>
+<math><mi style="column-width: 10px">mi</mi></math>
+<math><mn style="column-count: 10">mn</mn></math>
+<math><mn style="column-width: 10px">mn</mn></math>
+<math><mo style="column-count: 10">mo</mo></math>
+<math><mo style="column-width: 10px">mo</mo></math>
+<math><ms style="column-count: 10">ms</ms></math>
+<math><ms style="column-width: 10px">ms</ms></math>
+<math><mtext style="column-count: 10">mtext</mtext></math>
+<math><mtext style="column-width: 10px">mtext</mtext></math>
diff --git a/testing/web-platform/tests/mathml/crashtests/operator-and-first-letter.html b/testing/web-platform/tests/mathml/crashtests/operator-and-first-letter.html
new file mode 100644
index 0000000000..a4d56de72f
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/operator-and-first-letter.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<style>
+ p::first-letter { --panel-arrowcontent-color:-moz-FieldText; }
+</style>
+<p>
+ <math display="block">
+ <mo>&#x222B;</mo>
+ </math>
+</p>
diff --git a/testing/web-platform/tests/mathml/crashtests/scrollbar-caching-assert.html b/testing/web-platform/tests/mathml/crashtests/scrollbar-caching-assert.html
new file mode 100644
index 0000000000..3f972ef70d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/crashtests/scrollbar-caching-assert.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1663740">
+<style>
+@namespace url(http://www.w3.org/1998/Math/MathML);
+* {
+ all: inherit;
+ overflow-inline: hidden;
+}
+</style>
+<script>
+window.addEventListener('load', () => {
+ var x = document.getElementById('a')
+ x.setAttribute('mathvariant', 'double-struck')
+ x.innerHTML = '<select></select>'
+})
+</script>
+<math id='a'>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/direction/direction-006-ref.html b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-006-ref.html
new file mode 100644
index 0000000000..39e6dabdfb
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-006-ref.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>RTL mtable and mtable with frame</title>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math, math * {
+ font: 25px Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <p>
+ <math>
+ <mtable>
+ <mtr>
+ <mtd>
+ <mtext>É</mtext>
+ </mtd>
+ <mtd>
+ <mtext>p</mtext>
+ </mtd>
+ <mtd>
+ <mtext>X</mtext>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mtext>pÉ</mtext>
+ </mtd>
+ <mtd>
+ <mtext>XÉ</mtext>
+ </mtd>
+ <mtd>
+ <mtext>Xp</mtext>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <mtable frame="solid">
+ <mtr>
+ <mtd>
+ <mtext>É</mtext>
+ </mtd>
+ <mtd>
+ <mtext>p</mtext>
+ </mtd>
+ <mtd>
+ <mtext>X</mtext>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mtext>pÉ</mtext>
+ </mtd>
+ <mtd>
+ <mtext>XÉ</mtext>
+ </mtd>
+ <mtd>
+ <mtext>Xp</mtext>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/direction/direction-006.html b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-006.html
new file mode 100644
index 0000000000..76cdc41471
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-006.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>RTL mtable and mtable with frame</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#tabular-math">
+ <meta name="assert" content="Verify RTL math table renders the same as the column mirrored.">
+ <link rel="match" href="direction-006-ref.html">
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math, math * {
+ font: 25px Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <p>
+ <math dir="rtl">
+ <mtable>
+ <mtr>
+ <mtd>
+ <mtext>X</mtext>
+ </mtd>
+ <mtd>
+ <mtext>p</mtext>
+ </mtd>
+ <mtd>
+ <mtext>É</mtext>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mtext>Xp</mtext>
+ </mtd>
+ <mtd>
+ <mtext>XÉ</mtext>
+ </mtd>
+ <mtd>
+ <mtext>pÉ</mtext>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+
+ <p>
+ <math dir="rtl">
+ <mtable frame="solid">
+ <mtr>
+ <mtd>
+ <mtext>X</mtext>
+ </mtd>
+ <mtd>
+ <mtext>p</mtext>
+ </mtd>
+ <mtd>
+ <mtext>É</mtext>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mtext>Xp</mtext>
+ </mtd>
+ <mtd>
+ <mtext>XÉ</mtext>
+ </mtd>
+ <mtd>
+ <mtext>pÉ</mtext>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_dir");</script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/direction/direction-007-ref.html b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-007-ref.html
new file mode 100644
index 0000000000..5c77395f20
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-007-ref.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>mo and embellished mrow/munderover (lspace=1em rspace=2em)</title>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math, math * {
+ font: 25px/1 Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <p>
+ <math>
+ <mtext>p</mtext><mo lspace="2em" rspace="1em">X</mo><mtext>p</mtext>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <mtext>p</mtext>
+ <mrow><mo lspace="2em" rspace="1em">X</mo></mrow>
+ <mtext>p</mtext>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <mtext>p</mtext>
+ <munderover>
+ <mo lspace="2em" rspace="1em">X</mo>
+ <mtext>É</mtext>
+ <mtext>É</mtext>
+ </munderover>
+ <mtext>p</mtext>
+ </math>
+ </p>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/direction/direction-007.html b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-007.html
new file mode 100644
index 0000000000..3419467ae2
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-007.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>mo and embellished mrow/munderover (lspace=1em rspace=2em)</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#embellished-operators">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#horizontally-group-sub-expressions-mrow">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+ <meta name="assert" content="Verify that the lspace/rspace on an mo or an embellished mrow/munderover element are switched in RTL mode">
+ <link rel="match" href="direction-007-ref.html">
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math, math * {
+ font: 25px/1 Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <p>
+ <math dir="rtl">
+ <mtext>p</mtext><mo lspace="1em" rspace="2em">X</mo><mtext>p</mtext>
+ </math>
+ </p>
+
+ <p>
+ <math dir="rtl">
+ <mtext>p</mtext>
+ <mrow><mo lspace="1em" rspace="2em">X</mo></mrow>
+ <mtext>p</mtext>
+ </math>
+ </p>
+
+ <p>
+ <math dir="rtl">
+ <mtext>p</mtext>
+ <munderover>
+ <mo lspace="1em" rspace="2em">X</mo>
+ <mtext>É</mtext>
+ <mtext>É</mtext>
+ </munderover>
+ <mtext>p</mtext>
+ </math>
+ </p>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_dir");</script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/direction/direction-008-ref.html b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-008-ref.html
new file mode 100644
index 0000000000..492fa9539a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-008-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>embellished mfrac (lspace=1em rspace=2em)</title>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math, math * {
+ font: 25px/1 Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <p>
+ <math>
+ <mtext>p</mtext>
+ <mfrac>
+ <mo lspace="2em" rspace="1em">X</mo>
+ <mtext>É</mtext>
+ </mfrac>
+ <mtext>p</mtext>
+ </math>
+ </p>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/direction/direction-008.html b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-008.html
new file mode 100644
index 0000000000..0be8137364
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-008.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>embellished mfrac (lspace=1em rspace=2em)</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#embellished-operators">
+ <meta name="assert" content="Verify that the lspace/rspace on an embellished mfrac element are switched in RTL mode">
+ <link rel="match" href="direction-008-ref.html">
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math, math * {
+ font: 25px/1 Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <p>
+ <math dir="rtl">
+ <mtext>p</mtext>
+ <mfrac>
+ <mo lspace="1em" rspace="2em">X</mo>
+ <mtext>É</mtext>
+ </mfrac>
+ <mtext>p</mtext>
+ </math>
+ </p>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_dir");</script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/direction/direction-010-ref.html b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-010-ref.html
new file mode 100644
index 0000000000..4f595ed49f
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-010-ref.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>dir="rtl" VS direction: rtl on math/mrow/mstyle</title>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math {
+ font: 25px/1 Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <p>
+ <math style="direction: rtl">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ <mtext>É</mtext>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <mrow style="direction: rtl">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ <mtext>É</mtext>
+ </mrow>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <mstyle mathcolor="blue" style="direction: rtl">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ <mtext>É</mtext>
+ </mstyle>
+ </math>
+ </p>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/direction/direction-010.html b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-010.html
new file mode 100644
index 0000000000..6e92dfda2a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-010.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>dir="rtl" VS direction: rtl on math/mrow/mstyle</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#horizontally-group-sub-expressions-mrow">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#style-change-mstyle">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#the-top-level-math-element">
+ <meta name="assert" content="Verify that math, mrow and mstyle with a dir=rtl attribute render the same as CSS direction right-to-left.">
+ <link rel="match" href="direction-010-ref.html">
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math {
+ font: 25px/1 Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <p>
+ <math dir="rtl">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ <mtext>É</mtext>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <mrow dir="rtl">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ <mtext>É</mtext>
+ </mrow>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <mstyle mathcolor="blue" dir="rtl">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ <mtext>É</mtext>
+ </mstyle>
+ </math>
+ </p>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_dir");</script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/direction/direction-overall-ref.html b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-overall-ref.html
new file mode 100644
index 0000000000..5ce6c5c42b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-overall-ref.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Verify dir attribute on various containers</title>
+ </head>
+ <body>
+ <p>
+ math:
+ <math>
+ <mspace width="25px" height="25px" mathbackground="blue"/>
+ <mspace width="25px" height="25px" mathbackground="green"/>
+ <mspace width="25px" height="25px" mathbackground="red"/>
+ </math>
+ </p>
+
+ <p>
+ mrow:
+ <math>
+ <mrow>
+ <mspace width="25px" height="25px" mathbackground="blue"/>
+ <mspace width="25px" height="25px" mathbackground="green"/>
+ <mspace width="25px" height="25px" mathbackground="red"/>
+ </mrow>
+ </math>
+ </p>
+
+ <p>
+ mstyle:
+ <math>
+ <mstyle>
+ <mspace width="25px" height="25px" mathbackground="blue"/>
+ <mspace width="25px" height="25px" mathbackground="green"/>
+ <mspace width="25px" height="25px" mathbackground="red"/>
+ </mstyle>
+ </math>
+ </p>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/direction/direction-overall.html b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-overall.html
new file mode 100644
index 0000000000..6effb94c54
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-overall.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Verify dir attribute on various containers</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#the-top-level-math-element">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#horizontally-group-sub-expressions-mrow">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#style-change-mstyle">
+ <meta name="assert" content="Verify dir attribute on various containers.">
+ <link rel="match" href="direction-overall-ref.html">
+ </head>
+ <body>
+
+ <!-- Test dir="rtl" on <math>, <mrow> and <mstyle> elements. The rectangle
+ inside these elements should be displayed right-to-left. -->
+
+ <p>
+ math:
+ <math dir="rtl">
+ <mspace width="25px" height="25px" mathbackground="red"/>
+ <mspace width="25px" height="25px" mathbackground="green"/>
+ <mspace width="25px" height="25px" mathbackground="blue"/>
+ </math>
+ </p>
+
+ <p>
+ mrow:
+ <math>
+ <mrow dir="rtl">
+ <mspace width="25px" height="25px" mathbackground="red"/>
+ <mspace width="25px" height="25px" mathbackground="green"/>
+ <mspace width="25px" height="25px" mathbackground="blue"/>
+ </mrow>
+ </math>
+ </p>
+
+ <p>
+ mstyle:
+ <math>
+ <mstyle dir="rtl">
+ <mspace width="25px" height="25px" mathbackground="red"/>
+ <mspace width="25px" height="25px" mathbackground="green"/>
+ <mspace width="25px" height="25px" mathbackground="blue"/>
+ </mstyle>
+ </math>
+ </p>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/direction/direction-token-ref.html b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-token-ref.html
new file mode 100644
index 0000000000..f1895b578a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-token-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html dir="rtl">
+ <head>
+ <meta charset="utf-8"/>
+ <title>Verify dir attribute on token elements</title>
+ </head>
+ <body>
+
+ <p><math><mtext style="direction: rtl;">חוק \left חסר או חוק \right מיותר</mtext></math></p>
+ <p><math><ms style="direction: rtl;">חוק \left חסר או חוק \right מיותר</ms></math></p>
+ <p><math><mo style="direction: rtl;">חוק \left חסר או חוק \right מיותר</mo></math></p>
+ <p><math><mi style="direction: rtl;">חוק \left חסר או חוק \right מיותר</mi></math></p>
+ <p><math><mn style="direction: rtl;">חוק \left חסר או חוק \right מיותר</mn></math></p>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/direction/direction-token.html b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-token.html
new file mode 100644
index 0000000000..58319fbfac
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/direction/direction-token.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html dir="rtl">
+ <head>
+ <meta charset="utf-8"/>
+ <title>Verify dir attribute on token elements</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#token-elements">
+ <meta name="assert" content="Verify dir attribute on various token elements.">
+ <link rel="match" href="direction-token-ref.html">
+ </head>
+ <body>
+
+ <!-- Test dir="rtl" on MathML token elements. The text contains RTL and
+ LTR characters, so the attribute is needed to specify the actual
+ direction. -->
+
+ <p><math><mtext dir="rtl">חוק \left חסר או חוק \right מיותר</mtext></math></p>
+ <p><math><ms dir="rtl">חוק \left חסר או חוק \right מיותר</ms></math></p>
+ <p><math><mo dir="rtl">חוק \left חסר או חוק \right מיותר</mo></math></p>
+ <p><math><mi dir="rtl">חוק \left חסר או חוק \right מיותר</mi></math></p>
+ <p><math><mn dir="rtl">חוק \left חסר או חוק \right מיותר</mn></math></p>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_dir");</script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/direction/direction.html b/testing/web-platform/tests/mathml/presentation-markup/direction/direction.html
new file mode 100644
index 0000000000..dfb1671e4c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/direction/direction.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html dir="rtl">
+<head>
+<meta charset="utf-8"/>
+<title>Verify computed direction</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-top-level-math-element">
+<meta name="assert" content="Verify computed direction value.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+ function runTests() {
+ test(function() {
+ assert_equals(window.getComputedStyle(document.getElementById('x1')).direction, "ltr");
+ assert_equals(window.getComputedStyle(document.getElementById('x2')).direction, "ltr");
+ assert_equals(window.getComputedStyle(document.getElementById('x3')).direction, "ltr");
+ assert_equals(window.getComputedStyle(document.getElementById('x4')).direction, "rtl");
+ }, "Check direction");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <!-- Test the CSS direction and dir attribute on the <math> element. It
+ should be "ltr", except if an explicit dir="rtl" is used. -->
+
+ <p>שורשי משוואה מודגשת זו <math id="x1"> <mrow> <msup> <mi>y</mi> <mn>3</mn> </msup> <mo>+</mo> <mi>p</mi> <mi>y</mi> <mo>+</mo> <mi>q</mi> <mo>=</mo> <mn>0</mn> </mrow> </math> מודגשים גם הם</p>
+
+ <p>שורשי משוואה מודגשת זו <math id="x2" dir="ltr"> <mrow> <msup> <mi>y</mi> <mn>3</mn> </msup> <mo>+</mo> <mi>p</mi> <mi>y</mi> <mo>+</mo> <mi>q</mi> <mo>=</mo> <mn>0</mn> </mrow> </math> מודגשים גם הם</p>
+
+ <p>שורשי משוואה מודגשת זו <math id="x3" dir="invalid"> <mrow> <msup> <mi>y</mi> <mn>3</mn> </msup> <mo>+</mo> <mi>p</mi> <mi>y</mi> <mo>+</mo> <mi>q</mi> <mo>=</mo> <mn>0</mn> </mrow> </math> מודגשים גם הם</p>
+
+ <p>שורשי משוואה מודגשת זו <math id="x4" dir="rtl"> <mrow> <msup> <mi>y</mi> <mn>3</mn> </msup> <mo>+</mo> <mi>p</mi> <mi>y</mi> <mo>+</mo> <mi>q</mi> <mo>=</mo> <mn>0</mn> </mrow> </math> מודגשים גם הם</p>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-1.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-1.html
new file mode 100644
index 0000000000..604e574322
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-1.html
@@ -0,0 +1,191 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Fraction</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<link rel="help" href="https://w3c.github.io/mathml-core/#fraction-with-nonzero-line-thickness">
+<link rel="help" href="https://w3c.github.io/mathml-core/#fraction-with-zero-line-thickness">
+<meta name="assert" content="Verify fraction metrics for different sizes of numerator and denominator.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ math, mspace {
+ /* OS/2.sxHeight = 800 */
+ /* post.underlineThickness == 20 */
+ font-family: Ahem;
+ font-size: 10px;
+ }
+ div.shrink-wrap {
+ background: yellow;
+ display: inline-block;
+ margin-top: 5px;
+ padding-top: 5px;
+ }
+</style>
+<script>
+ const xHeight = 800;
+ const underlineThickness = 800;
+ const emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+
+ function getBox(aId) {
+ var box = document.getElementById(aId).getBoundingClientRect();
+ box.middle = (box.bottom + box.top) / 2;
+ box.center = (box.left + box.right) / 2;
+ return box;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 4;
+ var mathAxis = getBox("baseline").top - (xHeight/2) * emToPx;
+ for (var i = 0; i <= 4; i++) {
+ var frac = getBox("frac" + i);
+ var num = getBox("frac" + i + "num");
+ var den = getBox("frac" + i + "den");
+ // To estimate the fraction axis, we calculate barycenter between the
+ // top and bottom of the fraction, using the heights of numerator and
+ // denominator as weights.
+ var fracAxis = (frac.top * den.height + frac.bottom * num.height) / (num.height + den.height);
+ assert_approx_equals(fracAxis, mathAxis, e, "frac" + i + " fraction bar");
+ }
+ }, "Fraction axis is aligned on the math axis");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ for (var i = 0; i < 10; i++) {
+ assert_less_than_equal(getBox("frac" + i + "num").bottom, getBox("frac" + i + "den").top, "numerator is above denominator");
+ assert_less_than(getBox("frac" + i + "den").top - getBox("frac" + i + "num").bottom, 5, "The gap between numerator and denominator is not too large");
+ }
+ }, "Vertical positions of numerator and denominator");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 3;
+ for (var i = 0; i < 10; i++)
+ assert_approx_equals(getBox("frac" + i + "num").center, getBox("frac" + i + "den").center, e, "numerator and denominator are horizontally centered");
+ }, "Horizontal alignments of numerator and denominator");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 5;
+ for (var i = 0; i < 10; i++) {
+ var frac = getBox("frac" + i);
+ var num = getBox("frac" + i + "num");
+ var den = getBox("frac" + i + "den");
+ assert_approx_equals(frac.height, den.bottom - num.top, e, "height of frac " + i + " is determined by the bottom/top sides of the denominator/numerator");
+ assert_approx_equals(frac.width, Math.max(num.right, den.right) - Math.min(num.left, den.left), e, "width of frac " + i + " is determined by the left/right sides of the denominator/numerator (plus some spacing)");
+ }
+ }, "Dimension of mfrac elements");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_true(MathMLFeatureDetection.has_mfrac());
+
+ Array.from(document.getElementsByClassName("shrink-wrap")).forEach((container) => {
+ var marginPx = 2; // By default fractions have 1px margin on each side.
+ var epsilon = 1;
+ var containerWidth = container.getBoundingClientRect().width;
+ var children = container.getElementsByTagName("mspace");
+ var numWidth = children[0].getBoundingClientRect().width;
+ var denWidth = children[1].getBoundingClientRect().width;
+ assert_approx_equals(containerWidth, marginPx + Math.max(numWidth, denWidth), epsilon, "Should be the maximum preferred width of numerator/denominator.");
+ });
+ }, "Preferred width of mfrac elements");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mspace id="baseline" width="1em" height="0em" depth="1em" style="background: black"/>
+ <mfrac id="frac0">
+ <mspace id="frac0num" width="15px" height="15px" style="background: blue"/>
+ <mspace id="frac0den" width="15px" height="15px" style="background: green"/>
+ </mfrac>
+ <mfrac id="frac1">
+ <mspace id="frac1num" width="30px" height="15px" style="background: blue"/>
+ <mspace id="frac1den" width="15px" height="15px" style="background: green"/>
+ </mfrac>
+ <mfrac id="frac2">
+ <mspace id="frac2num" width="15px" height="15px" style="background: blue"/>
+ <mspace id="frac2den" width="30px" height="15px" style="background: green"/>
+ </mfrac>
+ <mfrac id="frac3">
+ <mspace id="frac3num" width="15px" height="30px" style="background: blue"/>
+ <mspace id="frac3den" width="15px" height="15px" style="background: green"/>
+ </mfrac>
+ <mfrac id="frac4">
+ <mspace id="frac4num" width="15px" height="15px" style="background: blue"/>
+ <mspace id="frac4den" width="15px" height="30px" style="background: green"/>
+ </mfrac>
+ <mfrac id="frac5" linethickness="0px">
+ <mspace id="frac5num" width="15px" height="15px" style="background: blue"/>
+ <mspace id="frac5den" width="15px" height="15px" style="background: green"/>
+ </mfrac>
+ <mfrac id="frac6" linethickness="0px">
+ <mspace id="frac6num" width="30px" height="15px" style="background: blue"/>
+ <mspace id="frac6den" width="15px" height="15px" style="background: green"/>
+ </mfrac>
+ <mfrac id="frac7" linethickness="0px">
+ <mspace id="frac7num" width="15px" height="15px" style="background: blue"/>
+ <mspace id="frac7den" width="30px" height="15px" style="background: green"/>
+ </mfrac>
+ <mfrac id="frac8" linethickness="0px">
+ <mspace id="frac8num" width="15px" height="30px" style="background: blue"/>
+ <mspace id="frac8den" width="15px" height="15px" style="background: green"/>
+ </mfrac>
+ <mfrac id="frac9" linethickness="0px">
+ <mspace id="frac9num" width="15px" height="15px" style="background: blue"/>
+ <mspace id="frac9den" width="15px" height="30px" style="background: green"/>
+ </mfrac>
+ </math>
+ </p>
+ <div class="shrink-wrap">
+ <math>
+ <mfrac>
+ <mspace width="30px" height="15px" style="background: blue"/>
+ <mspace width="15px" height="15px" style="background: green"/>
+ </mfrac>
+ </math>
+ </div>
+ <div class="shrink-wrap">
+ <math>
+ <mfrac>
+ <mspace width="15px" height="15px" style="background: blue"/>
+ <mspace width="30px" height="15px" style="background: green"/>
+ </mfrac>
+ </math>
+ </div>
+ <div class="shrink-wrap">
+ <math>
+ <mfrac linethickness="0px">
+ <mspace width="30px" height="15px" style="background: blue"/>
+ <mspace width="15px" height="15px" style="background: green"/>
+ </mfrac>
+ </math>
+ </div>
+ <div class="shrink-wrap">
+ <math>
+ <mfrac linethickness="0px">
+ <mspace width="15px" height="15px" style="background: blue"/>
+ <mspace width="30px" height="15px" style="background: green"/>
+ </mfrac>
+ </math>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-001-ref.html
new file mode 100644
index 0000000000..5b7a8dff47
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-001-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>fractions bar</title>
+ <style type="text/css">
+ #container {
+ position: absolute;
+ left: 10px;
+ top: 50px;
+ width: 150px;
+ height: 150px;
+ background: green;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if you see a green square.</p>
+ <div id="container"></div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-001.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-001.html
new file mode 100644
index 0000000000..8284546e4f
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-001.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8">
+ <title>fractions bar</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <meta name="assert" content="Verifies painting of the fraction bar">
+ <link rel="match" href="frac-bar-001-ref.html">
+ <style type="text/css">
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/fraction-rulethickness10000.woff");
+ }
+ math {
+ /* FractionRuleThickness = 10000 * 1 / 1000 = 10px; */
+ /* The gap / shift / axisheight parameters are set to 0. */
+ font-family: "TestFont";
+ font-size: 1px;
+ }
+ #container {
+ position: absolute;
+ left: 0;
+ top: 0;
+ }
+ </style>
+ <script src="/common/reftest-wait.js"></script>
+ <script src="/mathml/support/fonts.js"></script>
+ <script>
+ window.addEventListener("load", () => { loadAllFonts().then(adjustPositionOfFraction); });
+
+ function adjustPositionOfFraction()
+ {
+ requestAnimationFrame(() => {
+ var container = document.getElementById("container");
+ var numeratorBox = document.getElementById("numerator").getBoundingClientRect();
+ container.style.left = (10 - numeratorBox.left) + "px";
+ container.style.top = (50 - numeratorBox.top) + "px";
+ requestAnimationFrame(takeScreenshot);
+ });
+ }
+ </script>
+ </head>
+ <body>
+ <p>This test passes if you see a green square.</p>
+ <div id="container">
+ <math>
+ <mfrac style="color: green; font-size: 15em">
+ <mspace id="numerator" width="150px"></mspace>
+ <mspace></mspace>
+ </mfrac>
+ </math>
+ </div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-002-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-002-ref.html
new file mode 100644
index 0000000000..9d5eef896a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-002-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>fractions bar</title>
+ <style type="text/css">
+ #green {
+ position: absolute;
+ background: green;
+ width: 150px;
+ height: 150px;
+ left: 50px;
+ top: 50px;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if you see a green <strong>square</strong> and no red.</p>
+ <div>
+ <div id="green"></div>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-002.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-002.html
new file mode 100644
index 0000000000..3eb5433e82
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-002.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8">
+ <title>fractions bar</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <meta name="assert" content="Verify painting of the fraction bar when margin/padding/border are involved.">
+ <link rel="match" href="frac-bar-002-ref.html">
+ <style type="text/css">
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/fraction-rulethickness10000.woff");
+ }
+ math {
+ /* FractionRuleThickness = 10000 * 1 / 1000 = 10px; */
+ /* The gap / shift / axisheight parameters are set to 0. */
+ font-family: "TestFont";
+ font-size: 1px;
+ }
+ #container {
+ position: absolute;
+ left: 0;
+ top: 0;
+ }
+ #red {
+ position: absolute;
+ background: red;
+ margin: 1px;
+ width: 148px;
+ height: 148px;
+ }
+ </style>
+ <script src="/mathml/support/fonts.js"></script>
+ <script src="/common/reftest-wait.js"></script>
+ <script>
+ window.addEventListener("load", () => { loadAllFonts().then(adjustPositionOfFraction); });
+
+ function adjustPositionOfFraction()
+ {
+ requestAnimationFrame(() => {
+ var container = document.getElementById("container");
+ var red = document.getElementById("red");
+ var numeratorBox = document.getElementById("numerator").getBoundingClientRect();
+ const shift = 50;
+ const numeratorMargin = 20;
+
+ /* Move the red square at the expected position,
+ with a 1px gap to avoid antialiasing issues. */
+ red.style.left = `${shift}px`;
+ red.style.top = `${shift}px`;
+
+ /* Move the fraction bar at the expected position. */
+ container.style.left = (shift - numeratorBox.left + numeratorMargin) + "px";
+ container.style.top = (shift - numeratorBox.bottom - numeratorMargin) + "px";
+ requestAnimationFrame(takeScreenshot);
+ });
+ }
+ </script>
+ </head>
+ <body>
+ <p>This test passes if you see a green <strong>square</strong> and no red.</p>
+ <div>
+ <div id="red"></div>
+ <div id="container">
+ <math>
+ <!-- border, padding and margin should not affect the width of the fraction bar. -->
+ <mfrac style="color: green; font-size: 15em;
+ border: 30px solid transparent;
+ padding: 60px; margin: 120px;
+ ">
+ <!-- the bar width is the one of the numerator margin box i.e. 80 + 2 * (5 + 10 + 20) = 150px -->
+ <mspace id="numerator" width="80px"
+ style="border: 5px solid transparent;
+ padding: 10px; margin: 20px;"></mspace>
+ <mspace></mspace>
+ </mfrac>
+ </math>
+ </div>
+ </div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-003-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-003-ref.html
new file mode 100644
index 0000000000..6bb6370d6e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-003-ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>fractions bar (reference)</title>
+ <style type="text/css">
+ #container {
+ position: absolute;
+ left: 10px;
+ top: 50px;
+ width: 150px;
+ height: 150px;
+ background: green;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if you see a green square.</p>
+ <div id="container"></div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-003.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-003.html
new file mode 100644
index 0000000000..69b45ea29c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-bar-003.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>fractions bar</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <meta name="assert" content="Verifies that the fraction bar takes the full width of the mfrac element">
+ <link rel="match" href="frac-bar-003-ref.html">
+ <style type="text/css">
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/fraction-rulethickness10000.woff");
+ }
+ math {
+ /* FractionRuleThickness = 10000 * 1 / 1000 = 10px; */
+ /* The gap / shift / axisheight parameters are set to 0. */
+ font-family: "TestFont";
+ font-size: 1px;
+ }
+ #container {
+ position: absolute;
+ left: 10px;
+ top: 50px;
+ width: 150px;
+ height: 150px;
+ }
+
+ /* Revert style specified in the UA style sheet that changes box size. */
+ mfrac { padding: 0; }
+ </style>
+ <script src="/mathml/support/fonts.js"></script>
+ </head>
+ <body>
+ <p>This test passes if you see a green square.</p>
+ <div id="container">
+ <math>
+ <mfrac style="width: 150px; color: green; font-size: 15em">
+ <mspace></mspace>
+ <mspace></mspace>
+ </mfrac>
+ </math>
+ </div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-color-001-notref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-color-001-notref.html
new file mode 100644
index 0000000000..498d6277a3
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-color-001-notref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Fraction bar color</title>
+ </head>
+ <body style="font-size: 20pt;">
+ <p>This test passes if you see a fraction with a blue fraction bar.</p>
+ <math>
+ <mfrac>
+ <mspace width="200px" height="20px" style="background: black"></mspace>
+ <mspace width="200px" height="20px" style="background: black"></mspace>
+ </mfrac>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-color-001.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-color-001.html
new file mode 100644
index 0000000000..442388a6eb
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-color-001.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Fraction bar color</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+ <meta name="assert" content="The CSS color property has an effect on the fraction bar.">
+ <link rel="mismatch" href="frac-color-001-notref.html">
+ </head>
+ <body style="font-size: 20pt;">
+ <p>This test passes if you see a fraction with a blue fraction bar.</p>
+ <math>
+ <mfrac style="color: blue;">
+ <mspace width="200px" height="20px" style="background: black"></mspace>
+ <mspace width="200px" height="20px" style="background: black"></mspace>
+ </mfrac>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-color-002-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-color-002-ref.html
new file mode 100644
index 0000000000..fe2f4fa7b1
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-color-002-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>fractions color</title>
+ </head>
+ <body>
+ <p>This test passes if you see a green square and a blue square.</p>
+ <div style="background: green; width: 200px; height: 200px;">
+ </div>
+ <div style="background: blue; width: 200px; height: 200px;">
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-color-002.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-color-002.html
new file mode 100644
index 0000000000..5c87212f59
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-color-002.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>fractions color</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+ <meta name="assert" content="Verifies the color property affects the fraction bar">
+ <link rel="match" href="frac-color-002-ref.html">
+ </head>
+ <body>
+ <p>This test passes if you see a green square and a blue square.</p>
+ <div style="background: green; width: 200px; height: 200px;">
+ <math>
+ <mspace width="10px"></mspace>
+ <mfrac style="color: green">
+ <mspace width="150px" height="20px"></mspace>
+ <mspace width="150px" height="20px"></mspace>
+ </mfrac>
+ </math>
+ </div>
+ <div style="background: blue; width: 200px; height: 200px;">
+ <math>
+ <mspace width="10px"></mspace>
+ <mfrac style="color: blue">
+ <mspace width="150px" height="20px"></mspace>
+ <mspace width="150px" height="20px"></mspace>
+ </mfrac>
+ </math>
+ </div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-2-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-2-ref.html
new file mode 100644
index 0000000000..d389906112
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-2-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>mfrac created dynamically</title>
+ </head>
+ <body>
+ <p>This test passes if it renders the same as an invalid fraction with 3 children.</p>
+ <math>
+ <mfrac>
+ <mspace width="50px" height="50px" style="background: black"></mspace>
+ <mspace width="50px" height="50px" style="background: black"></mspace>
+ <mspace width="50px" height="50px" style="background: black"></mspace>
+ </mfrac>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-2.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-2.html
new file mode 100644
index 0000000000..8e9fa520ea
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-2.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>mfrac created dynamically</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript">
+<meta name="assert" content="A dynamically added mfrac should render like the equivalent markup.">
+<link rel="match" href="frac-created-dynamically-2-ref.html">
+<script>
+ window.addEventListener("load", function() {
+
+ // force initial layout so we're sure what we're testing against
+ document.documentElement.getBoundingClientRect();
+
+ var mfrac = document.createElementNS("http://www.w3.org/1998/Math/MathML","mfrac");
+ var mspace1 = document.createElementNS("http://www.w3.org/1998/Math/MathML","mspace");
+ mspace1.setAttribute("width", "50px");
+ mspace1.setAttribute("height", "50px");
+ mspace1.setAttribute("style", "background: black");
+ var mspace2 = document.createElementNS("http://www.w3.org/1998/Math/MathML","mspace");
+ mspace2.setAttribute("width", "50px");
+ mspace2.setAttribute("height", "50px");
+ mspace2.setAttribute("style", "background: black");
+ var mspace3 = document.createElementNS("http://www.w3.org/1998/Math/MathML","mspace");
+ mspace3.setAttribute("width", "50px");
+ mspace3.setAttribute("height", "50px");
+ mspace3.setAttribute("style", "background: black");
+ document.getElementsByTagName("math")[0].appendChild(mfrac);
+ mfrac.appendChild(mspace1);
+ mfrac.appendChild(mspace2);
+ mfrac.appendChild(mspace3);
+
+ document.documentElement.classList.remove('reftest-wait');
+ });
+</script>
+</head>
+<body>
+ <p>This test passes if it renders the same as an invalid fraction with 3 children.</p>
+ <math></math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-3-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-3-ref.html
new file mode 100644
index 0000000000..f8db144cfe
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-3-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>mfrac created dynamically</title>
+ </head>
+ <body>
+ <p>This test passes if you see a fraction 1/3.</p>
+ <math>
+ <mfrac>
+ <mn>1</mn>
+ <mn>3</mn>
+ </mfrac>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-3.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-3.html
new file mode 100644
index 0000000000..1f7e23bb84
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-3.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>mfrac created dynamically</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript">
+<meta name="assert" content="A dynamically added mfrac should render like the equivalent markup.">
+<link rel="match" href="frac-created-dynamically-3-ref.html">
+<script>
+ window.addEventListener("load", function() {
+
+ // force initial layout so we're sure what we're testing against
+ document.documentElement.getBoundingClientRect();
+
+ var mn3 = document.createElementNS("http://www.w3.org/1998/Math/MathML","mn");
+ mn3.appendChild(document.createTextNode("3"));
+ document.getElementsByTagName("mfrac")[0].appendChild(mn3);
+ document.getElementById("mn2").remove();
+
+ document.documentElement.classList.remove('reftest-wait');
+ });
+</script>
+</head>
+<body>
+ <p>This test passes if you see a fraction 1/3.</p>
+ <math>
+ <mfrac>
+ <mn>1</mn>
+ <mn id="mn2">2</mn>
+ </mfrac>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-ref.html
new file mode 100644
index 0000000000..e10405c572
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>mfrac created dynamically</title>
+ </head>
+ <body>
+ <p>This test passes if you see a fraction.</p>
+ <math>
+ <mfrac>
+ <mspace width="50px" height="50px" style="background: black"></mspace>
+ <mspace width="50px" height="50px" style="background: black"></mspace>
+ </mfrac>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically.html
new file mode 100644
index 0000000000..8f65e8d9cf
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-created-dynamically.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>mfrac created dynamically</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript">
+<meta name="assert" content="A dynamically added mfrac should render like the equivalent markup.">
+<link rel="match" href="frac-created-dynamically-ref.html">
+<script>
+ window.addEventListener("load", function() {
+
+ // force initial layout so we're sure what we're testing against
+ document.documentElement.getBoundingClientRect();
+
+ var mfrac = document.createElementNS("http://www.w3.org/1998/Math/MathML","mfrac");
+ var mspace1 = document.createElementNS("http://www.w3.org/1998/Math/MathML","mspace");
+ mspace1.setAttribute("width", "50px");
+ mspace1.setAttribute("height", "50px");
+ mspace1.setAttribute("style", "background: black");
+ var mspace2 = document.createElementNS("http://www.w3.org/1998/Math/MathML","mspace");
+ mspace2.setAttribute("width", "50px");
+ mspace2.setAttribute("height", "50px");
+ mspace2.setAttribute("style", "background: black");
+ mfrac.appendChild(mspace1);
+ mfrac.appendChild(mspace2);
+ document.getElementsByTagName("math")[0].appendChild(mfrac);
+
+ document.documentElement.classList.remove('reftest-wait');
+ });
+</script>
+</head>
+<body>
+ <p>This test passes if you see a fraction.</p>
+ <math></math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-default-padding-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-default-padding-ref.html
new file mode 100644
index 0000000000..93d3e0162b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-default-padding-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>fraction default padding</title>
+ </head>
+ <body>
+ <p>This test passes if you see three green squares of same size, separated by a gap of one pixel.</p>
+ <div>
+ <math>
+ <mspace width="150px" height="75px" depth="75px" style="background: green"/>
+ <mspace width="1px"/>
+ <mspace width="150px" height="75px" depth="75px" style="background: green"/>
+ <mspace width="1px"/>
+ <mspace width="150px" height="75px" depth="75px" style="background: green"/>
+ </math>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-default-padding.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-default-padding.html
new file mode 100644
index 0000000000..30f155661a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-default-padding.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>fraction default padding</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <meta name="assert" content="Verifies 1px padding is added around each side of the fraction.">
+ <link rel="match" href="frac-default-padding-ref.html">
+ <style type="text/css">
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/fraction-rulethickness10000.woff");
+ }
+ math {
+ /* FractionRuleThickness = 10000 * 1 / 1000 = 10px; */
+ /* The gap / shift / axisheight parameters are set to 0. */
+ font-family: "TestFont";
+ font-size: 1px;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if you see three green squares of same size, separated by a gap of one pixel.</p>
+ <div>
+ <math>
+ <mspace width="150px" height="75px" depth="75px" style="background: green"/>
+ <mfrac style="color: green; font-size: 15em">
+ <mspace id="numerator" width="150px"></mspace>
+ <mspace></mspace>
+ </mfrac>
+ <mspace width="150px" height="75px" depth="75px" style="background: green"/>
+ </math>
+ </div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-2-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-2-ref.html
new file mode 100644
index 0000000000..d57c20901b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-2-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mfrac with one child</title>
+</head>
+<body>
+ <p>This test passes if you see a single rectangle.</p>
+ <math>
+ <mrow style="padding-inline-start: 1px; padding-inline-end: 1px;">
+ <mspace width="200px" height="200px" style="background: green"></mspace>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-2.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-2.html
new file mode 100644
index 0000000000..729fe813d0
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-2.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mfrac with one child</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#mfrac">
+<meta name="assert" content="An mfrac with one child should render using mrow.">
+<link rel="match" href="frac-invalid-2-ref.html">
+</head>
+<body>
+ <p>This test passes if you see a single rectangle.</p>
+ <math>
+ <mfrac>
+ <mspace width="200px" height="200px" style="background: green"></mspace>
+ </mfrac>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-3-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-3-ref.html
new file mode 100644
index 0000000000..703e4aeca0
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-3-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mfrac with three children</title>
+</head>
+<body>
+ <p>This test passes if you see a single rectangle.</p>
+ <math>
+ <mrow style="padding-inline-start: 1px; padding-inline-end: 1px;">
+ <mspace width="50px" height="200px" style="background: green"></mspace>
+ <mspace width="50px" height="200px" style="background: green"></mspace>
+ <mspace width="100px" height="200px" style="background: green"></mspace>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-3.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-3.html
new file mode 100644
index 0000000000..d56b55ef80
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-3.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mfrac with three children</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#mfrac">
+<meta name="assert" content="An mfrac with no children should render using an empty mrow.">
+<link rel="match" href="frac-invalid-3-ref.html">
+</head>
+<body>
+ <p>This test passes if you see a single rectangle.</p>
+ <math>
+ <mfrac>
+ <mspace width="50px" height="200px" style="background: green"></mspace>
+ <mspace width="50px" height="200px" style="background: green"></mspace>
+ <mspace width="100px" height="200px" style="background: green"></mspace>
+ </mfrac>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-ref.html
new file mode 100644
index 0000000000..beb3024732
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mfrac with zero children</title>
+</head>
+<body>
+ <p>This test passes if mfrac renders nothing.</p>
+ <math>
+ <mrow style="padding-inline-start: 1px; padding-inline-end: 1px;">
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid.html
new file mode 100644
index 0000000000..78e11e7e2b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-invalid.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mfrac with zero children</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#mfrac">
+<meta name="assert" content="An mfrac with no children should render using an empty mrow.">
+<link rel="match" href="frac-invalid-ref.html">
+</head>
+<body>
+ <p>This test passes if mfrac renders nothing.</p>
+ <math>
+ <mfrac>
+ </mfrac>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-legacy-bevelled-attribute.tentative-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-legacy-bevelled-attribute.tentative-ref.html
new file mode 100644
index 0000000000..f0b355c7bd
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-legacy-bevelled-attribute.tentative-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>fractions bevelled (reference)</title>
+ </head>
+ <body>
+ <p>Test passes is you see a blue rectangle <em>above</em> a green rectangle, separated by a horizontal bar.</p>
+ <p>
+ <math>
+ <mfrac>
+ <mspace width="100px" height="30px" style="background: lightblue"></mspace>
+ <mspace width="100px" height="30px" style="background: lightgreen"></mspace>
+ </mfrac>
+ </math>
+ </p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-legacy-bevelled-attribute.tentative.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-legacy-bevelled-attribute.tentative.html
new file mode 100644
index 0000000000..a98fc0f979
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-legacy-bevelled-attribute.tentative.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>fractions bevelled</title>
+ <link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.mfrac">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <link rel="help" href="https://github.com/mathml-refresh/mathml/issues/29">
+ <meta name="assert" content="Verify that the MathML3 bevelled attribute is ignored.">
+ <link rel="match" href="frac-legacy-bevelled-attribute.tentative-ref.html">
+ </head>
+ <body>
+ <p>Test passes is you see a blue rectangle <em>above</em> a green rectangle, separated by a horizontal bar.</p>
+ <p>
+ <math>
+ <mfrac bevelled="true">
+ <mspace width="100px" height="30px" style="background: lightblue"></mspace>
+ <mspace width="100px" height="30px" style="background: lightgreen"></mspace>
+ </mfrac>
+ </math>
+ </p>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>
+ MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");
+ MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-001-ref.html
new file mode 100644
index 0000000000..d4be8ea03b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-001-ref.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>fractions linethickness</title>
+ <style type="text/css">
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/fraction-rulethickness10000.woff");
+ }
+ math {
+ /* FractionRuleThickness = 10000 * 1 / 1000 = 10px; */
+ font-family: "TestFont";
+ font-size: 1px;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if you see the same fraction four times.</p>
+ <math>
+ <mfrac>
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ <mspace width="20px"/>
+ <mfrac>
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ <mspace width="20px"/>
+ <mfrac>
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ <mspace width="20px"/>
+ <mfrac>
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-001.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-001.html
new file mode 100644
index 0000000000..918d4aba6e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-001.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>fractions linethickness</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <meta name="assert" content="Verifies deprecated 'thin', 'medium', 'thick' and unitless values have no effect on the linethickness of the mfrac element">
+ <link rel="match" href="frac-linethickness-001-ref.html">
+ <style type="text/css">
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/fraction-rulethickness10000.woff");
+ }
+ math {
+ /* FractionRuleThickness = 10000 * 1 / 1000 = 10px; */
+ font-family: "TestFont";
+ font-size: 1px;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if you see the same fraction four times.</p>
+ <math>
+ <mfrac linethickness="thin">
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ <mspace width="20px"/>
+ <mfrac linethickness="medium">
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ <mspace width="20px"/>
+ <mfrac linethickness="thick">
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ <mspace width="20px"/>
+ <mfrac linethickness="5">
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-002.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-002.html
new file mode 100644
index 0000000000..bb47f18687
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-002.html
@@ -0,0 +1,131 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>fractions linethickness</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript">
+ <meta name="assert" content="Verifies fraction with positive, negative, percent and named space linethickness values.">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script src="/mathml/support/fonts.js"></script>
+ <style type="text/css">
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/fraction-rulethickness10000.woff");
+ }
+ math {
+ /* FractionRuleThickness = 10000 * 10 / 1000 = 100px; */
+ font-family: "TestFont";
+ font-size: 10px;
+ }
+ </style>
+ <script>
+ function LineThickness(aId) {
+ var mfrac = document.getElementById(aId);
+ var numBox = mfrac.firstElementChild.getBoundingClientRect();
+ var denumBox = mfrac.lastElementChild.getBoundingClientRect();
+ return denumBox.top - numBox.bottom;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ var defaultRuleThickness = 100;
+ var epsilon = 2;
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_approx_equals(LineThickness("positive"), 5.67 * 10, epsilon);
+ }, "Positive");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ /* Negative values are treated as 0 */
+ assert_approx_equals(LineThickness("negative"), 0, epsilon);
+ }, "Negative");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_approx_equals(LineThickness("percent"), defaultRuleThickness * 234 / 100, epsilon);
+ }, "Percentage");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ /* Namedspace values are invalid in MathML Core. */
+ assert_approx_equals(LineThickness("namedspace"), defaultRuleThickness, epsilon);
+ }, "Named space");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ /* Calc() expressions are invalid in MathML Core. */
+ assert_approx_equals(LineThickness("calc"), defaultRuleThickness, epsilon);
+ }, "Calc() expression");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ document.getElementById("dynamic-attach").setAttribute("linethickness", "400%");
+ document.getElementById("dynamic-modify").setAttribute("linethickness", "200%");
+ document.getElementById("dynamic-remove").removeAttribute("linethickness");
+ assert_approx_equals(LineThickness("dynamic-attach"), defaultRuleThickness * 4, epsilon, "attach");
+ assert_approx_equals(LineThickness("dynamic-modify"), defaultRuleThickness * 2, epsilon, "modify");
+ assert_approx_equals(LineThickness("dynamic-remove"), defaultRuleThickness, epsilon, "remove");
+ }, "Dynamic linethickness");
+
+ done();
+ }
+ </script>
+ </head>
+ <body>
+ <math>
+ <mfrac id="positive" linethickness="5.67em">
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ </math>
+ <math>
+ <mfrac id="negative" linethickness="-1.23em">
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ </math>
+ <math>
+ <mfrac id="percent" linethickness="234%">
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ </math>
+ <math>
+ <mfrac id="namedspace" linethickness="veryverythickmathspace">
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ </math>
+ <math>
+ <mfrac id="calc" linethickness="calc(20px)">
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ </math>
+ <math>
+ <mfrac id="dynamic-attach">
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ </math>
+ <math>
+ <mfrac id="dynamic-modify" linethickness="300%">
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ </math>
+ <math>
+ <mfrac id="dynamic-remove" linethickness="300%">
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-003-notref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-003-notref.html
new file mode 100644
index 0000000000..934d666333
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-003-notref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>fractions linethickness</title>
+ </head>
+ <body>
+ <p>This test passes if you see a fraction without fraction bar.</p>
+ <math>
+ <mfrac>
+ <mspace width="20px" height="5px" style="background: blue"></mspace>
+ <mspace width="20px" height="5px" style="background: cyan"></mspace>
+ </mfrac>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-003.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-003.html
new file mode 100644
index 0000000000..d930f058c5
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-003.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>fractions linethickness</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <meta name="assert" content="Verifies fraction with 0px bar.">
+ <link rel="mismatch" href="frac-linethickness-003-notref.html">
+ </head>
+ <body>
+ <p>This test passes if you see a fraction without fraction bar.</p>
+ <math>
+ <mfrac linethickness="0px">
+ <mspace width="20px" height="5px" style="background: blue"></mspace>
+ <mspace width="20px" height="5px" style="background: cyan"></mspace>
+ </mfrac>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-004-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-004-ref.html
new file mode 100644
index 0000000000..8014f0a895
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-004-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>fractions linethickness</title>
+ <style type="text/css">
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/fraction-rulethickness10000.woff");
+ }
+ math {
+ /* FractionRuleThickness = 10000 * 1 / 1000 = 10px; */
+ font-family: "TestFont";
+ font-size: 1px;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if you see no fraction bar.</p>
+ <math>
+ <mfrac linethickness="0px">
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-004.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-004.html
new file mode 100644
index 0000000000..bfb708c092
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-linethickness-004.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>fractions linethickness</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <meta name="assert" content="Verifies that unitless value of zero causes no fraction bar to be painted">
+ <link rel="match" href="frac-linethickness-004-ref.html">
+ <style type="text/css">
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/fraction-rulethickness10000.woff");
+ }
+ math {
+ /* FractionRuleThickness = 10000 * 1 / 1000 = 10px; */
+ font-family: "TestFont";
+ font-size: 1px;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if you see no fraction bar.</p>
+ <math>
+ <mfrac linethickness="0">
+ <mspace width="20px" height="10px" style="background: blue"></mspace>
+ <mspace width="20px" height="10px" style="background: cyan"></mspace>
+ </mfrac>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-mrow-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-mrow-001-ref.html
new file mode 100644
index 0000000000..e42cb96fe8
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-mrow-001-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Fraction mrow</title>
+ </head>
+ <body style="font-size: 20pt;">
+ <p>This test passes if you see a fraction with a blue square as numerator and a cyan square as denominator.</p>
+ <math>
+ <mfrac>
+ <mspace width="60px" height="60px" style="background: blue"></mspace>
+ <mspace width="60px" height="60px" style="background: cyan"></mspace>
+ </mfrac>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-mrow-001.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-mrow-001.html
new file mode 100644
index 0000000000..82e817e4de
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-mrow-001.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Fraction mrow</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#horizontally-group-sub-expressions-mrow">
+ <meta name="assert" content="This test that <mrow> elements can be used as numerator and denominator of fractions.">
+ <link rel="match" href="frac-mrow-001-ref.html">
+ </head>
+ <body style="font-size: 20pt;">
+ <p>This test passes if you see a fraction with a blue square as numerator and a cyan square as denominator.</p>
+ <math>
+ <mfrac>
+ <mrow>
+ <mspace width="30px" height="60px" style="background: blue"></mspace>
+ <mspace width="30px" height="60px" style="background: blue "></mspace>
+ </mrow>
+ <mrow>
+ <mspace width="30px" height="60px" style="background: cyan"></mspace>
+ <mspace width="30px" height="60px" style="background: cyan "></mspace>
+ </mrow>
+ </mfrac>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-numalign-denomalign-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-numalign-denomalign-001-ref.html
new file mode 100644
index 0000000000..09b83e9efb
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-numalign-denomalign-001-ref.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Fraction numalign denomalign</title>
+ </head>
+ <body>
+ <p>This test passes if you see 6 fractions with numerators and
+ denominators horizontally centered.</p>
+ <p>
+ <math>
+ <mfrac>
+ <mrow>
+ <mspace width="10px" height="20px"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ <mspace width="10px" height="20px"></mspace>
+ </mrow>
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ </mfrac>
+ </math>
+ <math>
+ <mfrac>
+ <mrow>
+ <mspace width="10px" height="20px"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ <mspace width="10px" height="20px"></mspace>
+ </mrow>
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ </mfrac>
+ </math>
+ <math>
+ <mfrac>
+ <mrow>
+ <mspace width="10px" height="20px"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ <mspace width="10px" height="20px"></mspace>
+ </mrow>
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ </mfrac>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mfrac>
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mrow>
+ <mspace width="10px" height="20px"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ <mspace width="10px" height="20px"></mspace>
+ </mrow>
+ </mfrac>
+ </math>
+ <math>
+ <mfrac>
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mrow>
+ <mspace width="10px" height="20px"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ <mspace width="10px" height="20px"></mspace>
+ </mrow>
+ </mfrac>
+ </math>
+ <math>
+ <mfrac>
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mrow>
+ <mspace width="10px" height="20px"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ <mspace width="10px" height="20px"></mspace>
+ </mrow>
+ </mfrac>
+ </math>
+ </p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-numalign-denomalign-001.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-numalign-denomalign-001.html
new file mode 100644
index 0000000000..653962f33d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-numalign-denomalign-001.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Fraction numalign denomalign</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <meta name="assert" content="Check that legacy numalign/denomalign attributes are ignored.">
+ <link rel="match" href="frac-numalign-denomalign-001-ref.html">
+ </head>
+ <body>
+ <p>This test passes if you see 6 fractions with numerators and
+ denominators horizontally centered.</p>
+ <p>
+ <math>
+ <mfrac numalign="left">
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ </mfrac>
+ </math>
+ <math>
+ <mfrac numalign="center">
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ </mfrac>
+ </math>
+ <math>
+ <mfrac numalign="right">
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ </mfrac>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mfrac denomalign="left">
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ </mfrac>
+ </math>
+ <math>
+ <mfrac denomalign="center">
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ </mfrac>
+ </math>
+ <math>
+ <mfrac denomalign="right">
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ </mfrac>
+ </math>
+ </p>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-1.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-1.html
new file mode 100644
index 0000000000..3c5e35159e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-1.html
@@ -0,0 +1,440 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Fraction parameters</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<meta name="assert" content="Element mfrac correctly uses the fraction parameters from the MATH table.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math, mspace {
+ font-size: 10px;
+ }
+ @font-face {
+ font-family: axisheight7000-rulethickness1000;
+ src: url("/fonts/math/fraction-axisheight7000-rulethickness1000.woff");
+ }
+ @font-face {
+ font-family: denominatordisplaystylegapmin5000-rulethickness1000;
+ src: url("/fonts/math/fraction-denominatordisplaystylegapmin5000-rulethickness1000.woff");
+ }
+ @font-face {
+ font-family: denominatordisplaystyleshiftdown6000-axisheight1000-rulethickness1000;
+ src: url("/fonts/math/fraction-denominatordisplaystyleshiftdown6000-axisheight1000-rulethickness1000.woff");
+ }
+ @font-face {
+ font-family: denominatorgapmin4000-rulethickness1000;
+ src: url("/fonts/math/fraction-denominatorgapmin4000-rulethickness1000.woff");
+ }
+ @font-face {
+ font-family: denominatorshiftdown3000-axisheight1000-rulethickness1000;
+ src: url("/fonts/math/fraction-denominatorshiftdown3000-axisheight1000-rulethickness1000.woff");
+ }
+ @font-face {
+ font-family: numeratordisplaystylegapmin8000-rulethickness1000;
+ src: url("/fonts/math/fraction-numeratordisplaystylegapmin8000-rulethickness1000.woff");
+ }
+ @font-face {
+ font-family: numeratordisplaystyleshiftup2000-axisheight1000-rulethickness1000;
+ src: url("/fonts/math/fraction-numeratordisplaystyleshiftup2000-axisheight1000-rulethickness1000.woff");
+ }
+ @font-face {
+ font-family: numeratorgapmin9000-rulethickness1000;
+ src: url("/fonts/math/fraction-numeratorgapmin9000-rulethickness1000.woff");
+ }
+ @font-face {
+ font-family: numeratorshiftup11000-axisheight1000-rulethickness1000;
+ src: url("/fonts/math/fraction-numeratorshiftup11000-axisheight1000-rulethickness1000.woff");
+ }
+ @font-face {
+ font-family: rulethickness10000;
+ src: url("/fonts/math/fraction-rulethickness10000.woff");
+ }
+</style>
+<script>
+ var emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+ var epsilon = 1;
+
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 7000 * emToPx;
+ var v2 = 1000 * emToPx;
+ assert_approx_equals(getBox("ref0001").top - getBox("num0001").bottom,
+ v1 + v2 / 2, epsilon, "mfrac: axis height");
+ }, "AxisHeight");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 5000 * emToPx;
+ assert_approx_equals(getBox("den0002").top - getBox("ref0002").bottom,
+ v1, epsilon, "mfrac: denominator gap");
+ }, "DenominatorDisplayStyleGapMin");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 6000 * emToPx;
+ assert_approx_equals(getBox("den0003").top - getBox("ref0003").bottom,
+ v1, epsilon, "mfrac: denominator shift");
+ }, "DenominatorDisplayStyleShiftDown");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 5000 * emToPx;
+ assert_approx_equals(getBox("den0002b").top - getBox("ref0002b").bottom,
+ v1, epsilon, "mfrac: denominator gap");
+ }, "DenominatorDisplayStyleGapMin Displaystyle");
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var v1 = 6000 * emToPx;
+ assert_approx_equals(getBox("den0003b").top - getBox("ref0003b").bottom,
+ v1, epsilon, "mfrac: denominator shift");
+ }, "DenominatorDisplayStyleShiftDown Displaystyle");
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var v1 = 5000 * emToPx;
+ assert_approx_equals(getBox("den0002c").top - getBox("ref0002c").bottom,
+ v1, epsilon, "mfrac: denominator gap");
+ }, "DenominatorDisplayStyleGapMin Displaystyle on fraction");
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var v1 = 6000 * emToPx;
+ assert_approx_equals(getBox("den0003c").top - getBox("ref0003c").bottom,
+ v1, epsilon, "mfrac: denominator shift");
+ }, "DenominatorDisplayStyleShiftDown Displaystyle on fraction");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var v1 = 4000 * emToPx;
+ assert_approx_equals(getBox("den0004").top - getBox("ref0004").bottom,
+ v1, epsilon, "mfrac: denominator gap");
+ }, "DenominatorGapMin");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 3000 * emToPx;
+ assert_approx_equals(getBox("den0005").top - getBox("ref0005").bottom,
+ v1, epsilon, "mfrac: denominator shift");
+ }, "DenominatorShiftDown");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var v1 = 4000 * emToPx;
+ assert_approx_equals(getBox("den0004b").top - getBox("ref0004b").bottom,
+ v1, epsilon, "mfrac: denominator gap");
+ }, "DenominatorGapMin Displaystyle on fraction");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 3000 * emToPx;
+ assert_approx_equals(getBox("den0005b").top - getBox("ref0005b").bottom,
+ v1, epsilon, "mfrac: denominator shift");
+ }, "DenominatorShiftDown Displaystyle on fraction");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 8000 * emToPx;
+ assert_approx_equals(getBox("ref0006").top - getBox("num0006").bottom,
+ v1, epsilon, "mfrac: numerator gap");
+ }, "NumeratorDisplayStyleGapMin");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 2000 * emToPx;
+ assert_approx_equals(getBox("ref0007").top - getBox("num0007").bottom,
+ v1, epsilon, "mfrac: numerator shift");
+ }, "NumeratorDisplayStyleShiftDown");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 8000 * emToPx;
+ assert_approx_equals(getBox("ref0006b").top - getBox("num0006b").bottom,
+ v1, epsilon, "mfrac: numerator gap");
+ }, "NumeratorDisplayStyleGapMin Displaystyle");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 2000 * emToPx;
+ assert_approx_equals(getBox("ref0007b").top - getBox("num0007b").bottom,
+ v1, epsilon, "mfrac: numerator shift");
+ }, "NumeratorDisplayStyleShiftDown Displaystyle");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 8000 * emToPx;
+ assert_approx_equals(getBox("ref0006c").top - getBox("num0006c").bottom,
+ v1, epsilon, "mfrac: numerator gap");
+ }, "NumeratorDisplayStyleGapMin Displaystyle on fraction");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 2000 * emToPx;
+ assert_approx_equals(getBox("ref0007c").top - getBox("num0007c").bottom,
+ v1, epsilon, "mfrac: numerator shift");
+ }, "NumeratorDisplayStyleShiftDown Displaystyle on fraction");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 9000 * emToPx;
+ assert_approx_equals(getBox("ref0008").top - getBox("num0008").bottom,
+ v1, epsilon, "mfrac: numerator gap");
+ }, "NumeratorGapMin");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 11000 * emToPx;
+ assert_approx_equals(getBox("ref0009").top - getBox("num0009").bottom,
+ v1, epsilon, "mfrac: numerator shift");
+ }, "NumeratorShiftDown");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 10000 * emToPx;
+ assert_approx_equals(getBox("den0010").top - getBox("num0010").bottom,
+ v1, epsilon, "mfrac: rule thickness");
+ }, "FractionRuleThickness");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math style="font-family: axisheight7000-rulethickness1000;">
+ <mspace id="ref0001" depth="1em" width="3em" style="background: green"/>
+ <mfrac>
+ <mspace width="3em" height="1em" id="num0001" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math display="block" style="font-family: denominatordisplaystylegapmin5000-rulethickness1000;">
+ <mspace id="ref0002" width="3em"
+ height=".5em" depth=".5em" style="background: green"/>
+ <mfrac>
+ <mspace width="3em"/>
+ <mspace width="3em" height="1em" id="den0002" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math display="block" style="font-family: denominatordisplaystyleshiftdown6000-axisheight1000-rulethickness1000;">
+ <mspace id="ref0003" width="3em" height="1em" style="background: green"/>
+ <mfrac>
+ <mspace width="3em"/>
+ <mspace width="3em" depth="1em" id="den0003" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math displaystyle="true" style="font-family: denominatordisplaystylegapmin5000-rulethickness1000;">
+ <mspace id="ref0002b" width="3em"
+ height=".5em" depth=".5em" style="background: green"/>
+ <mfrac>
+ <mspace width="3em"/>
+ <mspace width="3em" height="1em" id="den0002b" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math displaystyle="true" style="font-family: denominatordisplaystyleshiftdown6000-axisheight1000-rulethickness1000;">
+ <mspace id="ref0003b" width="3em" height="1em" style="background: green"/>
+ <mfrac>
+ <mspace width="3em"/>
+ <mspace width="3em" depth="1em" id="den0003b" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: denominatordisplaystylegapmin5000-rulethickness1000;">
+ <mspace id="ref0002c" width="3em"
+ height=".5em" depth=".5em" style="background: green"/>
+ <mfrac displaystyle="true">
+ <mspace width="3em"/>
+ <mspace width="3em" height="1em" id="den0002c" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: denominatordisplaystyleshiftdown6000-axisheight1000-rulethickness1000;">
+ <mspace id="ref0003c" width="3em" height="1em" style="background: green"/>
+ <mfrac displaystyle="true">
+ <mspace width="3em"/>
+ <mspace width="3em" depth="1em" id="den0003c" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: denominatorgapmin4000-rulethickness1000;">
+ <mspace id="ref0004" width="3em"
+ height=".5em" depth=".5em" style="background: green"/>
+ <mfrac>
+ <mspace width="3em"/>
+ <mspace width="3em" height="1em" id="den0004" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: denominatorshiftdown3000-axisheight1000-rulethickness1000;">
+ <mspace id="ref0005" width="3em" height="1em" style="background: green"/>
+ <mfrac>
+ <mspace width="3em"/>
+ <mspace width="3em" depth="1em" id="den0005" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math displaystyle="true" style="font-family: denominatorgapmin4000-rulethickness1000;">
+ <mspace id="ref0004b" width="3em"
+ height=".5em" depth=".5em" style="background: green"/>
+ <mfrac displaystyle="false">
+ <mspace width="3em"/>
+ <mspace width="3em" height="1em" id="den0004b" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math displaystyle="true" style="font-family: denominatorshiftdown3000-axisheight1000-rulethickness1000;">
+ <mspace id="ref0005b" width="3em" height="1em" style="background: green"/>
+ <mfrac displaystyle="false">
+ <mspace width="3em"/>
+ <mspace width="3em" depth="1em" id="den0005b" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math display="block" style="font-family: numeratordisplaystylegapmin8000-rulethickness1000;">
+ <mspace id="ref0006" width="3em"
+ height=".5em" depth=".5em" style="background: green"/>
+ <mfrac>
+ <mspace width="3em" depth="1em" id="num0006" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math display="block" style="font-family: numeratordisplaystyleshiftup2000-axisheight1000-rulethickness1000;">
+ <mspace id="ref0007" width="3em"
+ depth="1em" style="background: green"/>
+ <mfrac>
+ <mspace width="3em" height="1em" id="num0007" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math displaystyle="true" style="font-family: numeratordisplaystylegapmin8000-rulethickness1000;">
+ <mspace id="ref0006b" width="3em"
+ height=".5em" depth=".5em" style="background: green"/>
+ <mfrac>
+ <mspace width="3em" depth="1em" id="num0006b" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math displaystyle="true" style="font-family: numeratordisplaystyleshiftup2000-axisheight1000-rulethickness1000;">
+ <mspace id="ref0007b" width="3em"
+ depth="1em" style="background: green"/>
+ <mfrac>
+ <mspace width="3em" height="1em" id="num0007b" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: numeratordisplaystylegapmin8000-rulethickness1000;">
+ <mspace id="ref0006c" width="3em"
+ height=".5em" depth=".5em" style="background: green"/>
+ <mfrac displaystyle="true">
+ <mspace width="3em" depth="1em" id="num0006c" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: numeratordisplaystyleshiftup2000-axisheight1000-rulethickness1000;">
+ <mspace id="ref0007c" width="3em"
+ depth="1em" style="background: green"/>
+ <mfrac displaystyle="true">
+ <mspace width="3em" height="1em" id="num0007c" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: numeratorgapmin9000-rulethickness1000;">
+ <mspace id="ref0008" width="3em"
+ height=".5em" depth=".5em" style="background: green"/>
+ <mfrac>
+ <mspace width="3em" depth="1em" id="num0008" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: numeratorshiftup11000-axisheight1000-rulethickness1000;">
+ <mspace id="ref0009" width="3em"
+ depth="1em" style="background: green"/>
+ <mfrac>
+ <mspace width="3em" height="1em" id="num0009" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: rulethickness10000">
+ <mfrac>
+ <mspace width="3em" height="1em" id="num0010" style="background: blue"/>
+ <mspace width="3em" depth="1em" id="den0010" style="background: green"/>
+ </mfrac>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-2.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-2.html
new file mode 100644
index 0000000000..d09ad8272c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-2.html
@@ -0,0 +1,290 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Stack parameters</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<meta name="assert" content="Element mfrac correctly uses the stack parameters from the MATH table.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math, mspace {
+ font-size: 10px;
+ }
+ @font-face {
+ font-family: bottomdisplaystyleshiftdown5000-axisheight1000;
+ src: url("/fonts/math/stack-bottomdisplaystyleshiftdown5000-axisheight1000.woff");
+ }
+ @font-face {
+ font-family: bottomshiftdown6000-axisheight1000;
+ src: url("/fonts/math/stack-bottomshiftdown6000-axisheight1000.woff");
+ }
+ @font-face {
+ font-family: displaystylegapmin4000;
+ src: url("/fonts/math/stack-displaystylegapmin4000.woff");
+ }
+ @font-face {
+ font-family: gapmin8000;
+ src: url("/fonts/math/stack-gapmin8000.woff");
+ }
+ @font-face {
+ font-family: topdisplaystyleshiftup3000-axisheight1000;
+ src: url("/fonts/math/stack-topdisplaystyleshiftup3000-axisheight1000.woff");
+ }
+ @font-face {
+ font-family: topshiftup9000-axisheight1000;
+ src: url("/fonts/math/stack-topshiftup9000-axisheight1000.woff");
+ }
+</style>
+<script>
+ var emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+ var epsilon = 1;
+
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 5000 * emToPx;
+ assert_approx_equals(getBox("den0002").top - getBox("ref0002").bottom,
+ v, epsilon, "mfrac: denominator shift");
+ }, "BottomDisplayStyleShiftDown");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 5000 * emToPx;
+ assert_approx_equals(getBox("den0002b").top - getBox("ref0002b").bottom,
+ v, epsilon, "mfrac: denominator shift");
+ }, "BottomDisplayStyleShiftDown Displaystyle");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 5000 * emToPx;
+ assert_approx_equals(getBox("den0002c").top - getBox("ref0002c").bottom,
+ v, epsilon, "mfrac: denominator shift");
+ }, "BottomDisplayStyleShiftDown Displaystyle om fraction");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 6000 * emToPx;
+ assert_approx_equals(getBox("den0003").top - getBox("ref0003").bottom,
+ v, epsilon, "mfrac: denominator shift");
+ }, "BottomShiftDown");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 4000 * emToPx;
+ assert_approx_equals(getBox("den0004").top - getBox("num0004").bottom,
+ v, epsilon, "mfrac: gap");
+ }, "DisplayStyleGapMin");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 4000 * emToPx;
+ assert_approx_equals(getBox("den0004b").top - getBox("num0004b").bottom,
+ v, epsilon, "mfrac: gap");
+ }, "DisplayStyleGapMin Dsiplaystyle");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 4000 * emToPx;
+ assert_approx_equals(getBox("den0004c").top - getBox("num0004c").bottom,
+ v, epsilon, "mfrac: gap");
+ }, "DisplayStyleGapMin Dsiplaystyle on fraction");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 8000 * emToPx;
+ assert_approx_equals(getBox("den0005").top - getBox("num0005").bottom,
+ v, epsilon, "mfrac: gap");
+ }, "GapMin");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 3000 * emToPx;
+ assert_approx_equals(getBox("ref0006").top - getBox("num0006").bottom,
+ v, epsilon, "mfrac: numerator shift");
+ }, "TopDisplayStyleShiftUp");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 3000 * emToPx;
+ assert_approx_equals(getBox("ref0006b").top - getBox("num0006b").bottom,
+ v, epsilon, "mfrac: numerator shift");
+ }, "TopDisplayStyleShiftUp Displaystyle");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 3000 * emToPx;
+ assert_approx_equals(getBox("ref0006c").top - getBox("num0006c").bottom,
+ v, epsilon, "mfrac: numerator shift");
+ }, "TopDisplayStyleShiftUp Displaystyle on fraction");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 9000 * emToPx;
+ assert_approx_equals(getBox("ref0007").top - getBox("num0007").bottom,
+ v, epsilon, "mfrac: numerator shift");
+ }, "ToShiftUp");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 9000 * emToPx;
+ assert_approx_equals(getBox("ref0007b").top - getBox("num0007b").bottom,
+ v, epsilon, "mfrac: numerator shift");
+ }, "ToShiftUp with Displaystyle on fraction");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math display="block" style="font-family: bottomdisplaystyleshiftdown5000-axisheight1000;">
+ <mspace id="ref0002" width="3em" height="1em" style="background: green"/>
+ <mfrac linethickness="0px">
+ <mspace width="3em"/>
+ <mspace width="3em" depth="1em" id="den0002" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math displaystyle="true" style="font-family: bottomdisplaystyleshiftdown5000-axisheight1000;">
+ <mspace id="ref0002b" width="3em" height="1em" style="background: green"/>
+ <mfrac linethickness="0px">
+ <mspace width="3em"/>
+ <mspace width="3em" depth="1em" id="den0002b" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: bottomdisplaystyleshiftdown5000-axisheight1000;">
+ <mspace id="ref0002c" width="3em" height="1em" style="background: green"/>
+ <mfrac displaystyle="true" linethickness="0px">
+ <mspace width="3em"/>
+ <mspace width="3em" depth="1em" id="den0002c" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: bottomshiftdown6000-axisheight1000;">
+ <mspace id="ref0003" width="3em" height="1em" style="background: green"/>
+ <mfrac linethickness="0px">
+ <mspace width="3em"/>
+ <mspace width="3em" depth="1em" id="den0003" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math display="block" style="font-family: displaystylegapmin4000;">
+ <mfrac linethickness="0px">
+ <mspace width="3em" height="1em" id="num0004" style="background: blue"/>
+ <mspace width="3em" depth="1em" id="den0004" style="background: green"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math displaystyle="true" style="font-family: displaystylegapmin4000;">
+ <mfrac linethickness="0px">
+ <mspace width="3em" height="1em" id="num0004b" style="background: blue"/>
+ <mspace width="3em" depth="1em" id="den0004b" style="background: green"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: displaystylegapmin4000;">
+ <mfrac displaystyle="true" linethickness="0px">
+ <mspace width="3em" height="1em" id="num0004c" style="background: blue"/>
+ <mspace width="3em" depth="1em" id="den0004c" style="background: green"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: gapmin8000;">
+ <mfrac linethickness="0px">
+ <mspace width="3em" height="1em" id="num0005" style="background: blue"/>
+ <mspace width="3em" depth="1em" id="den0005" style="background: green"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math display="block" style="font-family: topdisplaystyleshiftup3000-axisheight1000;">
+ <mspace id="ref0006" width="3em" depth="1em" style="background: green"/>
+ <mfrac linethickness="0px">
+ <mspace width="3em" height="1em" id="num0006" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math displaystyle="true" style="font-family: topdisplaystyleshiftup3000-axisheight1000;">
+ <mspace id="ref0006b" width="3em" depth="1em" style="background: green"/>
+ <mfrac linethickness="0px">
+ <mspace width="3em" height="1em" id="num0006b" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: topdisplaystyleshiftup3000-axisheight1000;">
+ <mspace id="ref0006c" width="3em" depth="1em" style="background: green"/>
+ <mfrac displaystyle="true" linethickness="0px">
+ <mspace width="3em" height="1em" id="num0006c" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: topshiftup9000-axisheight1000;">
+ <mspace id="ref0007" width="3em" depth="1em" style="background: green"/>
+ <mfrac linethickness="0px">
+ <mspace width="3em" height="1em" id="num0007" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math displaystyle="true" style="font-family: topshiftup9000-axisheight1000;">
+ <mspace id="ref0007b" width="3em" depth="1em" style="background: green"/>
+ <mfrac displaystyle="false" linethickness="0px">
+ <mspace width="3em" height="1em" id="num0007b" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-3.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-3.html
new file mode 100644
index 0000000000..ddcb9d5a69
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-3.html
@@ -0,0 +1,168 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Fraction/Stack parameters (fallback)</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<meta name="assert" content="Element mfrac correctly uses the fraction fallback parameters.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ /* Testing fallback values is tricky as we don't have a lot of flexibility to
+ make sure one parameter is not shadowed by another one. We also use the
+ Ahem font here, so can't really play with the fallback values involved. */
+ math, mspace {
+ font-size: 200px; /* Large value because underlineThickness is small */
+ }
+ math {
+ /* OS/2.sxHeight = 800 */
+ /* post.underlineThickness == 20 */
+ font-family: Ahem;
+ }
+</style>
+<script>
+ const emToPx = 200 / 1000; // font-size: 200px, font.em = 1000
+ const epsilon = 1;
+ const xHeight = 800;
+ const underlineThickness = 20;
+
+ // NB: This test assumes the fallback shifts are all equal to zero.
+ const axisHeight = xHeight / 2;
+ const fractionRuleThickness = underlineThickness;
+ const fractionNumeratorGapMin = underlineThickness;
+ const fractionDenominatorGapMin = underlineThickness;
+ const fractionNumeratorDisplayStyleGapMin = 3 * underlineThickness;
+ const fractionDenominatorDisplayStyleGapMin = 3 * underlineThickness;
+ const stackGapMin = 3 * underlineThickness;
+ const stackDisplayStyleGapMin = 7 * underlineThickness;
+
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_approx_equals(axisHeight * emToPx,
+ (getBox("ref0001").top -
+ getBox("num0001").bottom) -
+ (fractionRuleThickness/2 +
+ fractionNumeratorGapMin) * emToPx,
+ epsilon);
+ assert_approx_equals((getBox("den0002").top -
+ getBox("num0002").bottom),
+ (fractionNumeratorGapMin +
+ fractionRuleThickness +
+ fractionDenominatorGapMin) * emToPx,
+ epsilon);
+ }, "nonzero linethickness, displaystyle=false");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_approx_equals(axisHeight * emToPx,
+ (getBox("ref0003").top -
+ getBox("num0003").bottom) -
+ (fractionRuleThickness/2 +
+ fractionNumeratorDisplayStyleGapMin) * emToPx,
+ epsilon, "mfrac: thickness, axis height");
+ assert_approx_equals((getBox("den0004").top -
+ getBox("num0004").bottom),
+ (fractionNumeratorDisplayStyleGapMin +
+ fractionRuleThickness +
+ fractionDenominatorDisplayStyleGapMin) * emToPx,
+ epsilon);
+ }, "nonzero linethickness, displaystyle=true");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_approx_equals((getBox("ref1001").top -
+ getBox("num1001").bottom),
+ stackGapMin/2 * emToPx,
+ epsilon);
+ assert_approx_equals((getBox("den1001").top) -
+ getBox("ref1001").top,
+ stackGapMin/2 * emToPx,
+ epsilon);
+ }, "linethickness=0, displaystyle=false");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_approx_equals((getBox("ref1002").top -
+ getBox("num1002").bottom),
+ stackDisplayStyleGapMin/2 * emToPx,
+ epsilon);
+ assert_approx_equals((getBox("den1002").top) -
+ getBox("ref1002").top,
+ stackDisplayStyleGapMin/2 * emToPx,
+ epsilon);
+ }, "linethickness=0, displaystyle=true");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mspace id="ref0001" height="0em" depth="1em" width="1em" style="background: green"/>
+ <mfrac>
+ <mspace width="1em" height="2em" depth="0em" id="num0001" style="background: blue"/>
+ <mspace width="1em" height="0em" depth="2em" id="den0001" style="background: purple"/>
+ </mfrac>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mfrac>
+ <mspace width="1em" height="2em" depth="4em" id="num0002" style="background: blue"/>
+ <mspace width="1em" height="4em" depth="2em" id="den0002" style="background: purple"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math displaystyle="true">
+ <mspace id="ref0003" height="0em" depth="1em" width="1em" style="background: green"/>
+ <mfrac>
+ <mspace width="1em" height="2em" depth="0em" id="num0003" style="background: blue"/>
+ <mspace width="1em" height="0em" depth="2em" id="den0003" style="background: purple"/>
+ </mfrac>
+ </math>
+ </p>
+ <p>
+ <math displaystyle="true">
+ <mfrac>
+ <mspace width="1em" height="2em" depth="4em" id="num0004" style="background: blue"/>
+ <mspace width="1em" height="4em" depth="2em" id="den0004" style="background: purple"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math>
+ <mspace id="ref1001" height="0em" depth="1em" width="1em" style="background: green"/>
+ <mfrac linethickness="0">
+ <mspace width="1em" height="2em" depth="0em" id="num1001" style="background: blue"/>
+ <mspace width="1em" height="0em" depth="2em" id="den1001" style="background: purple"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math displaystyle="true">
+ <mspace id="ref1002" height="0em" depth="1em" width="1em" style="background: green"/>
+ <mfrac linethickness="0">
+ <mspace width="1em" height="2em" depth="0em" id="num1002" style="background: blue"/>
+ <mspace width="1em" height="0em" depth="2em" id="den1002" style="background: purple"/>
+ </mfrac>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-001-ref.html
new file mode 100644
index 0000000000..06fe8d8d35
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-001-ref.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>Fraction parameters</title>
+<style>
+ math, mspace {
+ font-size: 20px;
+ }
+ @font-face {
+ font-family: denominatordisplaystylegapmin5000-rulethickness1000;
+ src: url("/fonts/math/fraction-denominatordisplaystylegapmin5000-rulethickness1000.woff");
+ }
+ #reference {
+ background: green;
+ }
+ #frame {
+ position: absolute;
+ border-top: 4px solid black;
+ border-bottom: 4px solid black;
+ width: 100%;
+ }
+</style>
+<script src="/mathml/support/fonts.js"></script>
+<script>
+ function runTests() {
+ var div = document.getElementById("frame");
+ var refBox = document.getElementById("reference").getBoundingClientRect();
+ div.style.top = `${refBox.top-2}px`;
+ div.style.height = `${refBox.height-4}px`;
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+</script>
+</head>
+<body>
+ <p>
+ This test passes if the blue squares are aligned:
+ </p>
+ <p>
+ <math display="block" style="font-family: denominatordisplaystylegapmin5000-rulethickness1000;">
+ <mspace height="2em" depth="20em"/>
+ <mfrac>
+ <mspace width="3em"/>
+ <mspace id="reference" width="3em" height=".5em" depth=".5em"/>
+ </mfrac>
+ <mfrac>
+ <mspace width="3em"/>
+ <mspace width="1em" height=".5em" depth=".5em" style="background: blue"/>
+ </mfrac>
+ <mfrac>
+ <mspace width="3em"/>
+ <mspace width="1em" height="1em" style="background: blue"/>
+ </mfrac>
+ <mfrac>
+ <mspace width="3em"/>
+ <mspace width="1em" depth="1em" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <div id="frame"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-001.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-001.html
new file mode 100644
index 0000000000..ee31231145
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-001.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>Fraction parameters (display gap between bar and denominator)</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<link rel="match" href="frac-parameters-gap-001-ref.html"/>
+<meta name="assert" content="Element mfrac correctly uses the FractionDenomDisplayStyleGapMin parameter from the MATH table when denominator contains text.">
+<style>
+ math, mspace, mtext {
+ font-size: 20px;
+ }
+ mtext {
+ font-family: math-text;
+ color: blue;
+ }
+ @font-face {
+ font-family: denominatordisplaystylegapmin5000-rulethickness1000;
+ src: url("/fonts/math/fraction-denominatordisplaystylegapmin5000-rulethickness1000.woff");
+ }
+ @font-face {
+ /*
+ math-text has the following properties:
+ - typo/hhea/win metrics: 2.5em ascent and 2.5em descent.
+ - glyph A: .5em ascent and .5em descent.
+ - glyph B: 1em ascent and 0em descent.
+ - glyph C: 0em ascent and 1em descent.
+ */
+ font-family: math-text;
+ src: url("/fonts/math/math-text.woff");
+ }
+ #reference {
+ background: green;
+ }
+ #frame {
+ position: absolute;
+ border-top: 4px solid black;
+ border-bottom: 4px solid black;
+ width: 100%;
+ }
+</style>
+<script src="/mathml/support/fonts.js"></script>
+<script>
+ function runTests() {
+ var div = document.getElementById("frame");
+ var refBox = document.getElementById("reference").getBoundingClientRect();
+ div.style.top = `${refBox.top-2}px`;
+ div.style.height = `${refBox.height-4}px`;
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+</script>
+</head>
+<body>
+ <p>
+ This test passes if the blue squares are aligned:
+ </p>
+ <p>
+ <math display="block" style="font-family: denominatordisplaystylegapmin5000-rulethickness1000;">
+ <!-- This is a dummy mspace element to ensure that the font ascent/descent does not affect the size of the math element. -->
+ <mspace height="2em" depth="20em"/>
+ <!--
+ All the fraction bars must be aligned.
+ The gap between the denominators and bar must be FractionDenomDisplayStyleGapMin.
+ The gap should be calculated using the exact bounding box of the glyphs.
+ Hence glyphs A, B, C should be rendered at the same vertical position, even if they have different ascent/descent.
+ -->
+ <mfrac>
+ <mspace width="3em"/>
+ <mspace id="reference" width="3em" height=".5em" depth=".5em"/>
+ </mfrac>
+ <mfrac>
+ <mspace width="3em"/>
+ <mtext>A</mtext>
+ </mfrac>
+ <mfrac>
+ <mspace width="3em"/>
+ <mtext>B</mtext>
+ </mfrac>
+ <mfrac>
+ <mspace width="3em"/>
+ <mtext>C</mtext>
+ </mfrac>
+ </math>
+ </p>
+ <div id="frame"></div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-002-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-002-ref.html
new file mode 100644
index 0000000000..30958a6a5f
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-002-ref.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>Fraction parameters</title>
+<style>
+ math, mspace {
+ font-size: 20px;
+ }
+ @font-face {
+ font-family: denominatorgapmin4000-rulethickness1000;
+ src: url("/fonts/math/fraction-denominatorgapmin4000-rulethickness1000.woff");
+ }
+ #reference {
+ background: green;
+ }
+ #frame {
+ position: absolute;
+ border-top: 4px solid black;
+ border-bottom: 4px solid black;
+ width: 100%;
+ }
+</style>
+<script src="/mathml/support/fonts.js"></script>
+<script>
+ function runTests() {
+ var div = document.getElementById("frame");
+ var refBox = document.getElementById("reference").getBoundingClientRect();
+ div.style.top = `${refBox.top-2}px`;
+ div.style.height = `${refBox.height-4}px`;
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+</script>
+</head>
+<body>
+ <p>
+ This test passes if the blue squares are aligned:
+ </p>
+ <p>
+ <math style="font-family: denominatorgapmin4000-rulethickness1000;">
+ <mspace height="2em" depth="20em"/>
+ <mfrac>
+ <mspace width="3em"/>
+ <mspace id="reference" width="3em" height=".5em" depth=".5em"/>
+ </mfrac>
+ <mfrac>
+ <mspace width="3em"/>
+ <mspace width="1em" height=".5em" depth=".5em" style="background: blue"/>
+ </mfrac>
+ <mfrac>
+ <mspace width="3em"/>
+ <mspace width="1em" height="1em" style="background: blue"/>
+ </mfrac>
+ <mfrac>
+ <mspace width="3em"/>
+ <mspace width="1em" depth="1em" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <div id="frame"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-002.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-002.html
new file mode 100644
index 0000000000..bf77b2d910
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-002.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>Fraction parameters (inline gap between bar and denominator)</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<link rel="match" href="frac-parameters-gap-002-ref.html"/>
+<meta name="assert" content="Element mfrac correctly uses the FractionDenominatorGapMin parameter from the MATH table when denominator contains text.">
+<style>
+ math, mspace, mtext {
+ font-size: 20px;
+ }
+ mtext {
+ font-family: math-text;
+ color: blue;
+ }
+ @font-face {
+ font-family: denominatorgapmin4000-rulethickness1000;
+ src: url("/fonts/math/fraction-denominatorgapmin4000-rulethickness1000.woff");
+ }
+ @font-face {
+ /*
+ math-text has the following properties:
+ - typo/hhea/win metrics: 2.5em ascent and 2.5em descent.
+ - glyph A: .5em ascent and .5em descent.
+ - glyph B: 1em ascent and 0em descent.
+ - glyph C: 0em ascent and 1em descent.
+ */
+ font-family: math-text;
+ src: url("/fonts/math/math-text.woff");
+ }
+ #reference {
+ background: green;
+ }
+ #frame {
+ position: absolute;
+ border-top: 4px solid black;
+ border-bottom: 4px solid black;
+ width: 100%;
+ }
+</style>
+<script src="/mathml/support/fonts.js"></script>
+<script>
+ function runTests() {
+ var div = document.getElementById("frame");
+ var refBox = document.getElementById("reference").getBoundingClientRect();
+ div.style.top = `${refBox.top-2}px`;
+ div.style.height = `${refBox.height-4}px`;
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+</script>
+</head>
+<body>
+ <p>
+ This test passes if the blue squares are aligned:
+ </p>
+ <p>
+ <math style="font-family: denominatorgapmin4000-rulethickness1000;">
+ <!-- This is a dummy mspace element to ensure that the font ascent/descent does not affect the size of the math element. -->
+ <mspace height="2em" depth="20em"/>
+ <!--
+ All the fraction bars must be aligned.
+ The gap between the denominators and bar must be FractionDenominatorGapMin.
+ The gap should be calculated using the exact bounding box of the glyphs.
+ Hence glyphs A, B, C should be rendered at the same vertical position, even if they have different ascent/descent.
+ -->
+ <mfrac>
+ <mspace width="3em"/>
+ <mspace id="reference" width="3em" height=".5em" depth=".5em"/>
+ </mfrac>
+ <mfrac>
+ <mspace width="3em"/>
+ <mtext>A</mtext>
+ </mfrac>
+ <mfrac>
+ <mspace width="3em"/>
+ <mtext>B</mtext>
+ </mfrac>
+ <mfrac>
+ <mspace width="3em"/>
+ <mtext>C</mtext>
+ </mfrac>
+ </math>
+ </p>
+ <div id="frame"></div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-003-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-003-ref.html
new file mode 100644
index 0000000000..70e2ec5a88
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-003-ref.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>Fraction parameters</title>
+<style>
+ math, mspace {
+ font-size: 20px;
+ }
+ @font-face {
+ font-family: numeratordisplaystylegapmin8000-rulethickness1000;
+ src: url("/fonts/math/fraction-numeratordisplaystylegapmin8000-rulethickness1000.woff");
+ }
+ #reference {
+ background: green;
+ }
+ #frame {
+ position: absolute;
+ border-top: 4px solid black;
+ border-bottom: 4px solid black;
+ width: 100%;
+ }
+</style>
+<script src="/mathml/support/fonts.js"></script>
+<script>
+ function runTests() {
+ var div = document.getElementById("frame");
+ var refBox = document.getElementById("reference").getBoundingClientRect();
+ div.style.top = `${refBox.top-2}px`;
+ div.style.height = `${refBox.height-4}px`;
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+</script>
+</head>
+<body>
+ <p>
+ This test passes if the blue squares are aligned:
+ </p>
+ <p>
+ <math display="block" style="font-family: numeratordisplaystylegapmin8000-rulethickness1000;">
+ <mspace height="20em" depth="2em"/>
+ <mfrac>
+ <mspace id="reference" width="3em" height=".5em" depth=".5em"/>
+ <mspace width="3em"/>
+ </mfrac>
+ <mfrac>
+ <mspace width="1em" depth=".5em" height=".5em" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ <mfrac>
+ <mspace width="1em" height="1em" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ <mfrac>
+ <mspace width="1em" depth="1em" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+ <div id="frame"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-003.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-003.html
new file mode 100644
index 0000000000..c35c11ffdc
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-003.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>Fraction parameters (display gap between bar and numerator)</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<link rel="match" href="frac-parameters-gap-003-ref.html"/>
+<meta name="assert" content="Element mfrac correctly uses the FractionNumDisplayStyleGapMin parameter from the MATH table when numerator contains text.">
+<style>
+ math, mspace, mtext {
+ font-size: 20px;
+ }
+ mtext {
+ font-family: math-text;
+ color: blue;
+ }
+ @font-face {
+ font-family: numeratordisplaystylegapmin8000-rulethickness1000;
+ src: url("/fonts/math/fraction-numeratordisplaystylegapmin8000-rulethickness1000.woff");
+ }
+ @font-face {
+ /*
+ math-text has the following properties:
+ - typo/hhea/win metrics: 2.5em ascent and 2.5em descent.
+ - glyph A: .5em ascent and .5em descent.
+ - glyph B: 1em ascent and 0em descent.
+ - glyph C: 0em ascent and 1em descent.
+ */
+ font-family: math-text;
+ src: url("/fonts/math/math-text.woff");
+ }
+ #reference {
+ background: green;
+ }
+ #frame {
+ position: absolute;
+ border-top: 4px solid black;
+ border-bottom: 4px solid black;
+ width: 100%;
+ }
+</style>
+<script src="/mathml/support/fonts.js"></script>
+<script>
+ function runTests() {
+ var div = document.getElementById("frame");
+ var refBox = document.getElementById("reference").getBoundingClientRect();
+ div.style.top = `${refBox.top-2}px`;
+ div.style.height = `${refBox.height-4}px`;
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+</script>
+</head>
+<body>
+ <p>
+ This test passes if the blue squares are aligned:
+ </p>
+ <p>
+ <math display="block" style="font-family: numeratordisplaystylegapmin8000-rulethickness1000;">
+ <!-- This is a dummy mspace element to ensure that the font ascent/descent does not affect the size of the math element. -->
+ <mspace height="20em" depth="2em"/>
+ <!--
+ All the fraction bars must be aligned.
+ The gap between the numerators and bar must be FractionNumDisplayStyleGapMin.
+ The gap should be calculated using the exact bounding box of the glyphs.
+ Hence glyphs A, B, C should be rendered at the same vertical position, even if they have different ascent/descent.
+ -->
+ <mfrac>
+ <mspace id="reference" width="3em" height=".5em" depth=".5em"/>
+ <mspace width="3em"/>
+ </mfrac>
+ <mfrac>
+ <mtext>A</mtext>
+ <mspace width="3em"/>
+ </mfrac>
+ <mfrac>
+ <mtext>B</mtext>
+ <mspace width="3em"/>
+ </mfrac>
+ <mfrac>
+ <mtext>C</mtext>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+ <div id="frame"></div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-004-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-004-ref.html
new file mode 100644
index 0000000000..675d33fbcc
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-004-ref.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>Fraction parameters</title>
+<style>
+ math, mspace {
+ font-size: 20px;
+ }
+ @font-face {
+ font-family: numeratorgapmin9000-rulethickness1000;
+ src: url("/fonts/math/fraction-numeratorgapmin9000-rulethickness1000.woff");
+ }
+ #reference {
+ background: green;
+ }
+ #frame {
+ position: absolute;
+ border-top: 4px solid black;
+ border-bottom: 4px solid black;
+ width: 100%;
+ }
+</style>
+<script src="/mathml/support/fonts.js"></script>
+<script>
+ function runTests() {
+ var div = document.getElementById("frame");
+ var refBox = document.getElementById("reference").getBoundingClientRect();
+ div.style.top = `${refBox.top-2}px`;
+ div.style.height = `${refBox.height-4}px`;
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+</script>
+</head>
+<body>
+ <p>
+ This test passes if the blue squares are aligned:
+ </p>
+ <p>
+ <math style="font-family: numeratorgapmin9000-rulethickness1000;">
+ <mspace height="20em" depth="2em"/>
+ <mfrac>
+ <mspace id="reference" width="3em" height=".5em" depth=".5em"/>
+ <mspace width="3em"/>
+ </mfrac>
+ <mfrac>
+ <mspace width="1em" height=".5em" depth=".5em" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ <mfrac>
+ <mspace width="1em" height="1em" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ <mfrac>
+ <mspace width="1em" depth="1em" style="background: blue"/>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+ <div id="frame"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-004.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-004.html
new file mode 100644
index 0000000000..6d567d02d9
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-004.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>Fraction parameters (inline gap between bar and numerator)</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<link rel="match" href="frac-parameters-gap-004-ref.html"/>
+<meta name="assert" content="Element mfrac correctly uses the FractionNumeratorGapMin parameter from the MATH table when numerator contains text.">
+<style>
+ math, mspace, mtext {
+ font-size: 20px;
+ }
+ mtext {
+ font-family: math-text;
+ color: blue;
+ }
+ @font-face {
+ font-family: numeratorgapmin9000-rulethickness1000;
+ src: url("/fonts/math/fraction-numeratorgapmin9000-rulethickness1000.woff");
+ }
+ @font-face {
+ /*
+ math-text has the following properties:
+ - typo/hhea/win metrics: 2.5em ascent and 2.5em descent.
+ - glyph A: .5em ascent and .5em descent.
+ - glyph B: 1em ascent and 0em descent.
+ - glyph C: 0em ascent and 1em descent.
+ */
+ font-family: math-text;
+ src: url("/fonts/math/math-text.woff");
+ }
+ #reference {
+ background: green;
+ }
+ #frame {
+ position: absolute;
+ border-top: 4px solid black;
+ border-bottom: 4px solid black;
+ width: 100%;
+ }
+</style>
+<script src="/mathml/support/fonts.js"></script>
+<script>
+ function runTests() {
+ var div = document.getElementById("frame");
+ var refBox = document.getElementById("reference").getBoundingClientRect();
+ div.style.top = `${refBox.top-2}px`;
+ div.style.height = `${refBox.height-4}px`;
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+</script>
+</head>
+<body>
+ <p>
+ This test passes if the blue squares are aligned:
+ </p>
+ <p>
+ <math style="font-family: numeratorgapmin9000-rulethickness1000;">
+ <!-- This is a dummy mspace element to ensure that the font ascent/descent does not affect the size of the math element. -->
+ <mspace height="20em" depth="2em"/>
+ <!--
+ All the fraction bars must be aligned.
+ The gap between the numerators and bar must be FractionNumeratorGapMin.
+ The gap should be calculated using the exact bounding box of the glyphs.
+ Hence glyphs A, B, C should be rendered at the same vertical position, even if they have different ascent/descent.
+ -->
+ <mfrac>
+ <mspace id="reference" width="3em" height=".5em" depth=".5em"/>
+ <mspace width="3em"/>
+ </mfrac>
+ <mfrac>
+ <mtext>A</mtext>
+ <mspace width="3em"/>
+ </mfrac>
+ <mfrac>
+ <mtext>B</mtext>
+ <mspace width="3em"/>
+ </mfrac>
+ <mfrac>
+ <mtext>C</mtext>
+ <mspace width="3em"/>
+ </mfrac>
+ </math>
+ </p>
+ <div id="frame"></div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-005-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-005-ref.html
new file mode 100644
index 0000000000..c794a50047
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-005-ref.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>Fraction parameters</title>
+<style>
+ math, mspace {
+ font-size: 20px;
+ }
+ @font-face {
+ font-family: displaystylegapmin4000;
+ src: url("/fonts/math/stack-displaystylegapmin4000.woff");
+ }
+ #reference {
+ background: green;
+ }
+ #frame {
+ position: absolute;
+ border-top: 4px solid black;
+ border-bottom: 4px solid black;
+ width: 100%;
+ }
+</style>
+<script src="/mathml/support/fonts.js"></script>
+<script>
+ function runTests() {
+ var div = document.getElementById("frame");
+ var refBox = document.getElementById("reference").getBoundingClientRect();
+ div.style.top = `${refBox.top-2}px`;
+ div.style.height = `${refBox.height-4}px`;
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+</script>
+</head>
+<body>
+ <p>
+ This test passes if the blue squares are aligned:
+ </p>
+ <p>
+ <math display="block" style="font-family: displaystylegapmin4000">
+ <mspace height="10em" depth="10em"/>
+ <mfrac linethickness="0px">
+ <mspace width="3em" depth="1em"/>
+ <mspace id="reference" width="3em" height=".5em" depth=".5em"/>
+ </mfrac>
+ <mfrac linethickness="0px">
+ <mspace width="3em" depth="1em"/>
+ <mspace width="1em" height=".5em" depth=".5em" style="background: blue"/>
+ </mfrac>
+ <mfrac linethickness="0px">
+ <mspace width="3em" depth="1.5em"/>
+ <mspace width="1em" height="1em" style="background: blue"/>
+ </mfrac>
+ <mfrac linethickness="0px">
+ <mspace width="3em" depth=".5em"/>
+ <mspace width="1em" depth="1em" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <div id="frame"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-005.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-005.html
new file mode 100644
index 0000000000..a0aa13e679
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-005.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>Stack parameters (display gap between numerator and denominator)</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<link rel="match" href="frac-parameters-gap-005-ref.html"/>
+<meta name="assert" content="Element mfrac with zero linethickness correctly uses the StackDisplayStyleGapMin parameter from the MATH table when denominator contains text.">
+<style>
+ math, mspace, mtext {
+ font-size: 20px;
+ }
+ mtext {
+ font-family: math-text;
+ color: blue;
+ }
+ @font-face {
+ font-family: displaystylegapmin4000;
+ src: url("/fonts/math/stack-displaystylegapmin4000.woff");
+ }
+ @font-face {
+ /*
+ math-text has the following properties:
+ - typo/hhea/win metrics: 2.5em ascent and 2.5em descent.
+ - glyph A: .5em ascent and .5em descent.
+ - glyph B: 1em ascent and 0em descent.
+ - glyph C: 0em ascent and 1em descent.
+ */
+ font-family: math-text;
+ src: url("/fonts/math/math-text.woff");
+ }
+ #reference {
+ background: green;
+ }
+ #frame {
+ position: absolute;
+ border-top: 4px solid black;
+ border-bottom: 4px solid black;
+ width: 100%;
+ }
+</style>
+<script src="/mathml/support/fonts.js"></script>
+<script>
+ function runTests() {
+ var div = document.getElementById("frame");
+ var refBox = document.getElementById("reference").getBoundingClientRect();
+ div.style.top = `${refBox.top-2}px`;
+ div.style.height = `${refBox.height-4}px`;
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+</script>
+</head>
+<body>
+ <p>
+ This test passes if the blue squares are aligned:
+ </p>
+ <p>
+ <math display="block" style="font-family: displaystylegapmin4000">
+ <!-- This is a dummy mspace element to ensure that the font ascent/descent does not affect the size of the math element. -->
+ <mspace height="10em" depth="10em"/>
+ <!--
+ The gap between the numerators/denominators and the math axis must StackDisplayStyleGapMin / 2.
+ The gap should be calculated using the exact bounding box of the glyphs.
+ The numerator descent is .5em + the denominator ascent.
+ Hence glyphs A, B, C should be rendered at the same vertical position, even if they have different ascent/descent.
+ -->
+ <mfrac linethickness="0px">
+ <mspace width="3em" depth="1em"/>
+ <mspace id="reference" width="3em" height=".5em" depth=".5em"/>
+ </mfrac>
+ <mfrac linethickness="0px">
+ <mspace width="3em" depth="1em"/>
+ <mtext>A</mtext>
+ </mfrac>
+ <mfrac linethickness="0px">
+ <mspace width="3em" depth="1.5em"/>
+ <mtext>B</mtext>
+ </mfrac>
+ <mfrac linethickness="0px">
+ <mspace width="3em" depth=".5em"/>
+ <mtext>C</mtext>
+ </mfrac>
+ </math>
+ </p>
+ <div id="frame"></div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-006-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-006-ref.html
new file mode 100644
index 0000000000..02faaad19f
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-006-ref.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>Fraction parameters</title>
+<style>
+ math, mspace {
+ font-size: 20px;
+ }
+ @font-face {
+ font-family: gapmin8000;
+ src: url("/fonts/math/stack-gapmin8000.woff");
+ }
+ #reference {
+ background: green;
+ }
+ #frame {
+ position: absolute;
+ border-top: 4px solid black;
+ border-bottom: 4px solid black;
+ width: 100%;
+ }
+</style>
+<script src="/mathml/support/fonts.js"></script>
+<script>
+ function runTests() {
+ var div = document.getElementById("frame");
+ var refBox = document.getElementById("reference").getBoundingClientRect();
+ div.style.top = `${refBox.top-2}px`;
+ div.style.height = `${refBox.height-4}px`;
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+</script>
+</head>
+<body>
+ <p>
+ This test passes if the blue squares are aligned:
+ </p>
+ <p>
+ <math style="font-family: gapmin8000">
+ <mspace height="10em" depth="10em"/>
+ <mfrac linethickness="0px">
+ <mspace width="3em" depth="1em"/>
+ <mspace id="reference" width="3em" height=".5em" depth=".5em"/>
+ </mfrac>
+ <mfrac linethickness="0px">
+ <mspace width="3em" depth="1em"/>
+ <mspace width="1em" height=".5em" depth=".5em" style="background: blue"/>
+ </mfrac>
+ <mfrac linethickness="0px">
+ <mspace width="3em" depth="1.5em"/>
+ <mspace width="1em" height="1em" style="background: blue"/>
+ </mfrac>
+ <mfrac linethickness="0px">
+ <mspace width="3em" depth=".5em"/>
+ <mspace width="1em" depth="1em" style="background: blue"/>
+ </mfrac>
+ </math>
+ </p>
+ <div id="frame"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-006.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-006.html
new file mode 100644
index 0000000000..1260126e55
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-parameters-gap-006.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>Stack parameters (display gap between numerator and denominator)</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<link rel="match" href="frac-parameters-gap-006-ref.html"/>
+<meta name="assert" content="Element mfrac with zero linethickness correctly uses the StackGapMin parameter from the MATH table when denominator contains text.">
+<style>
+ math, mspace, mtext {
+ font-size: 20px;
+ }
+ mtext {
+ font-family: math-text;
+ color: blue;
+ }
+ @font-face {
+ font-family: gapmin8000;
+ src: url("/fonts/math/stack-gapmin8000.woff");
+ }
+ @font-face {
+ /*
+ math-text has the following properties:
+ - typo/hhea/win metrics: 2.5em ascent and 2.5em descent.
+ - glyph A: .5em ascent and .5em descent.
+ - glyph B: 1em ascent and 0em descent.
+ - glyph C: 0em ascent and 1em descent.
+ */
+ font-family: math-text;
+ src: url("/fonts/math/math-text.woff");
+ }
+ #reference {
+ background: green;
+ }
+ #frame {
+ position: absolute;
+ border-top: 4px solid black;
+ border-bottom: 4px solid black;
+ width: 100%;
+ }
+</style>
+<script src="/mathml/support/fonts.js"></script>
+<script>
+ function runTests() {
+ var div = document.getElementById("frame");
+ var refBox = document.getElementById("reference").getBoundingClientRect();
+ div.style.top = `${refBox.top-2}px`;
+ div.style.height = `${refBox.height-4}px`;
+ document.documentElement.classList.remove('reftest-wait');
+ }
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+</script>
+</head>
+<body>
+ <p>
+ This test passes if the blue squares are aligned:
+ </p>
+ <p>
+ <math style="font-family: gapmin8000">
+ <!-- This is a dummy mspace element to ensure that the font ascent/descent does not affect the size of the math element. -->
+ <mspace height="10em" depth="10em"/>
+ <!--
+ The gap between the numerators/denominators and the math axis must StackGapMin / 2.
+ The gap should be calculated using the exact bounding box of the glyphs.
+ The numerator descent is .5em + the denominator ascent.
+ Hence glyphs A, B, C should be rendered at the same vertical position, even if they have different ascent/descent.
+ -->
+ <mfrac linethickness="0px">
+ <mspace width="3em" depth="1em"/>
+ <mspace id="reference" width="3em" height=".5em" depth=".5em"/>
+ </mfrac>
+ <mfrac linethickness="0px">
+ <mspace width="3em" depth="1em"/>
+ <mtext>A</mtext>
+ </mfrac>
+ <mfrac linethickness="0px">
+ <mspace width="3em" depth="1.5em"/>
+ <mtext>B</mtext>
+ </mfrac>
+ <mfrac linethickness="0px">
+ <mspace width="3em" depth=".5em"/>
+ <mtext>C</mtext>
+ </mfrac>
+ </math>
+ </p>
+ <div id="frame"></div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-rendering-from-in-flow-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-rendering-from-in-flow-ref.html
new file mode 100644
index 0000000000..71f1583fd9
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-rendering-from-in-flow-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>fraction rendering from in-flow children</title>
+ </head>
+ <body>
+ <math>
+ <mfrac>
+ <mspace width="64px" height="48px" style="background: lightblue"></mspace>
+ <mspace width="128px" height="96px" style="background: lightgreen"></mspace>
+ </mfrac>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-rendering-from-in-flow.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-rendering-from-in-flow.html
new file mode 100644
index 0000000000..b57564b574
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-rendering-from-in-flow.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>fraction rendering from in-flow children</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <meta name="assert" content="Verify rendering of fractions is only affected by in-flow children.">
+ <style>
+ .oof1 {
+ position: absolute;
+ }
+ .oof2 {
+ position: fixed;
+ }
+ .nobox {
+ display: none;
+ }
+ </style>
+ <link rel="match" href="frac-rendering-from-in-flow-ref.html">
+ </head>
+ <body>
+ <math>
+ <mfrac>
+ <mspace height="32px" width="24px" class="oof1"/>
+ <mspace height="16px" width="12px" class="oof2"/>
+ <mspace height="8px" width="4px" class="nobox"/>
+ <mspace width="64px" height="48px" style="background: lightblue"></mspace>
+ <mspace height="32px" width="24px" class="oof1"/>
+ <mspace height="16px" width="12px" class="oof2"/>
+ <mspace height="8px" width="4px" class="nobox"/>
+ <mspace width="128px" height="96px" style="background: lightgreen"></mspace>
+ <mspace height="32px" width="24px" class="oof1"/>
+ <mspace height="16px" width="12px" class="oof2"/>
+ <mspace height="8px" width="4px" class="nobox"/>
+ </mfrac>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-visibility-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-visibility-001-ref.html
new file mode 100644
index 0000000000..41a262d511
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-visibility-001-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Fraction bar visibility</title>
+ </head>
+ <body>
+ <p>This test passes if you see a green square and no red.</p>
+ <div style="background: green; width: 200px; height: 200px;">
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-visibility-001.html b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-visibility-001.html
new file mode 100644
index 0000000000..29212c0594
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/fractions/frac-visibility-001.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Fraction bar visibility</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+ <meta name="assert" content="The CSS visible property affects the rendering of the fraction bar.">
+ <link rel="match" href="frac-visibility-001-ref.html">
+ </head>
+ <body>
+ <p>This test passes if you see a green square and no red.</p>
+ <div style="background: green; width: 200px; height: 200px;">
+ <math>
+ <mfrac style="visibility: hidden; color: red">
+ <mspace width="200px" height="20px"></mspace>
+ <mspace width="200px" height="20px"></mspace>
+ </mfrac>
+ </math>
+ </div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/menclose/legacy-menclose-radical-notation-ref.html b/testing/web-platform/tests/mathml/presentation-markup/menclose/legacy-menclose-radical-notation-ref.html
new file mode 100644
index 0000000000..c67ac03f5d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/menclose/legacy-menclose-radical-notation-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Legacy menclose radical notation (reference)</title>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math, math * {
+ font: 25px Ahem;
+ }
+ </style>
+ </head>
+ <body>
+ <math>
+ <menclose notation="">
+ <mn>123</mn>
+ </menclose>
+ <menclose notation="box">
+ <mn>123</mn>
+ </menclose>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/menclose/legacy-menclose-radical-notation.html b/testing/web-platform/tests/mathml/presentation-markup/menclose/legacy-menclose-radical-notation.html
new file mode 100644
index 0000000000..353202fd7b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/menclose/legacy-menclose-radical-notation.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Legacy menclose radical notation</title>
+ <link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.menclose">
+ <link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.menclose">
+ <meta name="assert" content="Verify that the legacy menclose radical notation is ignored.">
+ <link rel="match" href="legacy-menclose-radical-notation-ref.html">
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math, math * {
+ font: 25px Ahem;
+ }
+ </style>
+ </head>
+ <body>
+ <math>
+ <menclose notation="radical">
+ <mn>123</mn>
+ </menclose>
+ <menclose notation="box radical">
+ <mn>123</mn>
+ </menclose>
+ </math>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_menclose");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mpadded/legacy-orthogonal-pseudo-units.html b/testing/web-platform/tests/mathml/presentation-markup/mpadded/legacy-orthogonal-pseudo-units.html
new file mode 100644
index 0000000000..6eebac1df9
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mpadded/legacy-orthogonal-pseudo-units.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Legacy mpadded pseudo-units relying on orthogonal metrics</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#adjust-space-around-content-mpadded">
+<link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.mpadded">
+<meta name="assert" content="Legacy pseudo-units depending on orthogonal metrics">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/layout-comparison.js"></script>
+<style>
+ .testedElement {
+ background: red;
+ }
+</style>
+</head>
+<body>
+ <div id="log"></div>
+
+ <p>
+ <math>
+ <mpadded id="reference">
+ <mspace width="10px" height="20px" depth="30px"
+ style="background: blue"/>
+ </mpadded>
+ </math>
+ </p>
+
+ <p>
+ <!-- width cannot use vertical pseudo-units -->
+ <math>
+ <mpadded class="testedElement" width="200%height">
+ <mspace width="10px" height="20px" depth="30px"
+ style="background: blue"/>
+ </mpadded>
+ </math>
+ <math>
+ <mpadded class="testedElement" width="200%depth">
+ <mspace width="10px" height="20px" depth="30px"
+ style="background: blue"/>
+ </mpadded>
+ </math>
+ </p>
+
+ <p>
+ <!-- lspace cannot use vertical pseudo-units -->
+ <math>
+ <mpadded class="testedElement" lspace="200%height">
+ <mspace width="10px" height="20px" depth="30px"
+ style="background: blue"/>
+ </mpadded>
+ </math>
+ <math>
+ <mpadded class="testedElement" lspace="200%depth">
+ <mspace width="10px" height="20px" depth="30px"
+ style="background: blue"/>
+ </mpadded>
+ </math>
+ </p>
+ <p>
+ <!-- height cannot use horizontal pseudo-units -->
+ <math>
+ <mpadded class="testedElement" height="200%width">
+ <mspace width="10px" height="20px" depth="30px"
+ style="background: blue"/>
+ </mpadded>
+ </math>
+ </p>
+ <p>
+ <!-- depth cannot use horizontal pseudo-units -->
+ <math>
+ <mpadded class="testedElement" depth="200%width">
+ <mspace width="10px" height="20px" depth="30px"
+ style="background: blue"/>
+ </mpadded>
+ </math>
+ </p>
+ <p>
+ <!-- voffset cannot use horizontal pseudo-units -->
+ <math>
+ <mpadded class="testedElement" voffset="200%width">
+ <mspace width="10px" height="20px" depth="30px"
+ style="background: blue"/>
+ </mpadded>
+ </math>
+ </p>
+<script type="text/javascript">
+ Array.from(document.getElementsByClassName("testedElement")).forEach(mpadded => {
+ var reference = document.getElementById("reference");
+ const name = ["width", "depth", "height", "lspace", "voffset"].find(attr => mpadded.hasAttribute(attr));
+ const epsilon = 1;
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ compareLayout(mpadded, reference, epsilon);
+ }, `${mpadded.getAttribute(name)} is not allowed on ${name}`);
+ });
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-001.html b/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-001.html
new file mode 100644
index 0000000000..e61dc5af72
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-001.html
@@ -0,0 +1,147 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mpadded</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#adjust-space-around-content-mpadded">
+<meta name="assert" content="Verify metrics of empty mpadded element for different values of height, depth and width">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ var epsilon = 1;
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+ test(function() {
+ var none = getBox("none");
+ assert_equals(none.width, 0, "zero width");
+ assert_approx_equals(getBox("baseline").bottom - none.top, 0, epsilon, "zero depth");
+ assert_approx_equals(none.bottom - getBox("baseline").bottom, 0, epsilon, "zero depth");
+ }, "mpadded (no attributes)");
+
+ test(function() {
+ for (var i = 0; i <= 2; i++) {
+ var mpadded = getBox("width" + i);
+ assert_approx_equals(mpadded.width, 25*(i+1), epsilon, "width " + i);
+ assert_approx_equals(getBox("baseline").bottom - mpadded.top, 0, epsilon, "height" + i);
+ assert_approx_equals(mpadded.bottom - getBox("baseline").bottom, 0, epsilon, "depth" + i);
+ }
+ }, "Different widths");
+
+ test(function() {
+ for (var i = 0; i <= 2; i++) {
+ var mpadded = getBox("height" + i);
+ assert_equals(mpadded.width, 0, "width" + i);
+ assert_approx_equals(getBox("baseline").bottom - mpadded.top, 25*(i+1), epsilon, "height" + i);
+ assert_approx_equals(mpadded.bottom - getBox("baseline").bottom, 0, epsilon, "depth" + i);
+ }
+ }, "Different heights");
+
+ test(function() {
+ for (var i = 0; i <= 2; i++) {
+ var mpadded = getBox("depth" + i);
+ assert_equals(mpadded.width, 0, "width" + i);
+ assert_approx_equals(getBox("baseline").bottom - mpadded.top, 0, epsilon, "height" + i);
+ assert_approx_equals(mpadded.bottom - getBox("baseline").bottom, 25*(i+1), epsilon, "depth" + i);
+ }
+ }, "Different depths");
+
+ test(function() {
+ for (var i = 0; i <= 2; i++) {
+ var mpadded = getBox("mpadded" + i);
+ assert_approx_equals(mpadded.width, 25*(1+i%3), epsilon, "width" + i);
+ assert_approx_equals(getBox("baseline").bottom - mpadded.top, 25*(1+(i+1)%3), epsilon, "height" + i);
+ assert_approx_equals(mpadded.bottom - getBox("baseline").bottom, 25*(1+(i+2)%3), epsilon, "depth" + i);
+ }
+ }, "Various combinations of height, depth and width.");
+
+ test(function() {
+ var container = document.getElementById("containerForPreferredWidth");
+ var mpadded = container.getElementsByTagName("mpadded")[0];
+ var containerWidth = container.getBoundingClientRect().width;
+ var mpaddedWidth = mpadded.getBoundingClientRect().width;
+ assert_approx_equals(containerWidth, mpaddedWidth, epsilon);
+ }, "Preferred width");
+
+ // Dynamically set attributes.
+ ["width", "height", "depth"].forEach(function (name, index) {
+ document.getElementById("dynamic-remove").removeAttribute(name);
+ let length = `${50 + index * 10}px`;
+ document.getElementById("dynamic-attach").setAttribute(name, length);
+ document.getElementById("dynamic-modify").setAttribute(name, length);
+ });
+ let baseline = getBox("baseline2").bottom;
+
+ test(function() {
+ let remove = getBox("dynamic-remove");
+ assert_approx_equals(remove.width, 0, epsilon);
+ assert_approx_equals(remove.height, 0, epsilon);
+ assert_approx_equals(remove.top, baseline, epsilon);
+ }, "dynamic attributes (remove)");
+
+ test(function() {
+ let attach = getBox("dynamic-attach");
+ assert_approx_equals(attach.width, 50, epsilon);
+ assert_approx_equals(attach.height, 60 + 70, epsilon);
+ assert_approx_equals(baseline - attach.top, 60, epsilon);
+ }, "dynamic attributes (attach)");
+
+ test(function() {
+ let modify = getBox("dynamic-modify");
+ assert_approx_equals(modify.width, 50, epsilon);
+ assert_approx_equals(modify.height, 60 + 70, epsilon);
+ assert_approx_equals(baseline - modify.top, 60, epsilon);
+ }, "dynamic attributes (modify)");
+
+ done();
+ }
+</script>
+<style>
+div.shrink-wrap {
+ background: yellow;
+ display: inline-block;
+ margin-top: 5px;
+ padding-top: 5px;
+}
+</style>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <span id="baseline" style="display: inline-block; width: 30px; height: 5px; background: blue"></span>
+ <math>
+ <mpadded id="none"/>
+ <mpadded id="width0" width="25px"/>
+ <mpadded id="width1" width="50px"/>
+ <mpadded id="width2" width="75px"/>
+ <mpadded id="height0" height="25px"/>
+ <mpadded id="height1" height="50px"/>
+ <mpadded id="height2" height="75px"/>
+ <mpadded id="depth0" depth="25px"/>
+ <mpadded id="depth1" depth="50px"/>
+ <mpadded id="depth2" depth="75px"/>
+ <mpadded id="mpadded0" width="25px" height="50px" depth="75px" style="background: green"/>
+ <mpadded id="mpadded1" width="50px" height="75px" depth="25px" style="background: blue"/>
+ <mpadded id="mpadded2" width="75px" height="25px" depth="50px" style="background: green"/>
+ </math>
+ </p>
+ <div>
+ <div id="containerForPreferredWidth" class="shrink-wrap">
+ <math><mpadded width="75px" height="25px" depth="50px" style="background: green"/></math>
+ </div>
+ </div>
+ <p>
+ <span id="baseline2" style="display: inline-block; width: 30px; height: 5px; background: blue"></span>
+ <math>
+ <mpadded id="dynamic-attach" style="background: lightgreen"/>
+ <mpadded id="dynamic-remove" width="10px" height="20px" depth="30px" style="background: lightyellow"/>
+ <mpadded id="dynamic-modify" width="100px" height="200px" depth="300px" style="background: pink"/>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-002.html b/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-002.html
new file mode 100644
index 0000000000..93f2d594c7
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-002.html
@@ -0,0 +1,164 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mpadded</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#adjust-space-around-content-mpadded">
+<meta name="assert" content="Verify metrics of nonempty mpadded element for different values of height, depth and width">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ var epsilon = 1;
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+ const contentWidth = 100;
+ const contentDepth = 125;
+ const contentHeight = 150;
+
+ test(function() {
+ var none = getBox("none");
+ assert_equals(none.width, contentWidth, "content width");
+ assert_approx_equals(getBox("baseline").bottom - none.top, contentHeight, epsilon, "content height");
+ assert_approx_equals(none.bottom - getBox("baseline").bottom, contentDepth, epsilon, "content height");
+ }, "mpadded with no attributes");
+
+ test(function() {
+ for (var i = 0; i <= 2; i++) {
+ var mpadded = getBox("width" + i);
+ assert_approx_equals(mpadded.width, 25*(i+1), epsilon, "width " + i);
+ assert_approx_equals(getBox("baseline").bottom - mpadded.top, contentHeight, epsilon, "height" + i);
+ assert_approx_equals(mpadded.bottom - getBox("baseline").bottom, contentDepth, epsilon, "depth" + i);
+ }
+ }, "Different widths");
+
+ test(function() {
+ for (var i = 0; i <= 2; i++) {
+ var mpadded = getBox("height" + i);
+ assert_equals(mpadded.width, contentWidth, "width" + i);
+ assert_approx_equals(getBox("baseline").bottom - mpadded.top, 25*(i+1), epsilon, "height" + i);
+ assert_approx_equals(mpadded.bottom - getBox("baseline").bottom, contentDepth, epsilon, "depth" + i);
+ }
+ }, "Different heights");
+
+ test(function() {
+ var mpadded = getBox("percentages");
+ assert_equals(mpadded.width, contentWidth, "width");
+ assert_approx_equals(getBox("baseline").bottom - mpadded.top, contentHeight, epsilon, "height");
+ assert_approx_equals(mpadded.bottom - getBox("baseline").bottom, contentDepth, epsilon, "depth");
+ }, "Percentage calculation for width, height and depth");
+
+ test(function() {
+ for (var i = 0; i <= 2; i++) {
+ var mpadded = getBox("depth" + i);
+ assert_equals(mpadded.width, contentWidth, "width" + i);
+ assert_approx_equals(getBox("baseline2").bottom - mpadded.top, contentHeight, epsilon, "height" + i);
+ assert_approx_equals(mpadded.bottom - getBox("baseline2").bottom, 25*(i+1), epsilon, "depth" + i);
+ }
+ }, "Different depths");
+
+ test(function() {
+ for (var i = 0; i <= 2; i++) {
+ var mpadded = getBox("mpadded" + i);
+ assert_approx_equals(mpadded.width, 25*(1+i%3), epsilon, "width" + i);
+ assert_approx_equals(getBox("baseline2").bottom - mpadded.top, 25*(1+(i+1)%3), epsilon, "height" + i);
+ assert_approx_equals(mpadded.bottom - getBox("baseline2").bottom, 25*(1+(i+2)%3), epsilon, "depth" + i);
+ }
+ }, "Various combinations of height, depth and width.");
+
+ test(function() {
+ var container = document.getElementById("containerForPreferredWidth");
+ var mpadded = container.getElementsByTagName("mpadded")[0];
+ var containerWidth = container.getBoundingClientRect().width;
+ var mpaddedWidth = mpadded.getBoundingClientRect().width;
+ assert_approx_equals(containerWidth, mpaddedWidth, epsilon);
+ }, "Preferred width");
+
+ // Dynamically set attributes.
+ ["width", "height", "depth"].forEach(function (name, index) {
+ document.getElementById("dynamic-remove").removeAttribute(name);
+ let length = `${50 + index * 10}px`;
+ document.getElementById("dynamic-attach").setAttribute(name, length);
+ document.getElementById("dynamic-modify").setAttribute(name, length);
+ });
+ let baseline = getBox("baseline3").bottom;
+
+ test(function() {
+ let remove = getBox("dynamic-remove");
+ assert_approx_equals(remove.width, contentWidth, epsilon);
+ assert_approx_equals(remove.height, contentHeight + contentDepth, epsilon);
+ assert_approx_equals(baseline - remove.top, contentHeight, epsilon);
+ }, "dynamic attributes (remove)");
+
+ test(function() {
+ let attach = getBox("dynamic-attach");
+ assert_approx_equals(attach.width, 50, epsilon);
+ assert_approx_equals(attach.height, 60 + 70, epsilon);
+ assert_approx_equals(baseline - attach.top, 60, epsilon);
+ }, "dynamic attributes (attach)");
+
+ test(function() {
+ let modify = getBox("dynamic-modify");
+ assert_approx_equals(modify.width, 50, epsilon);
+ assert_approx_equals(modify.height, 60 + 70, epsilon);
+ assert_approx_equals(baseline - modify.top, 60, epsilon);
+ }, "dynamic attributes (modify)");
+
+ done();
+ }
+</script>
+<style>
+div.shrink-wrap {
+ background: yellow;
+ display: inline-block;
+ margin-top: 5px;
+ padding-top: 5px;
+}
+</style>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <span id="baseline" style="display: inline-block; width: 30px; height: 5px; background: blue"></span>
+ <math>
+ <mpadded id="none"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+ <mpadded id="width0" width="25px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+ <mpadded id="width1" width="50px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+ <mpadded id="width2" width="75px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+ <mpadded id="height0" height="25px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+ <mpadded id="height1" height="50px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+ <mpadded id="height2" height="75px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+ <mpadded id="percentages" width="50%" height="33%" depth="10%"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+ </math>
+ </p>
+ <p>
+ <span id="baseline2" style="display: inline-block; width: 30px; height: 5px; background: blue"></span>
+ <math>
+ <mpadded id="depth0" depth="25px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+ <mpadded id="depth1" depth="50px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+ <mpadded id="depth2" depth="75px"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+ <mpadded id="mpadded0" width="25px" height="50px" depth="75px" style="background: green"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+ <mpadded id="mpadded1" width="50px" height="75px" depth="25px" style="background: blue"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+ <mpadded id="mpadded2" width="75px" height="25px" depth="50px" style="background: green"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+ </math>
+ </p>
+ <div>
+ <div id="containerForPreferredWidth" class="shrink-wrap">
+ <math><mpadded width="75px" height="25px" depth="50px" style="background: green"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded></math>
+ </div>
+ </div>
+ <p>
+ <span id="baseline3" style="display: inline-block; width: 30px; height: 5px; background: blue"></span>
+ <math>
+ <mpadded id="dynamic-attach" style="background: lightgreen"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+ <mpadded id="dynamic-remove" width="10px" height="20px" depth="30px" style="background: lightyellow"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+ <mpadded id="dynamic-modify" width="100px" height="200px" depth="300px" style="background: pink"><mspace width="100px" depth="125px" height="150px" style="background: black; opacity: .5"/></mpadded>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-003.html b/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-003.html
new file mode 100644
index 0000000000..e0c24307f4
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-003.html
@@ -0,0 +1,230 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mpadded</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#adjust-space-around-content-mpadded">
+<meta name="assert" content="Verify metrics of mpadded element with voffset and lspace">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+ const contentWidth = 10;
+ const contentDepth = 15;
+ const contentHeight = 20;
+ const epsilon = 1;
+
+ test(function() {
+ Array.from(document.getElementsByClassName("shrink-wrap")).forEach(container => {
+ assert_approx_equals(container.getBoundingClientRect().width, contentWidth, epsilon);
+ });
+ }, "lspace/voffset shifts don't affect mpadded preferred width");
+
+ function GetShifts(mpadded) {
+ let mpadded_box = mpadded.getBoundingClientRect();
+ let mspace_box = mpadded.firstElementChild.getBoundingClientRect();
+ return { lspace: mspace_box.left - mpadded_box.left,
+ voffset: mpadded_box.top - mspace_box.top };
+ }
+
+ let mpaddeds = document.getElementById("static_tests").getElementsByTagName("mpadded");
+ test(function() {
+ let baseline = document.getElementById("baseline").getBoundingClientRect().bottom;
+ Array.from(mpaddeds).forEach(e => {
+ let mpadded = e.getBoundingClientRect();
+ assert_approx_equals(mpadded.width, contentWidth, epsilon);
+ assert_approx_equals(baseline - mpadded.top, contentHeight, epsilon);
+ assert_approx_equals(mpadded.bottom - baseline, contentDepth, epsilon);
+
+ });
+ }, "lspace/voffset shifts don't affect mpadded size");
+
+
+ test(function() {
+ let shifts = GetShifts(mpaddeds[0]);
+ assert_approx_equals(shifts.lspace, 5, epsilon, "positive lspace");
+ assert_approx_equals(shifts.voffset, 0, epsilon);
+
+ shifts = GetShifts(mpaddeds[1]);
+ assert_approx_equals(shifts.lspace, 0, epsilon, "negative lspace is clmaped to zero");
+ assert_approx_equals(shifts.voffset, 0, epsilon);
+
+ shifts = GetShifts(mpaddeds[2]);
+ assert_approx_equals(shifts.lspace, 0, epsilon, "positive lspace percentage");
+ assert_approx_equals(shifts.voffset, 0, epsilon);
+
+ shifts = GetShifts(mpaddeds[3]);
+ assert_approx_equals(shifts.lspace, 0, epsilon, "negative lspace percentage");
+ assert_approx_equals(shifts.voffset, 0, epsilon);
+
+ shifts = GetShifts(mpaddeds[4]);
+ assert_approx_equals(shifts.lspace, 0, epsilon);
+ assert_approx_equals(shifts.voffset, 10, epsilon, "positive voffset");
+
+ shifts = GetShifts(mpaddeds[5]);
+ assert_approx_equals(shifts.lspace, 0, epsilon);
+ assert_approx_equals(shifts.voffset, -10, epsilon, "negative voffset");
+
+ shifts = GetShifts(mpaddeds[6]);
+ assert_approx_equals(shifts.lspace, 0, epsilon);
+ assert_approx_equals(shifts.voffset, 0, epsilon, "positive voffset percentage");
+
+ shifts = GetShifts(mpaddeds[7]);
+ assert_approx_equals(shifts.lspace, 0, epsilon);
+ assert_approx_equals(shifts.voffset, 0, epsilon, "negative voffset percentage");
+
+ shifts = GetShifts(mpaddeds[8]);
+ assert_approx_equals(shifts.lspace, 5, epsilon);
+ assert_approx_equals(shifts.voffset, 10, epsilon);
+
+ shifts = GetShifts(mpaddeds[9]);
+ assert_approx_equals(shifts.lspace, 5, epsilon);
+ assert_approx_equals(shifts.voffset, -10, epsilon);
+ }, "content is shifted by the specified lspace/voffset");
+
+ mpaddeds = document.getElementById("static_tests_rtl").getElementsByTagName("mpadded");
+ test(function() {
+ let shifts = GetShifts(mpaddeds[0]);
+ assert_approx_equals(shifts.lspace, -5, epsilon, "positive lspace");
+ assert_approx_equals(shifts.voffset, 0, epsilon);
+
+ shifts = GetShifts(mpaddeds[1]);
+ assert_approx_equals(shifts.lspace, 0, epsilon, "negative lspace is clmaped to zero");
+ assert_approx_equals(shifts.voffset, 0, epsilon);
+
+ shifts = GetShifts(mpaddeds[2]);
+ assert_approx_equals(shifts.lspace, 0, epsilon);
+ assert_approx_equals(shifts.voffset, 10, epsilon, "positive voffset");
+
+ shifts = GetShifts(mpaddeds[3]);
+ assert_approx_equals(shifts.lspace, 0, epsilon);
+ assert_approx_equals(shifts.voffset, -10, epsilon, "negative voffset");
+
+ shifts = GetShifts(mpaddeds[4]);
+ assert_approx_equals(shifts.lspace, -5, epsilon);
+ assert_approx_equals(shifts.voffset, 10, epsilon);
+
+ shifts = GetShifts(mpaddeds[5]);
+ assert_approx_equals(shifts.lspace, -5, epsilon);
+ assert_approx_equals(shifts.voffset, -10, epsilon);
+ }, "content is shifted by the specified lspace/voffset (RTL)");
+
+ mpaddeds = document.getElementById("dynamic_tests").getElementsByTagName("mpadded");
+ test(function() {
+ mpaddeds[0].setAttribute("lspace", "5px")
+ let shifts = GetShifts(mpaddeds[0]);
+ assert_approx_equals(shifts.lspace, 5, epsilon, "attach lspace");
+ assert_approx_equals(shifts.voffset, 0, epsilon);
+
+ mpaddeds[1].setAttribute("voffset", "10px")
+ shifts = GetShifts(mpaddeds[1]);
+ assert_approx_equals(shifts.lspace, 0, epsilon);
+ assert_approx_equals(shifts.voffset, 10, epsilon, "attach voffset");
+
+ mpaddeds[2].removeAttribute("lspace")
+ shifts = GetShifts(mpaddeds[2]);
+ assert_approx_equals(shifts.lspace, 0, epsilon, "remove lspace");
+ assert_approx_equals(shifts.voffset, 10, epsilon);
+
+ mpaddeds[3].removeAttribute("voffset")
+ shifts = GetShifts(mpaddeds[3]);
+ assert_approx_equals(shifts.lspace, 5, epsilon);
+ assert_approx_equals(shifts.voffset, 0, epsilon, "remove voffset");
+
+ mpaddeds[4].setAttribute("lspace", "15px")
+ shifts = GetShifts(mpaddeds[4]);
+ assert_approx_equals(shifts.lspace, 15, epsilon, "modify lspace");
+ assert_approx_equals(shifts.voffset, 10, epsilon);
+
+ mpaddeds[5].setAttribute("voffset", "-10px")
+ shifts = GetShifts(mpaddeds[5]);
+ assert_approx_equals(shifts.lspace, 5, epsilon);
+ assert_approx_equals(shifts.voffset, -10, epsilon, "modify voffset");
+ }, "dynamic changes of lspace/voffset");
+
+ done();
+ }
+</script>
+<style>
+div.shrink-wrap {
+ background: yellow;
+ display: inline-block;
+ margin-top: 5px;
+ padding-top: 5px;
+}
+</style>
+</head>
+<body>
+ <div id="log"></div>
+ <div id="static_tests">
+ <span id="baseline" style="display: inline-block; width: 30px; height: 5px; background: blue"></span>
+ <math>
+ <mpadded lspace="5px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded lspace="-5px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded lspace="5%" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded lspace="-5%" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded voffset="-10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded voffset="10%" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded voffset="-10%" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded lspace="5px" voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded lspace="5px" voffset="-10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ </math>
+ </div>
+ <div id="static_tests_rtl">
+ <math dir="rtl">
+ <mpadded lspace="5px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded lspace="-5px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded voffset="-10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded lspace="5px" voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded lspace="5px" voffset="-10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ </math>
+ </div>
+ <div id="dynamic_tests">
+ <math>
+ <mpadded style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded lspace="5px" voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded lspace="5px" voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded lspace="5px" voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ <mpadded lspace="5px" voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ </math>
+ </div>
+ <div>
+ <div class="shrink-wrap">
+ <math>
+ <mpadded lspace="5px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ </math>
+ </div>
+ <div class="shrink-wrap">
+ <math>
+ <mpadded lspace="-5px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ </math>
+ </div>
+ <div class="shrink-wrap">
+ <math>
+ <mpadded voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ </math>
+ </div>
+ <div class="shrink-wrap">
+ <math>
+ <mpadded voffset="-10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ </math>
+ </div>
+ <div class="shrink-wrap">
+ <math>
+ <mpadded lspace="5px" voffset="10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ </math>
+ </div>
+ <div class="shrink-wrap">
+ <math>
+ <mpadded lspace="5px" voffset="-10px" style="background: black"><mspace width="10px" depth="15px" height="20px" style="background: green; opacity: .5"/></mpadded>
+ </math>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-percentage-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-percentage-001-ref.html
new file mode 100644
index 0000000000..79d7df39d0
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-percentage-001-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>mpadded percentages (reference)</title>
+ <style>
+ .red {
+ background: red;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if there is a green square with no red.</p>
+ <math display="block"
+ style="width: 200px; height: 200px; background: green">
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-percentage-001.html b/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-percentage-001.html
new file mode 100644
index 0000000000..ef2391c42b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-percentage-001.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>mpadded percentages</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#inner-box-and-requested-parameters">
+ <meta name="assert" content="Verify that percentage values for mpadded do not use refer to the containing block">
+ <link rel="match" href="mpadded-percentage-001-ref.html">
+ <style>
+ .red {
+ background: red;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if there is a green square with no red.</p>
+ <math display="block"
+ style="width: 200px; height: 200px; background: green">
+ <mpadded width="5%" height="10px" class="red"></mpadded>
+ <mpadded width=" 5%" height="10px" class="red"></mpadded>
+ <mpadded width="5% " height="10px" class="red"></mpadded>
+ <mpadded width="10px" height="5%" class="red"></mpadded>
+ <mpadded width="10px" height=" 5%" class="red"></mpadded>
+ <mpadded width="10px" height="5% " class="red"></mpadded>
+ <mpadded width="10px" depth="5%" class="red"></mpadded>
+ <mpadded width="10px" depth=" 5%" class="red"></mpadded>
+ <mpadded width="10px" depth="5% " class="red"></mpadded>
+ <mpadded width="10px" height="5%" depth="5%" class="red"></mpadded>
+ <mpadded width="10px" height=" 5%" depth=" 5%" class="red"></mpadded>
+ <mpadded width="10px" height="5% " depth="5% " class="red"></mpadded>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-percentage-002.html b/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-percentage-002.html
new file mode 100644
index 0000000000..36d1b4f389
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mpadded/mpadded-percentage-002.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title></title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#adjust-space-around-content-mpadded">
+ <meta name="assert" content="Percentage values are interpreted as the default value">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script src="/mathml/support/layout-comparison.js"></script>
+ <style>
+ .testedElement {
+ background: red;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="log"></div>
+
+ <p>
+ <math>
+ <mpadded id="reference">
+ <mspace width="10px" height="20px" depth="30px"
+ style="background: blue"/>
+ </mpadded>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mpadded class="testedElement" width="200%">
+ <mspace width="10px" height="20px" depth="30px"
+ style="background: blue"/>
+ </mpadded>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mpadded class="testedElement" height="200%">
+ <mspace width="10px" height="20px" depth="30px"
+ style="background: blue"/>
+ </mpadded>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mpadded class="testedElement" depth="200%">
+ <mspace width="10px" height="20px" depth="30px"
+ style="background: blue"/>
+ </mpadded>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mpadded class="testedElement" lspace="200%">
+ <mspace width="10px" height="20px" depth="30px"
+ style="background: blue"/>
+ </mpadded>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mpadded class="testedElement" voffset="200%">
+ <mspace width="10px" height="20px" depth="30px"
+ style="background: blue"/>
+ </mpadded>
+ </math>
+ </p>
+ <script type="text/javascript">
+ Array.from(document.getElementsByClassName("testedElement")).forEach(mpadded => {
+ var reference = document.getElementById("reference");
+ const name = ["width", "depth", "height", "lspace", "voffset"].find(attr => mpadded.hasAttribute(attr));
+ const epsilon = 1;
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ compareLayout(mpadded, reference, epsilon);
+ }, `${name}='${mpadded.getAttribute(name)}' is interpreted as the default value`);
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/dynamic-mrow-like-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/dynamic-mrow-like-001-ref.html
new file mode 100644
index 0000000000..2f823ba955
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/dynamic-mrow-like-001-ref.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Dynamic mrow-like elements (reference)</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ math {
+ font: 25px/1 Ahem;
+ background: lightblue;
+ }
+ li {
+ padding: 2px;
+ }
+</style>
+</head>
+<body>
+ <ol>
+ <li><math class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></math></li>
+ <li><math class="testedElement"><mn>X</mn><mn>p</mn></math></li>
+ <li><math><mrow class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></mrow></math></li>
+ <li><math><mrow class="testedElement"><mn>X</mn><mn>p</mn></mrow></math></li>
+ <li><math><maction class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></maction></math></li>
+ <li><math><maction class="testedElement"><mn>X</mn><mn>p</mn></maction></math></li>
+ <li><math><merror class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></merror></math></li>
+ <li><math><merror class="testedElement"><mn>X</mn><mn>p</mn></merror></math></li>
+ <li><math><mphantom class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></mphantom></math></li>
+ <li><math><mphantom class="testedElement"><mn>X</mn><mn>p</mn></mphantom></math></li>
+ <li><math><mstyle class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></mstyle></math></li>
+ <li><math><mstyle class="testedElement"><mn>X</mn><mn>p</mn></mstyle></math></li>
+ <li><math><semantics class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></semantics></math></li>
+ <li><math><semantics class="testedElement"><mn>X</mn><mn>p</mn></semantics></math></li>
+ <li><math><unknown class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></unknown></math></li>
+ <li><math><unknown class="testedElement"><mn>X</mn><mn>p</mn></unknown></math></li>
+ <li><math><none class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></none></math></li>
+ <li><math><none class="testedElement"><mn>X</mn><mn>p</mn></none></math></li>
+ <li><math><mprescripts class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></mprescripts></math></li>
+ <li><math><mprescripts class="testedElement"><mn>X</mn><mn>p</mn></mprescripts></math></li>
+ </ol>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/dynamic-mrow-like-001.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/dynamic-mrow-like-001.html
new file mode 100644
index 0000000000..79de59feec
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/dynamic-mrow-like-001.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>Dynamic mrow-like elements</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#horizontally-group-sub-expressions-mrow">
+<script src="/mathml/support/mathml-fragments.js"></script>
+<meta name="assert" content="Dynamically set children of mrow-like elements.">
+<style>
+ math {
+ font: 25px/1 Ahem;
+ background: lightblue;
+ }
+ li {
+ padding: 2px;
+ }
+</style>
+<link rel="match" href="dynamic-mrow-like-001-ref.html">
+<script>
+ window.addEventListener("load", function() {
+
+ // force initial layout so we're sure what we're testing against
+ document.documentElement.getBoundingClientRect();
+
+ Array.from(document.getElementsByClassName("testedElement")).forEach(e => {
+ if (e.children.length == 0) {
+ // Add 3 children.
+ let mn = FragmentHelper.createElement("mn");
+ mn.textContent = "X";
+ e.appendChild(mn);
+ mn = FragmentHelper.createElement("mn");
+ mn.textContent = "É";
+ e.appendChild(mn);
+ mn = FragmentHelper.createElement("mn");
+ mn.textContent = "p";
+ e.insertBefore(mn, e.lastElementChild);
+ } else {
+ // Remove last child.
+ e.removeChild(e.lastElementChild);
+ }
+ });
+
+ document.documentElement.classList.remove('reftest-wait');
+ });
+</script>
+</head>
+<body>
+ <ol>
+ <li><math class="testedElement"></math></li>
+ <li><math class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></math></li>
+ <li><math><mrow class="testedElement"></mrow></math></li>
+ <li><math><mrow class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></mrow></math></li>
+ <li><math><maction class="testedElement"></maction></math></li>
+ <li><math><maction class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></maction></math></li>
+ <li><math><merror class="testedElement"></merror></math></li>
+ <li><math><merror class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></merror></math></li>
+ <li><math><mphantom class="testedElement"></mphantom></math></li>
+ <li><math><mphantom class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></mphantom></math></li>
+ <li><math><mstyle class="testedElement"></mstyle></math></li>
+ <li><math><mstyle class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></mstyle></math></li>
+ <li><math><semantics class="testedElement"></semantics></math></li>
+ <li><math><semantics class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></semantics></math></li>
+ <li><math><unknown class="testedElement"></unknown></math></li>
+ <li><math><unknown class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></unknown></math></li>
+ <li><math><none class="testedElement"></none></math></li>
+ <li><math><none class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></none></math></li>
+ <li><math><mprescripts class="testedElement"></mprescripts></math></li>
+ <li><math><mprescripts class="testedElement"><mn>X</mn><mn>p</mn><mn>É</mn></mprescripts></math></li>
+ </ol>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/inferred-mrow-baseline.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/inferred-mrow-baseline.html
new file mode 100644
index 0000000000..0086646859
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/inferred-mrow-baseline.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Baseline of inferred mrows</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#horizontally-group-sub-expressions-mrow">
+<link rel="help" href="https://w3c.github.io/mathml-core/#radicals-msqrt-mroot">
+<link rel="help" href="https://w3c.github.io/mathml-core/#style-change-mstyle">
+<link rel="help" href="https://w3c.github.io/mathml-core/#error-message-merror">
+<link rel="help" href="https://w3c.github.io/mathml-core/#making-sub-expressions-invisible-mphantom">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-top-level-math-element">
+<link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.menclose">
+<link rel="help" href="https://w3c.github.io/mathml-core/#adjust-space-around-content-mpadded">
+<meta name="assert" content="Baseline for mrow-like elements is correct.">
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script type="text/javascript">
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+ function runTests()
+ {
+ ["Mrow", "Sqrt", "Style", "Error", "Phantom", "Math", "Menclose", "Mpadded", "Unknown", "Mtd", "None", "Mprescripts"].forEach((tag) => {
+ var x = document.getElementById(`above${tag}`).getBoundingClientRect();
+ var y = document.getElementById(`below${tag}`).getBoundingClientRect();
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_equals(x.bottom, y.top);
+ }, `baseline alignment inside ${tag}`);
+ });
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math><mrow><mspace id="aboveMrow" width="10px" height="30px" style="background: purple"></mspace><mspace id="belowMrow" width="10px" depth="30px" style="background: blue"></mspace></mrow></math>
+ <math><msqrt><mspace id="aboveSqrt" width="10px" height="30px" style="background: purple"></mspace><mspace id="belowSqrt" width="10px" depth="30px" style="background: blue"></mspace></msqrt></math>
+ <math><mstyle><mspace id="aboveStyle" width="10px" height="30px" style="background: purple"></mspace><mspace id="belowStyle" width="10px" depth="30px" style="background: blue"></mspace></mstyle></math>
+ <math><merror><mspace id="aboveError" width="10px" height="30px" style="background: purple"></mspace><mspace id="belowError" width="10px" depth="30px" style="background: blue"></mspace></merror></math>
+ <math><mphantom><mspace style="visibility: visible;" id="abovePhantom" width="10px" height="30px" style="background: purple"></mspace><mspace style="visibility: visible;" id="belowPhantom" width="10px" depth="30px" style="background: blue"></mspace></mphantom></math>
+ <math><mspace id="aboveMath" width="10px" height="30px" style="background: purple"></mspace><mspace id="belowMath" width="10px" depth="30px" style="background: blue"></mspace></math>
+ <!-- menclose is treated as <unknown> in MathML Core -->
+ <math><menclose notation="box"><mspace id="aboveMenclose" width="10px" height="30px" style="background: purple"
+></mspace><mspace id="belowMenclose" width="10px" depth="30px" style="background: blue"></mspace></menclose></math>
+ <math><mpadded lspace="10px"><mspace id="aboveMpadded" width="10px" height="30px" style="background: purple"
+></mspace><mspace id="belowMpadded" width="10px" depth="30px" style="background: blue"></mspace></mpadded></math>
+ <math><unknown><mspace id="aboveUnknown" width="10px" height="30px" style="background: purple"
+></mspace><mspace id="belowUnknown" width="10px" depth="30px" style="background: blue"></mspace></unknown></math>
+ <math><mtable><mtr><mtd><mspace id="aboveMtd" width="10px" height="30px" style="background: purple"
+></mspace><mspace id="belowMtd" width="10px" depth="30px" style="background: blue"></mspace></mtd></mtr></mtable></math>
+ <math><none><mspace id="aboveNone" width="10px" height="30px" style="background: purple"></mspace><mspace id="belowNone" width="10px" depth="30px" style="background: blue"></mspace></none></math>
+ <math><mprescripts><mspace id="aboveMprescripts" width="10px" height="30px" style="background: purple"></mspace><mspace id="belowMprescripts" width="10px" depth="30px" style="background: blue"></mspace></none></math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/inferred-mrow-stretchy.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/inferred-mrow-stretchy.html
new file mode 100644
index 0000000000..614438deb3
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/inferred-mrow-stretchy.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Stretchy in inferred mrows</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#horizontally-group-sub-expressions-mrow">
+<link rel="help" href="https://w3c.github.io/mathml-core/#radicals-msqrt-mroot">
+<link rel="help" href="https://w3c.github.io/mathml-core/#style-change-mstyle">
+<link rel="help" href="https://w3c.github.io/mathml-core/#error-message-merror">
+<link rel="help" href="https://w3c.github.io/mathml-core/#making-sub-expressions-invisible-mphantom">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-top-level-math-element">
+<link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.menclose">
+<link rel="help" href="https://w3c.github.io/mathml-core/#adjust-space-around-content-mpadded">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<meta name="assert" content="Operators can stretch inside mrow-like elements.">
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ mo {
+ font-size: 10px;
+ font-family: axisheight5000-verticalarrow14000;
+ }
+ @font-face {
+ font-family: axisheight5000-verticalarrow14000;
+ src: url("/fonts/math/axisheight5000-verticalarrow14000.woff");
+ }
+</style>
+<script type="text/javascript">
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ function runTests()
+ {
+ ["Mrow", "Sqrt", "Style", "Error", "Phantom", "Math", "Menclose", "Mpadded", "Unknown", "Mtd", "None", "Mprescripts"].forEach((tag) => {
+ var mo = document.getElementById(`mo${tag}`);
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_greater_than_equal(mo.getBoundingClientRect().height, 100);
+ }, `operator stretching inside ${tag}`);
+ });
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math><mrow><mo id="moMrow">&#x21A8;</mo><mspace width="1px" height="100px" style="background: blue"></mspace></mrow></math>
+ <math><msqrt><mo id="moSqrt">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></msqrt></math>
+ <math><mstyle><mo id="moStyle">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></mstyle></math>
+ <math><merror><mo id="moError">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></merror></math>
+ <math><mphantom><mo style="visibilty: visible;" id="moPhantom">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></mphantom></math>
+ <math><mo id="moMath">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></math>
+ <!-- menclose is treated as <unknown> in MathML Core -->
+ <math><menclose notation="box"><mo id="moMenclose">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></menclose></math>
+ <math><mpadded lspace="10px"><mo id="moMpadded">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></mpadded></math>
+ <math><unknown><mo id="moUnknown">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></unknown></math>
+ <math><mtable><mtr><mtd><mo id="moMtd">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></mtd></mtr></mtable></math>
+ <math><none><mo id="moNone">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></none></math>
+ <math><mprescripts><mo id="moMprescripts">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></mprescripts></math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mfenced-element-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mfenced-element-001-ref.html
new file mode 100644
index 0000000000..00c781b6e4
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mfenced-element-001-ref.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>mfenced element</title>
+ </head>
+ <body>
+ <p>Test passes if you see 6 green squares and no red.</p>
+ <p>
+ <math>
+ <mrow>
+ <mspace width="30px" height="30px" style="background: green"></mspace>
+ <mspace width="30px" height="30px" style="background: lightgreen"></mspace>
+ <mspace width="30px" height="30px" style="background: green"></mspace>
+ </mrow>
+ <mrow>
+ <mspace width="30px" height="30px" style="background: lightgreen"></mspace>
+ <mspace width="30px" height="30px" style="background: green"></mspace>
+ <mspace width="30px" height="30px" style="background: lightgreen"></mspace>
+ </mrow>
+ </math>
+ </p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mfenced-element-001.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mfenced-element-001.html
new file mode 100644
index 0000000000..d39ff45f62
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mfenced-element-001.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>mfenced element</title>
+ <link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.mfenced">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#new-display-math-value">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#mathml-elements">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#horizontally-group-sub-expressions-mrow">
+ <meta name="assert" content="Verify that the mfenced element is not supported.">
+ <link rel="match" href="legacy-mfenced-element-001-ref.html">
+ </head>
+ <body>
+ <p>Test passes if you see 6 green squares and no red.</p>
+ <p>
+ <math style="color: red">
+ <mfenced>
+ <mspace width="30px" height="30px" style="background: green"></mspace>
+ <mspace width="30px" height="30px" style="background: lightgreen"></mspace>
+ <mspace width="30px" height="30px" style="background: green"></mspace>
+ </mfenced>
+ <mfenced open="{" close="]" separators="?!">
+ <mspace width="30px" height="30px" style="background: lightgreen"></mspace>
+ <mspace width="30px" height="30px" style="background: green"></mspace>
+ <mspace width="30px" height="30px" style="background: lightgreen"></mspace>
+ </mfenced>
+ </math>
+ </p>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>
+ MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mrow-like-elements-001.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mrow-like-elements-001.html
new file mode 100644
index 0000000000..277529d829
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mrow-like-elements-001.html
@@ -0,0 +1,188 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Legacy maction and semantics elements</title>
+<link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.maction">
+<link rel="help" href="https://w3c.github.io/mathml-core/#enlivening-expressions">
+<link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.semantics">
+<link rel="help" href="https://w3c.github.io/mathml-core/#semantics-and-presentation">
+<meta name="assert" content="Legacy maction and semantics elements are handled as mrow with special style">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/layout-comparison.js"></script>
+<script type="text/javascript">
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+ function runTests()
+ {
+ Array.from(document.getElementsByClassName("TestContainer")).forEach(container => {
+ const id = container.id;
+ const math = container.getElementsByTagName("math");
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace(), "<mspace> is supported");
+ const epsilon = 1;
+ compareLayout(math[0], math[1], epsilon);
+ }, `Element is laid out as an mrow with only first child displayed (id=${id})`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace(), "<mspace> is supported");
+ let firstChild = math[0].firstElementChild.firstElementChild;
+ for (var child = firstChild; child; child = child.nextElementSibling) {
+ var style = window.getComputedStyle(child).getPropertyValue("display");
+ if (child == firstChild) {
+ assert_equals(style, "math", "First child has display: math");
+ } else {
+ assert_equals(style, "none", "Other children have display: none");
+ }
+ }
+ }, `Computed display of children (id=${id})`);
+ });
+ done();
+ }
+</script>
+<style>
+ mspace:nth-child(2n) {
+ background: lightblue;
+ }
+ mspace:nth-child(2n+1) {
+ background: lightgreen;
+ }
+ mrow.onlyShowFirstChild > :not(:first-child) {
+ display: none;
+ }
+</style>
+</head>
+<body>
+ <div id="log"></div>
+ <p class="TestContainer" id="semantics">
+ <math>
+ <semantics>
+ <mspace width="10px" height="10px"></mspace>
+ <mspace width="10px" depth="10px"></mspace>
+ <mspace width="10px" height="15px" depth="5px"></mspace>
+ <mspace width="10px" height="5px" depth="15px"></mspace>
+ </semantics>
+ </math>
+ <math>
+ <mrow class="onlyShowFirstChild">
+ <mspace width="10px" height="10px"></mspace>
+ <mspace width="10px" depth="10px"></mspace>
+ <mspace width="10px" height="15px" depth="5px"></mspace>
+ <mspace width="10px" height="5px" depth="15px"></mspace>
+ </mrow>
+ </math>
+ </p>
+ <p class="TestContainer" id="semantics-annotations">
+ <math>
+ <semantics>
+ <mspace width="10px" height="10px"></mspace>
+ <annotation>ANNOTATION</annotation>
+ <annotation-xml>ANNOTATION-XML</annotation-xml>
+ </semantics>
+ </math>
+ <math>
+ <mrow class="onlyShowFirstChild">
+ <mspace width="10px" height="10px"></mspace>
+ <annotation>ANNOTATION</annotation>
+ <annotation-xml>ANNOTATION-XML</annotation-xml>
+ </mrow>
+ </math>
+ </p>
+ <p class="TestContainer" id="maction">
+ <math>
+ <maction>
+ <mspace width="10px" height="10px"></mspace>
+ <mspace width="10px" depth="10px"></mspace>
+ <mspace width="10px" height="15px" depth="5px"></mspace>
+ <mspace width="10px" height="5px" depth="15px"></mspace>
+ </maction>
+ </math>
+ <math>
+ <mrow class="onlyShowFirstChild">
+ <mspace width="10px" height="10px"></mspace>
+ <mspace width="10px" depth="10px"></mspace>
+ <mspace width="10px" height="15px" depth="5px"></mspace>
+ <mspace width="10px" height="5px" depth="15px"></mspace>
+ </mrow>
+ </math>
+ </p>
+ <p class="TestContainer" id="maction-toggle">
+ <math>
+ <maction actiontype="toggle">
+ <mspace width="10px" height="10px"></mspace>
+ <mspace width="10px" depth="10px"></mspace>
+ <mspace width="10px" height="15px" depth="5px"></mspace>
+ <mspace width="10px" height="5px" depth="15px"></mspace>
+ </maction>
+ </math>
+ <math>
+ <mrow class="onlyShowFirstChild">
+ <mspace width="10px" height="10px"></mspace>
+ <mspace width="10px" depth="10px"></mspace>
+ <mspace width="10px" height="15px" depth="5px"></mspace>
+ <mspace width="10px" height="5px" depth="15px"></mspace>
+ </mrow>
+ </math>
+ </p>
+ <p class="TestContainer" id="maction-toggle-selection">
+ <math>
+ <maction actiontype="toggle" selection="3">
+ <mspace width="10px" height="10px"></mspace>
+ <mspace width="10px" depth="10px"></mspace>
+ <mspace width="10px" height="15px" depth="5px"></mspace>
+ <mspace width="10px" height="5px" depth="15px"></mspace>
+ </maction>
+ </math>
+ <math>
+ <mrow class="onlyShowFirstChild">
+ <mspace width="10px" height="10px"></mspace>
+ <mspace width="10px" depth="10px"></mspace>
+ <mspace width="10px" height="15px" depth="5px"></mspace>
+ <mspace width="10px" height="5px" depth="15px"></mspace>
+ </mrow>
+ </math>
+ </p>
+ <p class="TestContainer" id="maction-statusline">
+ <math>
+ <maction actiontype="statusline">
+ <mspace width="10px" height="10px"></mspace>
+ <mtext>MESSAGE</mtext>
+ </maction>
+ </math>
+ <math>
+ <mrow class="onlyShowFirstChild">
+ <mspace width="10px" height="10px"></mspace>
+ <mtext>MESSAGE</mtext>
+ </mrow>
+ </math>
+ </p>
+ <p class="TestContainer" id="maction-tooltip">
+ <math>
+ <maction actiontype="tooltip">
+ <mspace width="10px" height="10px"></mspace>
+ <mtext>MESSAGE</mtext>
+ </maction>
+ </math>
+ <math>
+ <mrow class="onlyShowFirstChild">
+ <mspace width="10px" height="10px"></mspace>
+ <mtext>MESSAGE</mtext>
+ </mrow>
+ </math>
+ </p>
+ <p class="TestContainer" id="maction-input">
+ <math>
+ <maction actiontype="input">
+ <mspace width="10px" height="10px"></mspace>
+ </maction>
+ </math>
+ <math>
+ <mrow class="onlyShowFirstChild">
+ <mspace width="10px" height="10px"></mspace>
+ </mrow>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mrow-like-elements-002-ref.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mrow-like-elements-002-ref.html
new file mode 100644
index 0000000000..4fd4b225f3
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mrow-like-elements-002-ref.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Legacy maction and semantics elements (reference)</title>
+</head>
+<body>
+ <p>This test passes if you see 4 green squares and no red.</p>
+ <p>
+ <math>
+ <mrow>
+ <mtext>
+ <span style="display: inline-block; width: 50px; height: 50px; background: green;"></span>
+ </mtext>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mrow style="display: inline-block">
+ <span style="display: inline-block; width: 50px; height: 50px; background: green;"></span>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mspace style="background: green" width="50px" height="50px"></mspace>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mspace style="background: green" width="50px" height="50px"></mspace>
+ </mrow>
+ </math>
+ </p>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mrow-like-elements-002.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mrow-like-elements-002.html
new file mode 100644
index 0000000000..99a5721bce
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mrow-like-elements-002.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Legacy maction and semantics elements</title>
+<link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.maction">
+<link rel="help" href="https://w3c.github.io/mathml-core/#enlivening-expressions">
+<link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.semantics">
+<link rel="help" href="https://w3c.github.io/mathml-core/#semantics-and-presentation">
+<meta name="assert" content="Verify that one can override the default rendering legacy maction and semantics elements using the display property">
+<link rel="match" href="legacy-mrow-like-elements-002-ref.html">
+</head>
+<body>
+ <p>This test passes if you see 4 green squares and no red.</p>
+ <p>
+ <math>
+ <semantics>
+ <mspace style="display: none; background: red;" width="50px" height="50px"></mspace>
+ <mspace style="background: red;" width="50px" height="50px"></mspace>
+ <annotation style="display: math">
+ <span style="display: inline-block; width: 50px; height: 50px; background: green;"></span>
+ </annotation>
+ </semantics>
+ </math>
+ </p>
+ <p>
+ <math>
+ <semantics>
+ <mspace style="display: none; background: red;" width="50px" height="50px"></mspace>
+ <mspace style="background: red;" width="50px" height="50px"></mspace>
+ <annotation-xml style="display: inline-block" encoding="text/html">
+ <span style="display: inline-block; width: 50px; height: 50px; background: green;"></span>
+ </annotation-xml>
+ </semantics>
+ </math>
+ </p>
+ <p>
+ <math>
+ <maction actiontype="toggle">
+ <mspace style="display: none; background: red" width="50px" height="50px"></mspace>
+ <mspace style="display: math; background: green" width="50px" height="50px"></mspace>
+ </maction>
+ </math>
+ </p>
+ <p>
+ <math>
+ <maction actiontype="toggle" selection="2">
+ <mspace style="display: none; background: red" width="50px" height="50px"></mspace>
+ <mspace style="display: math; background: green" width="50px" height="50px"></mspace>
+ <mspace style="background: red" width="50px" height="50px"></mspace>
+ </maction>
+ </math>
+ </p>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mstyle-attributes.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mstyle-attributes.html
new file mode 100644
index 0000000000..2463c40476
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/legacy-mstyle-attributes.html
@@ -0,0 +1,164 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Legacy mstyle attributes</title>
+<link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.mstyle">
+<link rel="help" href="https://w3c.github.io/mathml-core/#style-change-mstyle">
+<link rel="help" href="https://w3c.github.io/mathml-core/#space-mspace">
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#string-literal-ms">
+<link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.menclose">
+<meta name="assert" content="Legacy mstyle attributes are ignored">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/layout-comparison.js"></script>
+<script type="text/javascript">
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+ function runTests()
+ {
+ Array.from(document.getElementsByClassName("TestContainer")).forEach(container => {
+ const tag = container.id;
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ const epsilon = 1;
+ const math = container.getElementsByTagName("math");
+ compareLayout(math[0], math[1], epsilon);
+ }, `Legacy mstyle attributes do not apply to ${tag}`);
+ });
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <!-- Note: mpadded attributes are not tested since MathML3 did not allow to
+ set them from mstyle. Also, it is not clear whether munderover's
+ accent/accentunder could be applied from mstyle, given that the former
+ clashes with mo@accent. Other legacy mstyle attributes not in MathML
+ Core or without visual effect are not tested.
+ -->
+ <p class="TestContainer" id="mspace">
+ <math>
+ <mstyle width="50px" height="50px" depth="50px">
+ <mspace style="background: lightblue"></mspace>
+ </mstyle>
+ </math>
+ <math>
+ <mstyle>
+ <mspace style="background: lightblue"></mspace>
+ </mstyle>
+ </math>
+ </p>
+ <p class="TestContainer" id="mfrac">
+ <math>
+ <mstyle linethickness="50px">
+ <mfrac>
+ <mn>1</mn>
+ <mn>2</mn>
+ </mfrac>
+ </mstyle>
+ </math>
+ <math>
+ <mstyle>
+ <mfrac>
+ <mn>1</mn>
+ <mn>2</mn>
+ </mfrac>
+ </mstyle>
+ </math>
+ </p>
+ <p class="TestContainer" id="mo">
+ <math displaystyle="true">
+ <mstyle lspace="50px" rspace="50px">
+ <mn>1</mn>
+ <mo>A</mo>
+ <mn>2</mn>
+ </mstyle>
+ <mstyle movablelimits="false" largeop="false">
+ <munder>
+ <mo>∑</mo>
+ <mn>3</mn>
+ </munder>
+ </mstyle>
+ <mstyle accent="false">
+ <mover>
+ <mn>4</mn>
+ <mo>⇀</mo>
+ </mover>
+ </mstyle>
+ <mstyle stretchy="false" symmetric="false" maxsize="20px">
+ <mrow>
+ <mo>|</mo>
+ <mspace height="100px"></mspace>
+ </mrow>
+ </mstyle>
+ <mstyle minsize="100px">
+ <mrow>
+ <mo>|</mo>
+ <mn>4</mn>
+ </mrow>
+ </mstyle>
+ </math>
+ <math displaystyle="true">
+ <mstyle>
+ <mn>1</mn>
+ <mo>A</mo>
+ <mn>2</mn>
+ </mstyle>
+ <mstyle>
+ <munder>
+ <mo>∑</mo>
+ <mn>3</mn>
+ </munder>
+ </mstyle>
+ <mstyle>
+ <mover>
+ <mn>4</mn>
+ <mo>⇀</mo>
+ </mover>
+ </mstyle>
+ <mstyle>
+ <mrow>
+ <mo>|</mo>
+ <mspace height="100px"></mspace>
+ </mrow>
+ </mstyle>
+ <mstyle>
+ <mrow>
+ <mo>|</mo>
+ <mn>4</mn>
+ </mrow>
+ </mstyle>
+ </math>
+ </p>
+ <!-- notation attribute is from MathML3's menclose element -->
+ <p class="TestContainer" id="menclose">
+ <math>
+ <mstyle notation="box">
+ <mn>1</mn>
+ </mstyle>
+ </math>
+ <math>
+ <mstyle>
+ <mn>1</mn>
+ </mstyle>
+ </math>
+ </p>
+ <p class="TestContainer" id="ms">
+ <math>
+ <mstyle lquote="AAAA" rquote="BBBB">
+ <ms>1</ms>
+ </mstyle>
+ </math>
+ <math>
+ <mstyle>
+ <ms>1</ms>
+ </mstyle>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/merror-001.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/merror-001.html
new file mode 100644
index 0000000000..a9a021c2e9
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/merror-001.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Test the merror element</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#error-message-merror">
+<link rel="help" href="https://w3c.github.io/mathml-core/#user-agent-stylesheet">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<meta name="assert" content="Verify default merror style and size.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ math {
+ font: 25px/1 Ahem;
+ }
+</style>
+</head>
+<body>
+ <div id="log"></div>
+ <div>
+ <math>
+ <mrow id="reference"><mtext>AN ERROR</mtext></mrow>
+ <merror id="merror"><mtext>AN ERROR</mtext></merror>
+ </math>
+ </div>
+ <script>
+ test(function () {
+ var style = window.getComputedStyle(document.getElementById("merror"));
+ assert_equals(style.borderWidth, "1px");
+ assert_equals(style.borderColor, "rgb(255, 0, 0)");
+ assert_equals(style.borderStyle, "solid");
+ assert_equals(style.backgroundColor, "rgb(255, 255, 224)");
+ }, "Default CSS properties on merror");
+
+ test(function () {
+ var merrorBox = document.getElementById("merror").getBoundingClientRect();
+ var referenceBox = document.getElementById("reference").getBoundingClientRect();
+ assert_equals(merrorBox.width, referenceBox.width + 2);
+ assert_equals(merrorBox.height, referenceBox.height + 2);
+ }, "Bounding box is the same as mrow + 1px border");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/mrow-fallback.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/mrow-fallback.html
new file mode 100644
index 0000000000..3f9d466148
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/mrow-fallback.html
@@ -0,0 +1,125 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Test mrow fallback for some MathML elements</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#script-and-limit-schemata">
+<meta name="assert" content="Verify that invalid markup fallbacks to row layout.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/layout-comparison.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function isValid(tagName, mspaceCount) {
+ switch (tagName) {
+ case "mfrac":
+ case "mroot":
+ case "munder":
+ case "mover":
+ case "msub":
+ case "msup":
+ return mspaceCount == 2;
+ case "munderover":
+ case "msubsup":
+ return mspaceCount == 3;
+ case "mmultiscripts":
+ return mspaceCount % 2 == 1;
+ }
+ }
+
+ function runTests() {
+ let container = document.getElementById("container");
+ const epsilon = 1;
+ ["mfrac", "mroot", "munder", "mover", "munderover", "msub", "msup", "msubsup", "mmultiscripts"].forEach(tag => {
+ let element = FragmentHelper.createElement(tag);
+ let reference = FragmentHelper.createElement("mrow");
+ container.appendChild(element);
+ container.appendChild(reference);
+ let maxCount = tag == "mmultiscripts" ? 10 : 5;
+ let mspaceCount = 0;
+ for (let count = 0; count <= maxCount; count++) {
+ if (!isValid(tag, mspaceCount)) {
+ test(function() {
+ compareLayout(element, reference, epsilon);
+ }, `Invalid <${element.tagName}> should lay out as an mrow (count == ${count})`);
+ }
+ if (tag == "mmultiscripts" && count == maxCount / 2) {
+ [element, reference].forEach(el => {
+ el.insertAdjacentHTML("beforeend", `<mprescripts/>`);
+ });
+ } else {
+ let width = (count + 1) * 10;
+ let height = (count + 1) * (count % 2 ? 15 : 5);
+ let depth = (count + 1) * (count % 2 ? 5 : 15);
+ [element, reference].forEach(el => {
+ el.insertAdjacentHTML("beforeend", `<mspace height="${height}px" depth="${depth}px" width="${width}px" style="background: black"/>`);
+ });
+ mspaceCount++;
+ }
+ }
+ });
+ Array.from(document.getElementById("invalidMultiscripts").
+ getElementsByTagName("mmultiscripts")).forEach(element => {
+ let reference = element.nextElementSibling;
+ let description = element.dataset.description;
+ test(function() {
+ compareLayout(element, reference, epsilon);
+ }, `Invalid mmultiscripts should lay out as an mrow (${description})`);
+ });
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <div id="container"></div>
+ <div id="invalidMultiscripts">
+ <math>
+ <mmultiscripts data-description="first in-flow child is an <mprescripts>">
+ <mprescripts/>
+ <mspace height="5px" depth="15px" width="10px" style="background: black"/>
+ <mspace height="30px" depth="10px" width="20px" style="background: black"/>
+ <mspace height="15px" depth="45px" width="30px" style="background: black"/>
+ <mspace height="60px" depth="20px" width="40px" style="background: black"/>
+
+ </mmultiscripts>
+ <mrow>
+ <mprescripts/>
+ <mspace height="5px" depth="15px" width="10px" style="background: black"/>
+ <mspace height="30px" depth="10px" width="20px" style="background: black"/>
+ <mspace height="15px" depth="45px" width="30px" style="background: black"/>
+ <mspace height="60px" depth="20px" width="40px" style="background: black"/>
+
+ </mrow>
+ </math>
+ <math>
+ <mmultiscripts data-description="one of the even number of children after the first <mprescripts> is an <mprescripts>">
+ <mspace height="5px" depth="15px" width="10px" style="background: black"/>
+ <mspace height="30px" depth="10px" width="20px" style="background: black"/>
+ <mspace height="15px" depth="45px" width="30px" style="background: black"/>
+ <mprescripts/>
+ <mspace height="60px" depth="20px" width="40px" style="background: black"/>
+ <mprescripts/>
+ <mspace height="25px" depth="75px" width="50px" style="background: black"/>
+ <mspace height="35px" depth="105px" width="70px" style="background: black"/>
+ </mmultiscripts>
+ <mrow>
+ <mspace height="5px" depth="15px" width="10px" style="background: black"/>
+ <mspace height="30px" depth="10px" width="20px" style="background: black"/>
+ <mspace height="15px" depth="45px" width="30px" style="background: black"/>
+ <mprescripts/>
+ <mspace height="60px" depth="20px" width="40px" style="background: black"/>
+ <mprescripts/>
+ <mspace height="25px" depth="75px" width="50px" style="background: black"/>
+ <mspace height="35px" depth="105px" width="70px" style="background: black"/>
+ </mrow>
+ </math>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/mrow-painting-order-ref.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/mrow-painting-order-ref.html
new file mode 100644
index 0000000000..72694959a8
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/mrow-painting-order-ref.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>mrow painting order (reference)</title>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ .container {
+ position: absolute;
+ left: 2em;
+ top: 10em;
+ }
+ math {
+ font: 50px/1 Ahem;
+ }
+ .hidden {
+ visibility: hidden;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if there is no red and content is stacked such that</p>
+ <ul>
+ <li>foreground (dark colors) is above background (light colors)</li>
+ <li>yellow foreground is above green foreground which is itself above blue foreground</li>
+ <li>yellow background is above green background which is itself above blue background</li>
+ </ul>
+ <!-- Paint lightblue background -->
+ <div class="container">
+ <math>
+ <mrow>
+ <mrow style="background: lightblue"><mn class="hidden">XXÉ</mn></mrow>
+ </mrow>
+ </math>
+ </div>
+ <!-- Paint lightgreen background -->
+ <div class="container">
+ <math>
+ <mrow>
+ <mn class="hidden">XXÉX</mn>
+ <mrow style="background: lightgreen; margin-inline-start: -3em"><mn style="visibility: hidden">p&#xA0;XXÉ</mn></mrow>
+ </mrow>
+ </math>
+ </div>
+ <!-- Paint lightyellow background -->
+ <div class="container">
+ <math>
+ <mrow>
+ <mn class="hidden">XXÉX</mn>
+ <mn class="hidden" style="margin-inline-start: -3em">p&#xA0;XXÉX</mn>
+ <mrow style="background: lightyellow; margin-inline-start: -3em"><mn style="visibility: hidden">p&#xA0;X</mn></mrow>
+ </mrow>
+ </math>
+ </div>
+ <!-- Paint blue foreground -->
+ <div class="container">
+ <math>
+ <mrow>
+ <mn style="color: blue;">XXÉ</mn>
+ </mrow>
+ </math>
+ </div>
+ <!-- Paint green foreground -->
+ <div class="container">
+ <math>
+ <mrow>
+ <mn class="hidden">XXÉX</mn>
+ <mn style="color: green; margin-inline-start: -3em">p&#xA0;XXÉ</mn>
+ </mrow>
+ </math>
+ </div>
+ <!-- Paint yellow foreground -->
+ <div class="container">
+ <math>
+ <mrow>
+ <mn class="hidden">XXÉX</mn>
+ <mn class="hidden" style="margin-inline-start: -3em">p&#xA0;XXÉX</mn>
+ <mn style="color: yellow; margin-inline-start: -3em">p&#xA0;X</mn>
+ </mrow>
+ </math>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/mrow-painting-order.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/mrow-painting-order.html
new file mode 100644
index 0000000000..516359a545
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/mrow-painting-order.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>mrow painting order</title>
+ <link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.mfenced">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#stacking-contexts">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#horizontally-group-sub-expressions-mrow">
+ <meta name="assert" content="Verify in which order the children paint">
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <link rel="match" href="mrow-painting-order-ref.html">
+ <style>
+ .container {
+ position: absolute;
+ left: 2em;
+ top: 10em;
+ }
+ math {
+ font: 50px/1 Ahem;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if there is no red and content is stacked such that</p>
+ <ul>
+ <li>foreground (dark colors) is above background (light colors)</li>
+ <li>yellow foreground is above green foreground which is itself above blue foreground</li>
+ <li>yellow background is above green background which is itself above blue background</li>
+ </ul>
+ <div class="container">
+ <math>
+ <mrow>
+ <mn style="color: blue; background: lightblue">XXÉ</mn>
+ <mn style="color: red">X</mn>
+ <mn style="color: green; background: lightgreen; margin-inline-start: -3em">p&#xA0;XXÉ</mn>
+ <mn style="color: red">X</mn>
+ <mn style="color: yellow; background: lightyellow; margin-inline-start: -3em">p&#xA0;X</mn>
+ </mrow>
+ </math>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/mrow-preferred-width.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/mrow-preferred-width.html
new file mode 100644
index 0000000000..8f0e3216c1
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/mrow-preferred-width.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Preferred width of mrow-like elements</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#horizontally-group-sub-expressions-mrow">
+<link rel="help" href="https://w3c.github.io/mathml-core/#style-change-mstyle">
+<link rel="help" href="https://w3c.github.io/mathml-core/#making-sub-expressions-invisible-mphantom">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-top-level-math-element">
+<link rel="help" href="https://w3c.github.io/mathml-core/#adjust-space-around-content-mpadded">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<meta name="assert" content="The preferred width of mrow-like elements is the sum of children's width, modulo extra spacing.">
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script type="text/javascript">
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+ function runTests()
+ {
+ var epsilon = 1;
+
+ function MrowWidthFromChildren(mrow) {
+ var first = mrow.firstElementChild.getBoundingClientRect();
+ var last = mrow.lastElementChild.getBoundingClientRect();
+ return last.right - first.left;
+ }
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ Array.from(document.getElementById("mspace-tests").getElementsByClassName("shrink-wrap")).forEach((container) => {
+ var containerWidth = container.getBoundingClientRect().width;
+ var mrow = container.getElementsByClassName("mrow-like")[0];
+ var mrowWidth = MrowWidthFromChildren(mrow);
+ assert_approx_equals(containerWidth, mrowWidth, epsilon, mrow.tagName);
+ });
+ }, "Preferred width of mrow with mspace children");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+
+ Array.from(document.getElementById("tokens-tests").getElementsByClassName("shrink-wrap")).forEach((container) => {
+ var containerWidth = container.getBoundingClientRect().width;
+ var mrow = container.getElementsByClassName("mrow-like")[0];
+ var mrowWidth = MrowWidthFromChildren(mrow);
+ assert_approx_equals(containerWidth, mrowWidth, epsilon, mrow.tagName);
+ });
+ }, "Preferred width of mrow with mn and mo children");
+
+ done();
+ }
+</script>
+<style>
+div.shrink-wrap {
+ background: yellow;
+ display: inline-block;
+ margin-top: 5px;
+ padding-top: 5px;
+}
+</style>
+</head>
+<body>
+ <div id="log"></div>
+ <div id="mspace-tests">
+ <div><div class="shrink-wrap">
+ <math><mrow class="mrow-like"><mspace width="30px" height="15px" style="background: blue"/><mspace width="20px" depth="30px" style="background: green"/><mspace width="15px" height="5px" depth="10px" style="background: black"/></mrow></math>
+ </div></div>
+ <div>
+ <div class="shrink-wrap">
+ <math><mstyle class="mrow-like"><mspace width="30px" height="15px" style="background: blue"/><mspace width="20px" depth="30px" style="background: green"/><mspace width="15px" height="5px" depth="10px" style="background: black"/></mstyle></math>
+ </div>
+ </div>
+ <div>
+ <div class="shrink-wrap">
+ <math><mphantom class="mrow-like"><mspace width="30px" height="15px" style="background: blue"/><mspace width="20px" depth="30px" style="background: green"/><mspace width="15px" height="5px" depth="10px" style="background: black"/></mphantom></math>
+ </div>
+ </div>
+ <div>
+ <div class="shrink-wrap">
+ <math class="mrow-like"><mspace width="30px" height="15px" style="background: blue"/><mspace width="20px" depth="30px" style="background: green"/><mspace width="15px" height="5px" depth="10px" style="background: black"/></math>
+ </div>
+ </div>
+ <div>
+ <div class="shrink-wrap">
+ <math><unknown class="mrow-like"><mspace width="30px" height="15px" style="background: blue"/><mspace width="20px" depth="30px" style="background: green"/><mspace width="15px" height="5px" depth="10px" style="background: black"/></unknown></math>
+ </div>
+ </div>
+ <div>
+ </div>
+ </div>
+ <div id="tokens-tests">
+ <div>
+ <div class="shrink-wrap">
+ <math><mrow class="mrow-like"><mtext>blah</mtext><mo lspace="30px" rspace="20px">|</mo><mn>2</mn></mrow></math>
+ </div>
+ </div>
+ <div>
+ <div class="shrink-wrap">
+ <math><mstyle class="mrow-like"><mtext>blah</mtext><mo lspace="30px" rspace="20px">|</mo><mn>2</mn></mstyle></math>
+ </div>
+ </div>
+ <div>
+ <div class="shrink-wrap">
+ <math><mphantom class="mrow-like"><mtext>blah</mtext><mo lspace="30px" rspace="20px">|</mo><mn>2</mn></mphantom></math>
+ </div>
+ </div>
+ <div>
+ <div class="shrink-wrap">
+ <math class="mrow-like"><mtext>blah</mtext><mo lspace="30px" rspace="20px">|</mo><mn>2</mn></math>
+ </div>
+ </div>
+ <div>
+ <div class="shrink-wrap">
+ <math><unknown class="mrow-like"><mtext>blah</mtext><mo lspace="30px" rspace="20px">|</mo><mn>2</mn></unknown></math>
+ </div>
+ </div>
+ </div>
+</p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/no-spacing.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/no-spacing.html
new file mode 100644
index 0000000000..a2e7eb7d8d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/no-spacing.html
@@ -0,0 +1,139 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>No spacing in elements</title>
+<meta name="assert" content="Spacing is not added around operators when an element does not use mrow layout. However, when the element is embellished, spacing of the core mo is added around it.">
+<link rel="help" href="https://w3c.github.io/mathml-core/#embellished-operators">
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<link rel="help" href="https://w3c.github.io/mathml-core/#horizontally-group-sub-expressions-mrow">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#prescripts-and-tensor-indices-mmultiscripts">
+<link rel="help" href="https://w3c.github.io/mathml-core/#radicals-msqrt-mroot">
+<link rel="help" href="https://w3c.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+<link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script type="text/javascript">
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ function runTests()
+ {
+ Array.from(document.getElementsByClassName("testedElement")).forEach((e) => {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ let box = e.getBoundingClientRect();
+ let spacing = 100;
+ assert_less_than_equal(box.width, spacing);
+ }, `Spacing inside <${e.tagName}>.`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ let box = e.parentNode.getBoundingClientRect();
+ let spacing = 100;
+ if (e.classList.contains("embellished"))
+ assert_greater_than_equal(box.width, spacing * 2);
+ else
+ assert_less_than_equal(box.width, spacing);
+ }, `Spacing around <${e.tagName}>.`);
+ });
+ done();
+ }
+</script>
+<style>
+ .testedElement {
+ background: lightgreen;
+ }
+ math {
+ background: lightblue;
+ }
+ math, math * {
+ font: 25px/1 Ahem;
+ }
+</style>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mfrac class="testedElement embellished">
+ <mo lspace="100px" rspace="100px">X</mo>
+ <mo lspace="100px" rspace="100px">X</mo>
+ </mfrac>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msub class="testedElement embellished">
+ <mo lspace="100px" rspace="100px">X</mo>
+ <mo lspace="100px" rspace="100px">X</mo>
+ </msub>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msup class="testedElement embellished">
+ <mo lspace="100px" rspace="100px">X</mo>
+ <mo lspace="100px" rspace="100px">X</mo>
+ </msup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msubsup class="testedElement embellished">
+ <mo lspace="100px" rspace="100px">X</mo>
+ <mo lspace="100px" rspace="100px">X</mo>
+ <mo lspace="100px" rspace="100px">X</mo>
+ </msubsup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts class="testedElement embellished">
+ <mo lspace="100px" rspace="100px">X</mo>
+ <mo lspace="100px" rspace="100px">X</mo>
+ <mo lspace="100px" rspace="100px">X</mo>
+ <mprescripts/>
+ <mo lspace="100px" rspace="100px">X</mo>
+ <mo lspace="100px" rspace="100px">X</mo>
+ </mmultiscripts>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munder class="testedElement embellished">
+ <mo lspace="100px" rspace="100px">X</mo>
+ <mo lspace="100px" rspace="100px">X</mo>
+ </munder>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mover class="testedElement embellished">
+ <mo lspace="100px" rspace="100px">X</mo>
+ <mo lspace="100px" rspace="100px">X</mo>
+ </mover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover class="testedElement embellished">
+ <mo lspace="100px" rspace="100px">X</mo>
+ <mo lspace="100px" rspace="100px">X</mo>
+ <mo lspace="100px" rspace="100px">X</mo>
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mroot class="testedElement">
+ <mtext>X</mtext>
+ <mo lspace="100px" rspace="100px">X</mo>
+ </mroot>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/spacing.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/spacing.html
new file mode 100644
index 0000000000..c066f72cde
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/spacing.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Spacing in mrows</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#horizontally-group-sub-expressions-mrow">
+<link rel="help" href="https://w3c.github.io/mathml-core/#radicals-msqrt-mroot">
+<link rel="help" href="https://w3c.github.io/mathml-core/#style-change-mstyle">
+<link rel="help" href="https://w3c.github.io/mathml-core/#error-message-merror">
+<link rel="help" href="https://w3c.github.io/mathml-core/#making-sub-expressions-invisible-mphantom">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-top-level-math-element">
+<link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.menclose">
+<link rel="help" href="https://w3c.github.io/mathml-core/#adjust-space-around-content-mpadded">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<meta name="assert" content="Spacing is added around operators inside mrow-like elements.">
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script type="text/javascript">
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ function runTests()
+ {
+ ["Mrow", "Sqrt", "Style", "Error", "Phantom", "Math", "Menclose", "Mpadded", "Unknown", "Mtd"].forEach((tag) => {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ var mrow = document.getElementById(tag);
+ var mn1 = mrow.firstElementChild.getBoundingClientRect();
+ var mn2 = mrow.lastElementChild.getBoundingClientRect();
+ assert_greater_than_equal(mn2.left - mn1.right, 50);
+ }, `operator spacing inside ${tag}`);
+ });
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math><mrow id="Mrow"><mn>1</mn><mo lspace="50px">|</mo><mn>2</mn></mrow></math>
+ <math><msqrt id="Sqrt"><mn>1</mn><mo lspace="50px">|</mo><mn>2</mn></msqrt></math>
+ <math><mstyle id="Style"><mn>1</mn><mo lspace="50px">|</mo><mn>2</mn></mstyle></math>
+ <math><merror id="Error"><mn>1</mn><mo lspace="50px"></mo><mn>2</mn></merror></math>
+ <math><mphantom id="Phantom"><mn>1</mn><mo lspace="50px">|</mo><mn>2</mn></mphantom></math>
+ <math id="Math"><mn>1</mn><mo lspace="50px">|</mo><mn>2</mn></math>
+ <!-- menclose is treated as <unknown> in MathML Core -->
+ <math><menclose id="Menclose" notation="box"><mn>1</mn><mo lspace="50px">|</mo><mn>2</mn></menclose></math>
+ <math><mpadded id="Mpadded" lspace="10px"><mn>1</mn><mo lspace="50px">|</mo><mn>2</mn></mpadded></math>
+ <math><unknown id="Unknown"><mn>1</mn><mo lspace="50px">|</mo><mn>2</mn></unknown></math>
+ <math><mtable><mtr><mtd id="Mtd"><mn>1</mn><mo lspace="50px">|</mo><mn>2</mn></mtd></mtr></mtable></math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/mrow/stretch-along-block-axis-001.html b/testing/web-platform/tests/mathml/presentation-markup/mrow/stretch-along-block-axis-001.html
new file mode 100644
index 0000000000..31385f5388
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/mrow/stretch-along-block-axis-001.html
@@ -0,0 +1,176 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Stretching operators along the block axis</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#dfn-algorithm-for-stretching-operators-along-the-block-axis">
+<meta name="assert" content="">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math {
+ font: 25px/1 Ahem;
+ }
+ @font-face {
+ font-family: stretchy;
+ src: url("/fonts/math/stretchy.woff");
+ }
+ mo {
+ font-family: stretchy;
+ }
+</style>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+
+ var epsilon = 2;
+ var emToPx = 25;
+ var element;
+
+ test(function() {
+ element = document.getElementById("horizontal_arrow");
+ assert_approx_equals(element.getBoundingClientRect().height, 1 * emToPx, epsilon, "horizontal characters don't stretch vertically");
+
+ element = document.getElementById("vertical_arrow");
+ assert_approx_equals(element.getBoundingClientRect().height, 6 * emToPx, epsilon, "vertical characters stretch vertically");
+ }, `Taking into account stretch axis.`);
+
+ test(function() {
+ element = document.getElementById("non_stretchy_horizontal_arrow");
+ assert_approx_equals(element.getBoundingClientRect().height, 1 * emToPx, epsilon, "horizontal characters don't stretch vertically");
+
+ element = document.getElementById("non_stretchy_vertical_arrow");
+ assert_approx_equals(element.getBoundingClientRect().height, 1 * emToPx, epsilon, "vertical characters stretch vertically");
+ }, `Taking into account stretchy property.`);
+
+ test(function() {
+ // There are only stretchy operators : the maximum of their base sizes
+ // is used as the target size.
+ let tallest_base_size = 2 * emToPx;
+
+ element = document.getElementById("small_vertical");
+ assert_approx_equals(element.getBoundingClientRect().width, .5 * emToPx, epsilon, "small width");
+ assert_approx_equals(element.getBoundingClientRect().height, tallest_base_size, epsilon, "height is the max(.5em, 1em, 2em)");
+
+ element = document.getElementById("medium_vertical");
+ assert_approx_equals(element.getBoundingClientRect().width, 1 * emToPx, epsilon, "normal width");
+ assert_approx_equals(element.getBoundingClientRect().height, tallest_base_size, epsilon, "height is the max(.5em, 1em, 2em)");
+
+ element = document.getElementById("big_vertical");
+ assert_approx_equals(element.getBoundingClientRect().width, 2 * emToPx, epsilon, "large width");
+ assert_approx_equals(element.getBoundingClientRect().height, tallest_base_size, epsilon, "height is the max(.5em, 1em, 2em)");
+
+ }, `Only operators with a stretchy property and block stretch axis.`);
+
+ test(function() {
+ // There are non-stretchy operators : the maximum of their base sizes
+ // is used as the target size. In any case, operators remain at least
+ // as large as their base size.
+
+ element = document.getElementById("smaller_op");
+ assert_approx_equals(element.getBoundingClientRect().width, .5 * emToPx, epsilon, "small width");
+ assert_approx_equals(element.getBoundingClientRect().height, 1.5 * emToPx, epsilon, "height is the max(.5em, 1em)");
+
+ element = document.getElementById("bigger_op");
+ assert_approx_equals(element.getBoundingClientRect().width, 2 * emToPx, epsilon, "large width");
+ assert_approx_equals(element.getBoundingClientRect().height, 2 * emToPx, epsilon, "height is the max(1em, 2em)");
+
+ }, `Operators smaller and larger than non-stretchy siblings.`);
+
+ test(function() {
+ element = document.getElementById("core_operator_1");
+ assert_approx_equals(element.getBoundingClientRect().height, 6 * emToPx, epsilon, "mrow");
+
+ element = document.getElementById("core_operator_2");
+ assert_approx_equals(element.getBoundingClientRect().height, 6 * emToPx, epsilon, "munder");
+
+ element = document.getElementById("core_operator_3");
+ assert_approx_equals(element.getBoundingClientRect().height, 6 * emToPx, epsilon, "mover");
+
+ element = document.getElementById("core_operator_4");
+ assert_approx_equals(element.getBoundingClientRect().height, 6 * emToPx, epsilon, "mundeover");
+
+ element = document.getElementById("core_operator_5");
+ assert_approx_equals(element.getBoundingClientRect().height, 6 * emToPx, epsilon, "complex nesting");
+ }, `Embellished operators`);
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mrow>
+ <mspace width="1em" height="3em" depth="3em" style="background: blue"/>
+ <mo id="horizontal_arrow" stretchy="true">⥚</mo>
+ <mo id="vertical_arrow" stretchy="true">⥜</mo>
+ <mo id="non_stretchy_horizontal_arrow" stretchy="false">⥚</mo>
+ <mo id="non_stretchy_vertical_arrow" stretchy="false">⥜</mo>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <!-- This contains only vertical stretchy operators. -->
+ <mo style="font-size: 50%" id="small_vertical" stretchy="true">⥜</mo>
+ <mo style="font-size: 200%" id="big_vertical" stretchy="true">⥜</mo>
+ <mo style="font-size: 100%" id="medium_vertical" stretchy="true">⥜</mo>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mspace style="background: blue" width="1em" height=".75em"/>
+ <mo style="font-size: 50%" id="smaller_op" stretchy="true">⥜</mo>
+ <mspace style="background: blue" width="1em" height="1.5em"/>
+ <mo style="font-size: 200%" id="bigger_op" stretchy="true">⥜</mo>
+ <mspace style="background: blue" width="1em" height="1em"/>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mspace width="1em" height="3em" depth="3em" style="background: blue"/>
+ <mrow><mo id="core_operator_1" stretchy="true">⥜</mo></mrow>
+ <munder>
+ <mo id="core_operator_2" stretchy="true">⥜</mo>
+ <mspace></mspace>
+ </munder>
+ <mover>
+ <mo id="core_operator_3" stretchy="true">⥜</mo>
+ <mspace></mspace>
+ </mover>
+ <munderover>
+ <mo id="core_operator_4" stretchy="true">⥜</mo>
+ <mspace></mspace>
+ </munderover>
+ <mrow>
+ <mspace></mspace>
+ <munderover>
+ <mover>
+ <munder>
+ <mrow>
+ <mo id="core_operator_5" stretchy="true">⥜</mo>
+ </mrow>
+ <mspace></mspace>
+ </munder>
+ <mspace></mspace>
+ </mover>
+ <mspace></mspace>
+ <mspace></mspace>
+ </munderover>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-001-crash.html b/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-001-crash.html
new file mode 100644
index 0000000000..15e9a0367c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-001-crash.html
@@ -0,0 +1,10 @@
+<!DOCTYPE>
+<!-- See https://github.com/w3c/mathml-core/issues/108 -->
+<math>
+ <mrow style="display: inline">A</mrow>
+</math>
+<math>
+ <mrow>
+ <mrow style="display: inline">A</mrow>
+ </mrow>
+</math>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-001.html b/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-001.html
new file mode 100644
index 0000000000..b8e2cefc1c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-001.html
@@ -0,0 +1,521 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Embellished operators</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#embellished-operators">
+<link rel="help" href="https://w3c.github.io/mathml-core/#definition-of-space-like-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-mrow">
+<meta name="assert" content="Verify definition of embellished operators">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/box-navigation.js"></script>
+<style>
+ /* Default spacing of operator 'X' is 0.2777777777777778em so quite different
+ from the measured/specified 0em and 1em. */
+ math, math * {
+ font: 25px/1 Ahem;
+ }
+ mn {
+ color: black;
+ }
+ .testedElement mo {
+ color: yellow !important;
+ }
+ .testedElement, .testedElement * {
+ color: blue !important;
+ background: blue !important;
+ }
+ .oof1 {
+ position: absolute;
+ }
+ .oof2 {
+ position: fixed;
+ }
+ .nobox {
+ display: none;
+ }
+</style>
+<script>
+ function spaceBeforeElement(id) {
+ var element = document.getElementById(id);
+ var mnBefore = previousInFlowSibling(element);
+ return element.getBoundingClientRect().left - mnBefore.getBoundingClientRect().right;
+ }
+
+ function spaceBeforeCoreOperator(id) {
+ var element = document.getElementById(id);
+ var coreMo = element.getElementsByTagName("mo")[0];
+ return coreMo.getBoundingClientRect().left - element.getBoundingClientRect().left;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+ var epsilon = 1;
+ var emToPx = 25;
+
+ ["mrow", "mstyle", "mphantom", "mpadded", "merror", "mprescripts", "none", "unknown"].forEach(tag => {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBeforeElement(`${tag}-op-1`), 2 * emToPx, epsilon);
+ assert_approx_equals(spaceBeforeCoreOperator(`${tag}-op-1`), 0, epsilon);
+ }, `${tag} (embellished operator)`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBeforeElement(`${tag}-op-2`), 2 * emToPx, epsilon);
+ assert_approx_equals(spaceBeforeCoreOperator(`${tag}-op-2`), 0, epsilon);
+ }, `${tag} (embellished operator, from in-flow children)`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBeforeElement(`${tag}-nonop-1`), 0, epsilon);
+ assert_approx_equals(spaceBeforeCoreOperator(`${tag}-nonop-1`), 2 * emToPx, epsilon);
+ }, `${tag} (not embellished operator)`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBeforeElement(`${tag}-nonop-2`), 0, epsilon);
+ assert_approx_equals(spaceBeforeCoreOperator(`${tag}-nonop-2`), 2 * emToPx, epsilon);
+ }, `${tag} (not embellished operator, from in-flow children)`);
+ });
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <!-- mrow is an embellished operator if its in-flow children consist
+ of one embellished operator and zero or more space-like elements. -->
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow id="mrow-op-1" class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mtext class="space-like">X</mtext>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow id="mrow-nonop-1" class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn> <!-- "mn" is not space-like -->
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mrow id="mrow-op-2" class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext class="space-like">X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mrow>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mrow id="mrow-nonop-2" class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn> <!-- "mn" is not space-like -->
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mrow>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <!-- mstyle is an embellished operator if its in-flow children consist
+ of one embellished operator and zero or more space-like elements. -->
+ <p>
+ <math>
+ <mn>X</mn>
+ <mstyle id="mstyle-op-1" class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ </mstyle>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mstyle id="mstyle-nonop-1" class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn> <!-- "mn" is not space-like -->
+ </mstyle>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mstyle id="mstyle-op-2" class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mstyle>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mstyle id="mstyle-nonop-2" class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn> <!-- "mn" is not space-like -->
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mstyle>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <!-- mphantom is an embellished operator if its in-flow children consist
+ of one embellished operator and zero or more space-like elements. -->
+ <p>
+ <math>
+ <mn>X</mn>
+ <mphantom id="mphantom-op-1" class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ </mphantom>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mphantom id="mphantom-nonop-1" class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn> <!-- "mn" is not space-like -->
+ </mphantom>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mphantom id="mphantom-op-2" class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mphantom>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mphantom id="mphantom-nonop-2" class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn> <!-- "mn" is not space-like -->
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mphantom>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <!-- mpadded is an embellished operator if its in-flow children consist
+ of one embellished operator and zero or more space-like elements. -->
+ <p>
+ <math>
+ <mn>X</mn>
+ <mpadded id="mpadded-op-1" class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ </mpadded>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mpadded id="mpadded-nonop-1" class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn> <!-- "mn" is not space-like -->
+ </mpadded>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mpadded id="mpadded-op-2" class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mpadded>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mpadded id="mpadded-nonop-2" class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn> <!-- "mn" is not space-like -->
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mpadded>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <!-- merror is an embellished operator if its in-flow children consist
+ of one embellished operator and zero or more space-like elements. -->
+ <p>
+ <math>
+ <mn>X</mn>
+ <merror id="merror-op-1" class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ </merror>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <merror id="merror-nonop-1" class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn> <!-- "mn" is not space-like -->
+ </merror>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <merror id="merror-op-2" class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </merror>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <merror id="merror-nonop-2" class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn> <!-- "mn" is not space-like -->
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </merror>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <!-- mprescripts is an embellished operator if its in-flow children consist
+ of one embellished operator and zero or more space-like elements. -->
+ <p>
+ <math>
+ <mn>X</mn>
+ <mprescripts id="mprescripts-op-1" class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ </mprescripts>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mprescripts id="mprescripts-nonop-1" class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn> <!-- "mn" is not space-like -->
+ </mprescripts>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mprescripts id="mprescripts-op-2" class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mprescripts>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mprescripts id="mprescripts-nonop-2" class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn> <!-- "mn" is not space-like -->
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mprescripts>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <!-- none is an embellished operator if its in-flow children consist
+ of one embellished operator and zero or more space-like elements. -->
+ <p>
+ <math>
+ <mn>X</mn>
+ <none id="none-op-1" class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ </none>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <none id="none-nonop-1" class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn> <!-- "mn" is not space-like -->
+ </none>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <none id="none-op-2" class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </none>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <none id="none-nonop-2" class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn> <!-- "mn" is not space-like -->
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </none>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <!-- unknown is an embellished operator if its in-flow children consist
+ of one embellished operator and zero or more space-like elements. -->
+ <p>
+ <math>
+ <mn>X</mn>
+ <unknown id="unknown-op-1" class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ </unknown>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <unknown id="unknown-nonop-1" class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn> <!-- "mn" is not space-like -->
+ </unknown>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <unknown id="unknown-op-2" class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </unknown>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <unknown id="unknown-nonop-2" class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn> <!-- "mn" is not space-like -->
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </unknown>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-002.html b/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-002.html
new file mode 100644
index 0000000000..7ab05441c3
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-002.html
@@ -0,0 +1,559 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Embellished operators</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#embellished-operators">
+<link rel="help" href="https://w3c.github.io/mathml-core/#definition-of-space-like-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-mrow">
+<meta name="assert" content="Verify definition of embellished operators">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/box-navigation.js"></script>
+<style>
+ /* Default spacing of operator 'X' is 0.2777777777777778em so quite different
+ from the measured/specified 0em and 1em. */
+ math, math * {
+ font: 25px/1 Ahem;
+ }
+ mn {
+ color: black;
+ }
+ mtext.space-like {
+ color: lightblue !important;
+ }
+ .testedElement mo {
+ color: yellow !important;
+ }
+ .testedElement, .testedElement * {
+ color: blue !important;
+ background: blue !important;
+ }
+ .oof1 {
+ position: absolute;
+ }
+ .oof2 {
+ position: fixed;
+ }
+ .nobox {
+ display: none;
+ }
+</style>
+<script>
+ function spaceBeforeElement(element) {
+ var mnBefore = previousInFlowSibling(element);
+ return element.getBoundingClientRect().left - mnBefore.getBoundingClientRect().right;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+ var epsilon = 1;
+ var emToPx = 25;
+
+ ["msub", "msup", "msubsup", "munder", "mover", "munderover",
+ "mmultiscripts", "mfrac"].forEach(tag => {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ var element = document.getElementsByTagName(tag)[0];
+ assert_approx_equals(spaceBeforeElement(element), 2 * emToPx, epsilon);
+ }, `${tag} (embellished operator)`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ var element = document.getElementsByTagName(tag)[1];
+ assert_approx_equals(spaceBeforeElement(element), 2 * emToPx, epsilon);
+ }, `${tag} (embellished operator, from in-flow children)`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ var element = document.getElementsByTagName(tag)[2];
+ assert_approx_equals(spaceBeforeElement(element), 0, epsilon);
+ }, `${tag} (not embellished operator)`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ var element = document.getElementsByTagName(tag)[3];
+ assert_approx_equals(spaceBeforeElement(element), 0, epsilon);
+ }, `${tag} (not embellished operator, from in-flow children)`);
+ });
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <!-- <msub>, <msup>, <msubsup>, <munder>, <mover>, <munderover>,
+ <mmultiscripts>, <mfrac> are embellished
+ operators if their first in-flow
+ child exists and is an embellished operator -->
+ <p>
+ <math>
+ <mn>X</mn>
+ <msub class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn>
+ </msub>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <msup class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn>
+ </msup>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <msubsup class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn>
+ <mn>X</mn>
+ </msubsup>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <munder class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn>
+ </munder>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mover class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn>
+ </mover>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <munderover class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn>
+ </munderover>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mmultiscripts class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn>
+ <mn>X</mn>
+ <mn>X</mn>
+ <mn>X</mn>
+ </mmultiscripts>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mfrac class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn>
+ </mfrac>
+ <mn>X</mn>
+ </math>
+ </p>
+
+ <!-- Only in-flow children affect determination of embellished operators. -->
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <msub class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </msub>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <msup class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </msup>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <msubsup class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </msubsup>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <munder class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </munder>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mover class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mover>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <munderover class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </munderover>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mmultiscripts class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mmultiscripts>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mfrac class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mfrac>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+
+ <!-- <msub>, <msup>, <msubsup>, <munder>, <mover>, <munderover>,
+ <mmultiscripts>, <mfrac> are not embellished
+ operators if their first in-flow child is not an embellished operator -->
+ <p>
+ <math>
+ <mn>X</mn>
+ <msub class="testedElement">
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ </msub>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <msup class="testedElement">
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ </msup>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <msubsup class="testedElement">
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn>
+ </msubsup>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <munder class="testedElement">
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ </munder>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mover class="testedElement">
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ </mover>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <munderover class="testedElement">
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ </munderover>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mmultiscripts class="testedElement">
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn>
+ <mn>X</mn>
+ <mn>X</mn>
+ </mmultiscripts>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mfrac class="testedElement">
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ </mfrac>
+ <mn>X</mn>
+ </math>
+ </p>
+
+ <!-- Only in-flow children affect determination of embellished operators. -->
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <msub class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </msub>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <msup class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </msup>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <msubsup class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </msubsup>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <munder class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </munder>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mover class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mover>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <munderover class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </munderover>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mmultiscripts class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mmultiscripts>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mfrac class="testedElement">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mfrac>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-003.html b/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-003.html
new file mode 100644
index 0000000000..7b36665787
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-003.html
@@ -0,0 +1,394 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Embellished operators</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#embellished-operators">
+<link rel="help" href="https://w3c.github.io/mathml-core/#definition-of-space-like-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-mrow">
+<meta name="assert" content="Verify definition of embellished operators">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/box-navigation.js"></script>
+<style>
+ /* Default spacing of operator 'X' is 0.2777777777777778em so quite different
+ from the measured/specified 0em and 1em. */
+ math, math * {
+ font: 25px/1 Ahem;
+ }
+ mn {
+ color: black;
+ }
+ mtext.space-like {
+ color: lightblue !important;
+ }
+ .testedElement mo {
+ color: yellow !important;
+ }
+ .testedElement, .testedElement * {
+ color: blue !important;
+ background: blue !important;
+ }
+ .oof1 {
+ position: absolute;
+ }
+ .oof2 {
+ position: fixed;
+ }
+ .nobox {
+ display: none;
+ }
+ .allChildrenVisible > *:not(.nobox) {
+ display: inline math;
+ }
+</style>
+<script>
+ function spaceBeforeElement(element) {
+ var mnBefore = previousInFlowSibling(element);
+ return element.getBoundingClientRect().left - mnBefore.getBoundingClientRect().right;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+ var epsilon = 1;
+ var emToPx = 25;
+
+ ["maction", "semantics"].forEach(tag => {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ var element = document.getElementsByTagName(tag)[0];
+ assert_approx_equals(spaceBeforeElement(element), 2 * emToPx, epsilon);
+ }, `${tag} (embellished operator)`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ var element = document.getElementsByTagName(tag)[1];
+ assert_approx_equals(spaceBeforeElement(element), 2 * emToPx, epsilon);
+ }, `${tag} (embellished operator, from in-flow children)`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ var element = document.getElementsByTagName(tag)[2];
+ assert_approx_equals(spaceBeforeElement(element), 0, epsilon);
+ }, `${tag} (not embellished operator)`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ var element = document.getElementsByTagName(tag)[3];
+ assert_approx_equals(spaceBeforeElement(element), 0, epsilon);
+ }, `${tag} (not embellished operator, from in-flow children)`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ var element = document.getElementsByTagName(tag)[4];
+ assert_approx_equals(spaceBeforeElement(element), 0, epsilon);
+ }, `${tag} (not embellished operator, empty)`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ var element = document.getElementsByTagName(tag)[5];
+ assert_approx_equals(spaceBeforeElement(element), 2 * emToPx, epsilon);
+ }, `${tag} (embellished operator, one child)`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ var element = document.getElementsByTagName(tag)[6];
+ assert_approx_equals(spaceBeforeElement(element), 2 * emToPx, epsilon);
+ }, `${tag} (embellished operator, complex)`);
+ });
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <!-- <semantics> or <maction> are embellished operators if their children
+ consist (in any order) of one embellished operator and zero or more
+ space-like elements. -->
+ <p>
+ <math>
+ <mn>X</mn>
+ <maction class="testedElement" actiontype="statusline">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>STATUS MESSAGE</mn>
+ </maction>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <semantics class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <annotation>TEXT ANNOTATION</annotation>
+ <mn>X</mn>
+ </semantics>
+ <mn>X</mn>
+ </math>
+ </p>
+
+ <!-- Only in-flow children affect determination of embellished operators. -->
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <maction class="testedElement" actiontype="statusline">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>STATUS MESSAGE</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </maction>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <semantics class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <annotation>TEXT ANNOTATION</annotation>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </semantics>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+
+ <!-- <semantics> or <maction> are not embellished
+ operators if their first in-flow child is not an embellished operator -->
+ <p>
+ <math>
+ <mn>X</mn>
+ <msub class="testedElement">
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ </msub>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <msup class="testedElement">
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ </msup>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <msubsup class="testedElement">
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn>
+ </msubsup>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <munder class="testedElement">
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ </munder>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mover class="testedElement">
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ </mover>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <munderover class="testedElement">
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ </munderover>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mmultiscripts class="testedElement">
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn>X</mn>
+ <mn>X</mn>
+ <mn>X</mn>
+ </mmultiscripts>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mfrac class="testedElement">
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ </mfrac>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <maction class="testedElement" actiontype="statusline">
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">STATUS MESSAGE</mo>
+ </maction>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <semantics class="testedElement">
+ <mrow>
+ <mn>X</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ </mrow>
+ <annotation>TEXT ANNOTATION</annotation>
+ </semantics>
+ <mn>X</mn>
+ </math>
+ </p>
+
+ <!-- Only in-flow children affect determination of embellished operators. -->
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <maction class="testedElement" actiontype="statusline">
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">STATUS MESSAGE</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </maction>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <semantics class="testedElement">
+ <mrow>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mrow>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <annotation>TEXT ANNOTATION</annotation>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </semantics>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+
+ <!-- Empty <maction> and <semantics> (invalid in MathML3). -->
+ <p>
+ <math>
+ <mn>X</mn>
+ <maction class="testedElement">
+ </maction>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <semantics class="testedElement">
+ </semantics>
+ <mn>X</mn>
+ </math>
+ </p>
+
+ <!-- One-child <maction> and <semantics> (invalid in MathML3). -->
+ <p>
+ <math>
+ <mn>X</mn>
+ <maction class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ </maction>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <semantics class="testedElement">
+ <mo lspace="2em" rspace="0em">X</mo>
+ </semantics>
+ <mn>X</mn>
+ </math>
+ </p>
+
+ <!-- Complex structure (invalid in MathML3). -->
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <maction class="testedElement allChildrenVisible">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext class="space-like">X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </maction>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <semantics class="testedElement allChildrenVisible">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="2em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext class="space-like">X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </semantics>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-dynamic-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-dynamic-001-ref.html
new file mode 100644
index 0000000000..b37ce125a7
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-dynamic-001-ref.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Embellished operators - tree change and relayout (reference)</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ math, math * {
+ font: 25px/1 Ahem;
+ }
+ mn {
+ color: black;
+ }
+ mo {
+ color: blue;
+ }
+</style>
+</head>
+<body>
+ <p>There should be the five 1em squares on the same line, with colors
+ black, orange, blue, orange, black:</p>
+ <math display="block">
+ <mrow style="background: yellow">
+ <mn>1</mn>
+ <mrow style="background: orange">
+ <mrow id="change_to_non_embellished_operator">
+ <mrow>
+ <mo lspace="1em" rspace="1em">X</mo>
+ </mrow>
+ <mn></mn>
+ </mrow>
+ </mrow>
+ <mn>2</mn>
+ </mrow>
+ </math>
+
+ <p>There should be the five 1em squares on the same line, with colors
+ black, yellow, blue, yellow, black:</p>
+ <math display="block">
+ <mrow style="background: yellow">
+ <mn>3</mn>
+ <mrow style="background: orange">
+ <mrow id="change_to_embellished_operator">
+ <mrow>
+ <mo lspace="1em" rspace="1em">X</mo>
+ </mrow>
+ </mrow>
+ </mrow>
+ <mn>4</mn>
+ </mrow>
+ </math>
+
+ <p>There should be the five 1em squares on the same line, with colors
+ black, orange, blue, orange, black:</p>
+ <math display="block">
+ <mrow style="background: yellow">
+ <mn>5</mn>
+ <mrow style="background: orange">
+ <mrow>
+ <mrow>
+ <mo lspace="1em" rspace="1em">X</mo>
+ </mrow>
+ </mrow>
+ <mrow id="change_to_not_space_like">
+ <mspace></mspace>
+ <mtext></mtext>
+ <mn></mn>
+ </mrow>
+ </mrow>
+ <mn>6</mn>
+ </mrow>
+ </math>
+
+ <p>There should be the five 1em squares on the same line, with colors
+ black, yellow, blue, yellow, black:</p>
+ <math display="block">
+ <mrow style="background: yellow">
+ <mn>7</mn>
+ <mrow style="background: orange">
+ <mrow>
+ <mrow>
+ <mo lspace="1em" rspace="1em">X</mo>
+ </mrow>
+ <mrow id="change_to_space_like">
+ <mspace></mspace>
+ <mtext></mtext>
+ </mrow>
+ </mrow>
+ </mrow>
+ <mn>8</mn>
+ </mrow>
+ </math>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-dynamic-001.html b/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-dynamic-001.html
new file mode 100644
index 0000000000..09a7fe412a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-dynamic-001.html
@@ -0,0 +1,123 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>Embellished operators - tree change and relayout</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#embellished-operators">
+<link rel="help" href="https://w3c.github.io/mathml-core/#definition-of-space-like-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-mrow">
+<script src="/mathml/support/mathml-fragments.js"></script>
+<meta name="assert" content="Verify relayout of an mrow with a child that has a deeply nested <mo> element.">
+<link rel="match" href="embellished-operator-dynamic-001-ref.html">
+<style>
+ math, math * {
+ font: 25px/1 Ahem;
+ }
+ mn {
+ color: black;
+ }
+ mo {
+ color: blue;
+ }
+</style>
+</head>
+<body>
+ <p>There should be the five 1em squares on the same line, with colors
+ black, orange, blue, orange, black:</p>
+ <math display="block">
+ <mrow style="background: yellow">
+ <mn>1</mn>
+ <mrow style="background: orange">
+ <mrow id="change_to_not_embellished_operator">
+ <mrow>
+ <mo lspace="1em" rspace="1em">X</mo>
+ </mrow>
+ </mrow>
+ </mrow>
+ <mn>2</mn>
+ </mrow>
+ </math>
+
+ <p>There should be the five 1em squares on the same line, with colors
+ black, yellow, blue, yellow, black:</p>
+ <math display="block">
+ <mrow style="background: yellow">
+ <mn>3</mn>
+ <mrow style="background: orange">
+ <mrow id="change_to_embellished_operator">
+ <mrow>
+ <mo lspace="1em" rspace="1em">X</mo>
+ </mrow>
+ <mn></mn>
+ </mrow>
+ </mrow>
+ <mn>4</mn>
+ </mrow>
+ </math>
+
+ <p>There should be the five 1em squares on the same line, with colors
+ black, orange, blue, orange, black:</p>
+ <math display="block">
+ <mrow style="background: yellow">
+ <mn>5</mn>
+ <mrow style="background: orange">
+ <mrow>
+ <mrow>
+ <mo lspace="1em" rspace="1em">X</mo>
+ </mrow>
+ </mrow>
+ <mrow id="change_to_not_space_like">
+ <mspace></mspace>
+ <mtext></mtext>
+ </mrow>
+ </mrow>
+ <mn>6</mn>
+ </mrow>
+ </math>
+
+ <p>There should be the five 1em squares on the same line, with colors
+ black, yellow, blue, yellow, black:</p>
+ <math display="block">
+ <mrow style="background: yellow">
+ <mn>7</mn>
+ <mrow style="background: orange">
+ <mrow>
+ <mrow>
+ <mo lspace="1em" rspace="1em">X</mo>
+ </mrow>
+ <mrow id="change_to_space_like">
+ <mspace></mspace>
+ <mtext></mtext>
+ <mn></mn>
+ </mrow>
+ </mrow>
+ </mrow>
+ <mn>8</mn>
+ </mrow>
+ </math>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>
+ MathMLFeatureDetection.ensure_for_match_reftest("has_operator_spacing");
+
+ // After adding a not space-like element to mrow1, it is no longer an
+ // embellished operator : lspace/rspace should be around its mrow child.
+ let mrow1 = document.getElementById("change_to_not_embellished_operator");
+ mrow1.appendChild(FragmentHelper.createElement("mn"));
+
+ // Removing the not space-like element from mrow2 makes its orange parent
+ // an embellished operator. lspace/rspace should be around this parent.
+ let mrow2 = document.getElementById("change_to_embellished_operator");
+ mrow2.removeChild(mrow2.lastElementChild);
+
+ // Same as above, but changing the space-like nature of one child.
+ let mrow3 = document.getElementById("change_to_not_space_like");
+ mrow3.appendChild(FragmentHelper.createElement("mn"));
+ let mrow4 = document.getElementById("change_to_space_like");
+ mrow4.removeChild(mrow4.lastElementChild);
+
+ document.documentElement.classList.remove('reftest-wait');
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-dynamic-002.html b/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-dynamic-002.html
new file mode 100644
index 0000000000..2c52684765
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/embellished-operator-dynamic-002.html
@@ -0,0 +1,185 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Embellished operators - tree change and relayout</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#embellished-operators">
+<link rel="help" href="https://w3c.github.io/mathml-core/#definition-of-space-like-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-mrow">
+<link rel="help" href="https://chromium-review.googlesource.com/c/chromium/src/+/3059456">
+<meta name="assert" content="Verify relayout of an mrow with a child that has a deeply nested <mo> element.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math, math * {
+ font: 25px/1 Ahem;
+ }
+ mn {
+ color: black;
+ }
+ .relative_positioned_and_fixed_size {
+ position: relative;
+ height: 0px;
+ width: 0px;
+ overflow: scroll;
+ }
+</style>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ var epsilon = 1;
+ var emToPx = 25;
+
+ function assertCorrectSpacing(container,
+ zero_size_mrow_is_embellished_op) {
+ // The container should add lspace/rspace around the zero size mrow
+ // if and only if that mrow is an embellished operator.
+ let mnBefore = container.children[0].getBoundingClientRect();
+ let zeroSizeMrow = container.children[1].getBoundingClientRect();
+ let mnAfter = container.children[2].getBoundingClientRect();
+ assert_approx_equals(zeroSizeMrow.left - mnBefore.right,
+ zero_size_mrow_is_embellished_op ?
+ emToPx * 1 : 0, epsilon,
+ "lspace");
+ assert_approx_equals(mnAfter.left - zeroSizeMrow.right,
+ zero_size_mrow_is_embellished_op ?
+ emToPx * 2 : 0, epsilon,
+ "rspace");
+ }
+
+ let container1 = document.getElementById("container1");
+ test(function() {
+ assertCorrectSpacing(container1, true);
+ }, "container1: Initially an embellished operator");
+
+ let container2 = document.getElementById("container2");
+ test(function() {
+ assertCorrectSpacing(container2, false);
+ }, "container2: Initially not an embellished operator");
+
+ test(function() {
+ let mrow1 = document.getElementById("change_to_not_embellished_operator");
+ mrow1.appendChild(FragmentHelper.createElement("mn"));
+ assertCorrectSpacing(container1, false);
+ }, " container1: No longer an embellished operator");
+
+ test(function() {
+ let mrow2 = document.getElementById("change_to_embellished_operator");
+ mrow2.removeChild(mrow2.lastElementChild);
+ assertCorrectSpacing(container2, true);
+ }, "container2: Became an embellished operator");
+
+ let container3 = document.getElementById("container3");
+ test(function() {
+ assertCorrectSpacing(container3, true);
+ }, "container3: Initially an embellished operator (testing space-like)");
+
+ let container4 = document.getElementById("container4");
+ test(function() {
+ assertCorrectSpacing(container4, false);
+ }, "container4/space-like: Initially not an embellished operator (testing space-like)");
+
+ test(function() {
+ let mrow = document.getElementById("change_to_not_space_like");
+ mrow.appendChild(FragmentHelper.createElement("mn"));
+ assertCorrectSpacing(container3, false);
+ }, " container3: No longer an embellished operator (testing space-like)");
+
+ test(function() {
+ let mrow = document.getElementById("change_to_space_like");
+ mrow.removeChild(mrow.lastElementChild);
+ assertCorrectSpacing(container4, true);
+ }, "container4: Became an embellished operator (testing space-like)");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+
+ <div>
+ <math display="block">
+ <mrow id="container1">
+ <mn>1</mn>
+ <mrow class="relative_positioned_and_fixed_size">
+ <mrow id="change_to_not_embellished_operator">
+ <mrow>
+ <mo lspace="1em" rspace="2em"></mo>
+ </mrow>
+ </mrow>
+ </mrow>
+ <mn>2</mn>
+ </mrow>
+ </math>
+ </div>
+
+ <div>
+ <math display="block">
+ <mrow id="container2">
+ <mn>3</mn>
+ <mrow class="relative_positioned_and_fixed_size">
+ <mrow id="change_to_embellished_operator">
+ <mrow>
+ <mo lspace="1em" rspace="2em"></mo>
+ </mrow>
+ <mn></mn>
+ </mrow>
+ </mrow>
+ <mn>4</mn>
+ </mrow>
+ </math>
+ </div>
+
+ <div>
+ <math display="block">
+ <mrow id="container3">
+ <mn>5</mn>
+ <mrow>
+ <mrow>
+ <mrow>
+ <mo lspace="1em" rspace="2em"></mo>
+ </mrow>
+ <mrow class="relative_positioned_and_fixed_size">
+ <mrow id="change_to_not_space_like">
+ <mspace></mspace>
+ <mtext></mtext>
+ </mrow>
+ </mrow>
+ </mrow>
+ </mrow>
+ <mn>6</mn>
+ </mrow>
+ </math>
+ </div>
+
+ <div>
+ <math display="block">
+ <mrow id="container4">
+ <mn>7</mn>
+ <mrow>
+ <mrow>
+ <mrow>
+ <mo lspace="1em" rspace="2em"></mo>
+ </mrow>
+ <mrow class="relative_positioned_and_fixed_size">
+ <mrow id="change_to_space_like">
+ <mspace></mspace>
+ <mtext></mtext>
+ <mn></mn>
+ </mrow>
+ </mrow>
+ </mrow>
+ </mrow>
+ <mn>8</mn>
+ </mrow>
+ </math>
+ </div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/largeop-hit-testing.html b/testing/web-platform/tests/mathml/presentation-markup/operators/largeop-hit-testing.html
new file mode 100644
index 0000000000..2b81eb692a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/largeop-hit-testing.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Test hit testing on large operators</title>
+<meta name="assert" content="Verify that hit testing works on large operators.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/largeop-displayoperatorminheight5000.woff");
+ }
+ mo {
+ font-family: TestFont;
+ font-size: 16px;
+ }
+</style>
+<script>
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+
+ let bbox = getBox("largeop");
+ let hit = document.getElementById("largeop");
+ let reference = getBox("reference");
+ assert_true(bbox.height > reference.height, "height of large op is bigger than the equivalent normal operator");
+ assert_equals(hit, document.elementFromPoint(bbox.left + 1, bbox.top + 1), "hit testing top-left corner of large op works");
+ assert_equals(hit, document.elementFromPoint(bbox.right - 1, bbox.bottom - 1), "hit testing bottom-right corner of large op works");
+ }, "Large op hit testing");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <math>
+ <mtable>
+ <mtr>
+ <mtd>
+ <mstyle displaystyle="false">
+ <mo id="reference">&#x2AFF;</mo>
+ </mstyle>
+ </mtd>
+ <mtd>
+ <mstyle displaystyle="true">
+ <mo id="largeop">&#x2AFF;</mo>
+ </mstyle>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-axis-height-1.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-axis-height-1.html
new file mode 100644
index 0000000000..6de6284188
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-axis-height-1.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mo axis height</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<meta name="assert" content="Element mo correctly uses the axis height parameter from the MATH table.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math, mspace {
+ font-size: 10px;
+ }
+ @font-face {
+ font-family: axisheight5000-verticalarrow14000;
+ src: url("/fonts/math/axisheight5000-verticalarrow14000.woff");
+ }
+</style>
+<script>
+ var emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+ var epsilon = 5;
+
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ var v1 = 5000 * emToPx;
+ var moMiddle = (getBox("mo1").bottom + getBox("mo1").top) / 2;
+ assert_approx_equals(getBox("mo1").height,
+ 14000 * emToPx, epsilon, "mo: size");
+ assert_approx_equals(getBox("baseline1").bottom - moMiddle,
+ v1, epsilon, "mo: axis height");
+ }, "AxisHeight (size variant)");
+
+ test(function() {
+ var v1 = 5000 * emToPx;
+ var moMiddle = (getBox("mo2").bottom + getBox("mo2").top) / 2;
+ assert_approx_equals(getBox("mo2").height,
+ 2 * (getBox("target2").height - v1),
+ epsilon, "mo: size");
+ assert_approx_equals(getBox("baseline2").bottom - moMiddle,
+ v1, epsilon, "mo: axis height");
+ }, "AxisHeight (glyph assembly)");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math style="font-family: axisheight5000-verticalarrow14000;">
+ <mrow>
+ <mspace id="baseline1" style="background: blue" width="50px" height="1px"/>
+ <mpadded voffset="50px"><mspace style="background: cyan" width="50px" height="1px"/></mpadded>
+ <mo id="mo1" symmetric="true" style="color: green">&#x21A8;</mo>
+ <mspace style="background: gray" width="10px" height="50px"/>
+ </mrow>
+ </math>
+ <math style="font-family: axisheight5000-verticalarrow14000;">
+ <mrow>
+ <mspace id="baseline2" style="background: blue" width="50px" height="1px"/>
+ <mpadded voffset="50px"><mspace style="background: cyan" width="50px" height="1px"/></mpadded>
+ <mo id="mo2" symmetric="true" style="color: green">&#x21A8;</mo>
+ <mspace id="target2" style="background: gray" width="10px" height="200px"/>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-font-relative-lengths-001.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-font-relative-lengths-001.html
new file mode 100644
index 0000000000..209e59ee33
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-font-relative-lengths-001.html
@@ -0,0 +1,114 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Font-relative lengths on an operator</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#embellished-operators">
+<link rel="help" href="https://w3c.github.io/mathml-core/#definition-of-space-like-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-mrow">
+<meta name="assert" content="Verify font-relative lengths refer to the core operator, not the embellished operator">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math {
+ font: 100px/1 Ahem;
+ }
+ @font-face {
+ font-family: operators;
+ src: url("/fonts/math/operators.woff");
+ }
+ mo {
+ font-family: operators;
+ }
+</style>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ var epsilon = 1;
+ var baseSizePx = 100;
+
+ test(function() {
+ var beforeRight = document.getElementById("before1").getBoundingClientRect().right;
+ var afterLeft = document.getElementById("after1").getBoundingClientRect().left;
+ var fontScalePercent = .5;
+ var lspaceEm = 1;
+ var moWidthEm = 1;
+ assert_approx_equals(afterLeft - beforeRight, baseSizePx * fontScalePercent * (lspaceEm + moWidthEm), epsilon, "baseSizePx * fontScalePercent * lspaceEm");
+ }, `font-relative lspace refers to the core operator`);
+
+ test(function() {
+ var beforeRight = document.getElementById("before2").getBoundingClientRect().right;
+ var afterLeft = document.getElementById("after2").getBoundingClientRect().left;
+ var fontScalePercent = 2;
+ var rspaceEm = 1;
+ var moWidthEm = 1;
+ assert_approx_equals(afterLeft - beforeRight, baseSizePx * fontScalePercent * (rspaceEm + moWidthEm), epsilon, "baseSizePx * fontScalePercent * rspaceEm");
+ }, `font-relative rspace refers to the core operator`);
+
+ test(function() {
+ var moStretchSize = document.getElementById("operator1").getBoundingClientRect().height;
+ var fontScalePercent = .5;
+ var minsizeEm = 8;
+ var beforeHeight = document.getElementById("before1").getBoundingClientRect().height;
+
+ assert_approx_equals(moStretchSize, baseSizePx * minsizeEm * fontScalePercent, epsilon, "baseSizePx * fontScalePercent * minsizeEm");
+
+ // This is really testing the same thing but do make sure minsize is
+ // applied i.e. the unconstrained target size is less than the actual
+ // stretch size.
+ assert_approx_equals(beforeHeight, moStretchSize / 2, epsilon);
+
+ }, `font-relative minsize refers to the core operator`);
+
+ test(function() {
+ var moStretchSize = document.getElementById("operator2").getBoundingClientRect().height;
+ var fontScalePercent = 2;
+ var maxsizeEm = 1;
+ var afterHeight = document.getElementById("after2").getBoundingClientRect().height;
+
+ assert_approx_equals(moStretchSize, baseSizePx * maxsizeEm * fontScalePercent, epsilon, "baseSizePx * fontScalePercent * maxsizeEm");
+
+ // This is really testing the same thing but do make sure maxsize is
+ // applied i.e. the unconstrained target size is more than the actual
+ // stretch size.
+ assert_approx_equals(afterHeight, 2 * moStretchSize, epsilon);
+
+ }, `font-relative maxsize refers to the core operator`);
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mrow>
+ <mspace id="before1" width="1em" height="1em" depth="1em" style="background: blue"/>
+ <mrow style="font-size: 50%;">
+ <mo id="operator1" lspace="1em" rspace="0em" minsize="8em">⥯</mo>
+ <mspace id="after1" width="1em" height=".5em" depth=".5em" style="background: green"/>
+ </mrow>
+ <mn><!-- not space like --></mn>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mrow style="font-size: 200%">
+ <mspace id="before2" width="1em" height=".5em" depth=".5em" style="background: green"/>
+ <mo id="operator2" lspace="0em" rspace="1em" maxsize="1em">⥯</mo>
+ </mrow>
+ <mspace id="after2" width="1em" height="2em" depth="2em" style="background: blue"/>
+ <mn><!-- not space like --></mn>
+ </mrow>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-dynamic-002-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-dynamic-002-ref.html
new file mode 100644
index 0000000000..be7f5aa173
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-dynamic-002-ref.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>&lt;mo&gt; dynamic form</title>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math, math * {
+ font: 60px/1 Ahem;
+ }
+ mo {
+ color: blue;
+ }
+ </style>
+ </head>
+ <body>
+ <p>
+ <math>
+ <mn>1</mn><mo id="infix_attach_prefix" form="prefix">+</mo><mn>2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mo id="prefix_attach_infix" form="infix">+</mo><mn>3</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>1</mn><mo id="infix_remove">+</mo><mn>2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mo id="prefix_remove">+</mo><mn>3</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>1</mn><mo id="infix_set_to_prefix" form="prefix">+</mo><mn>2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mo id="prefix_set_to_infix" form="infix">+</mo><mn>3</mn>
+ </math>
+ </p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-dynamic-002.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-dynamic-002.html
new file mode 100644
index 0000000000..862fc36a20
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-dynamic-002.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8">
+ <title>&lt;mo&gt; dynamic form</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <meta name="assert" content="Verifies that the form (and thus spacing) can be changed dynamically">
+ <link rel="match" href="mo-form-dynamic-002-ref.html">
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math, math * {
+ font: 60px/1 Ahem;
+ }
+ mo {
+ color: blue;
+ }
+ </style>
+ <script>
+ window.addEventListener("load", () => {
+ document.getElementById("infix_attach_prefix").setAttribute("form", "prefix");
+ document.getElementById("prefix_attach_infix").setAttribute("form", "infix");
+ document.getElementById("infix_remove").removeAttribute("form");
+ document.getElementById("prefix_remove").removeAttribute("form");
+ document.getElementById("infix_set_to_prefix").setAttribute("form", "prefix");
+ document.getElementById("prefix_set_to_infix").setAttribute("form", "infix");
+ document.documentElement.classList.remove("reftest-wait");
+ });
+ </script>
+ </head>
+ <body>
+ <!-- Prefix and infix forms of "+" have different default spacing in
+ the operator dictionary. -->
+ <p>
+ <math>
+ <mn>1</mn><mo id="infix_attach_prefix">+</mo><mn>2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mo id="prefix_attach_infix">+</mo><mn>3</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>1</mn><mo id="infix_remove" form="prefix">+</mo><mn>2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mo id="prefix_remove" form="infix">+</mo><mn>3</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>1</mn><mo id="infix_set_to_prefix" form="postfix">+</mo><mn>2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mo id="prefix_set_to_infix" form="postfix">+</mo><mn>3</mn>
+ </math>
+ </p>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_operator_spacing");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-dynamic-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-dynamic-ref.html
new file mode 100644
index 0000000000..8f8d3da2c3
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-dynamic-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>&lt;mo&gt; dynamic form</title>
+ </head>
+ <body>
+
+ <p>The test should render the same as the static reference.</p>
+
+ _<math><merror><mi>x</mi><mo>+</mo><mi>y</mi></merror></math>_
+ _<math><mi>x</mi><mo>+</mo><mi>y</mi></math>_
+ _<math><mphantom><mi>x</mi><mo>+</mo><mi>y</mi></mphantom></math>_
+ _<math><mrow><mi>x</mi><mo>+</mo><mi>y</mi></mrow></math>_
+ _<math><msqrt><mi>x</mi><mo>+</mo><mi>y</mi></msqrt></math>_
+ _<math><mstyle><mi>x</mi><mo>+</mo><mi>y</mi></mstyle></math>_
+
+ _<math><merror><mo>−</mo><mi>y</mi></merror></math>_
+ _<math><mo>−</mo><mi>y</mi></math>_
+ _<math><mphantom><mo>−</mo><mi>y</mi></mphantom></math>_
+ _<math><mrow><mo>−</mo><mi>y</mi></mrow></math>_
+ _<math><msqrt><mo>−</mo><mi>y</mi></msqrt></math>_
+ _<math><mstyle><mo>−</mo><mi>y</mi></mstyle></math>_
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-dynamic.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-dynamic.html
new file mode 100644
index 0000000000..cec203f517
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-dynamic.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8"/>
+ <title>&lt;mo&gt; dynamic form</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript">
+ <meta name="assert" content="This test verifies that the form of the operators (and thus their spacing) is updated when you change the child list.">
+ <link rel="match" href="mo-form-dynamic-ref.html">
+
+ <script>
+ window.addEventListener("load", () => {
+
+ // force initial layout so we're sure what we're testing against
+ document.documentElement.getBoundingClientRect();
+
+ for (var i = 1; i <= 6; i++) {
+ var row = document.getElementById("row" + i);
+ var x = document.getElementById("x" + i);
+
+ x.parentNode.removeChild(x);
+
+ row.insertBefore(x, row.firstElementChild);
+ }
+
+ document.documentElement.classList.remove('reftest-wait');
+ })
+ </script>
+ </head>
+ <body>
+
+ <p>The test should render the same as the static reference.</p>
+
+ _<math><merror id="row1"><mo>+</mo><mi>y</mi></merror></math>_
+ _<math id="row2"><mo>+</mo><mi>y</mi></math>_
+ _<math><mphantom id="row3"><mo>+</mo><mi>y</mi></mphantom></math>_
+ _<math><mrow id="row4"><mo>+</mo><mi>y</mi></mrow></math>_
+ _<math><msqrt id="row5"><mo>+</mo><mi>y</mi></msqrt></math>_
+ _<math><mstyle id="row6"><mo>+</mo><mi>y</mi></mstyle></math>_
+
+ _<math><merror><mi id="x1">x</mi><mo>−</mo><mi>y</mi></merror></math>_
+ _<math><mi id="x2">x</mi><mo>−</mo><mi>y</mi></math>_
+ _<math><mphantom><mi id="x3">x</mi><mo>−</mo><mi>y</mi></mphantom></math>_
+ _<math><mrow><mi id="x4">x</mi><mo>−</mo><mi>y</mi></mrow></math>_
+ _<math><msqrt><mi id="x5">x</mi><mo>−</mo><mi>y</mi></msqrt></math>_
+ _<math><mstyle><mi id="x6">x</mi><mo>−</mo><mi>y</mi></mstyle></math>_
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_operator_spacing");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-fallback-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-fallback-ref.html
new file mode 100644
index 0000000000..8d964eba45
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-fallback-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>form fallback</title>
+ </head>
+ <body>
+
+ <math>
+ <mo stretchy="true">(</mo> <mspace height="3em" depth="3em"/> <mo stretchy="true">)</mo>
+ <mo stretchy="true">(</mo> <mspace height="3em" depth="3em"/> <mo stretchy="true">)</mo>
+ </math>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-fallback.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-fallback.html
new file mode 100644
index 0000000000..b49db9d9ff
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-fallback.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>form fallback</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <meta name="assert" content="Verify fallback to postfix/prefix forms.">
+ <link rel="match" href="mo-form-fallback-ref.html">
+ </head>
+ <body>
+
+ <!-- The left (respectively right) parenthesis only has a prefix
+ (respectively postfix) form which gives its stretchiness.
+ In theory, the parenthesis in the middle of the <math> element are
+ considered infix operators and should not stretch. Let's check that we
+ fallback to the postfix/prefix forms and actually make them stretchy.
+ This is to handle bad MathML markup that misses explicit <mrow> tags.
+ -->
+
+ <math>
+ <mo>(</mo> <mspace height="3em" depth="3em"/> <mo>)</mo>
+ <mo>(</mo> <mspace height="3em" depth="3em"/> <mo>)</mo>
+ </math>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-minus-plus-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-minus-plus-ref.html
new file mode 100644
index 0000000000..b46b307dbe
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-minus-plus-ref.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>form plus/minus</title>
+ </head>
+ <body>
+
+ <!-- These operators should have form "prefix" -->
+
+ _<math><merror><mo form="prefix" lspace="0em" rspace="0em">−</mo><mi>x</mi></merror></math>_
+ _<math><mo form="prefix" lspace="0em" rspace="0em">−</mo><mi>x</mi></math>_
+ _<math><mphantom><mo form="prefix" lspace="0em" rspace="0em">−</mo><mi>x</mi></mphantom></math>_
+ _<math><mrow><mo form="prefix" lspace="0em" rspace="0em">−</mo><mi>x</mi></mrow></math>_
+ _<math><msqrt><mo form="prefix" lspace="0em" rspace="0em">−</mo><mi>x</mi></msqrt></math>_
+ _<math><mstyle><mo form="prefix" lspace="0em" rspace="0em">−</mo><mi>x</mi></mstyle></math>_
+
+ <br/>
+
+ _<math><merror><mo form="prefix" lspace="0em" rspace="0em">+</mo><mi>x</mi></merror></math>_
+ _<math><mo form="prefix" lspace="0em" rspace="0em">+</mo><mi>x</mi></math>_
+ _<math><mphantom><mo form="prefix" lspace="0em" rspace="0em">+</mo><mi>x</mi></mphantom></math>_
+ _<math><mrow><mo form="prefix" lspace="0em" rspace="0em">+</mo><mi>x</mi></mrow></math>_
+ _<math><msqrt><mo form="prefix" lspace="0em" rspace="0em">+</mo><mi>x</mi></msqrt></math>_
+ _<math><mstyle><mo form="prefix" lspace="0em" rspace="0em">+</mo><mi>x</mi></mstyle></math>_
+
+ <br/>
+
+ _<math><merror><mo form="prefix" lspace="0em" rspace="0em">±</mo><mi>x</mi></merror></math>_
+ _<math><mo form="prefix" lspace="0em" rspace="0em">±</mo><mi>x</mi></math>_
+ _<math><mphantom><mo form="prefix" lspace="0em" rspace="0em">±</mo><mi>x</mi></mphantom></math>_
+ _<math><mrow><mo form="prefix" lspace="0em" rspace="0em">±</mo><mi>x</mi></mrow></math>_
+ _<math><msqrt><mo form="prefix" lspace="0em" rspace="0em">±</mo><mi>x</mi></msqrt></math>_
+ _<math><mstyle><mo form="prefix" lspace="0em" rspace="0em">±</mo><mi>x</mi></mstyle></math>_
+
+ <br/>
+
+ _<math><merror><mo form="prefix" lspace="0em" rspace="0em">∓</mo><mi>x</mi></merror></math>_
+ _<math><mo form="prefix" lspace="0em" rspace="0em">∓</mo><mi>x</mi></math>_
+ _<math><mphantom><mo form="prefix" lspace="0em" rspace="0em">∓</mo><mi>x</mi></mphantom></math>_
+ _<math><mrow><mo form="prefix" lspace="0em" rspace="0em">∓</mo><mi>x</mi></mrow></math>_
+ _<math><msqrt><mo form="prefix" lspace="0em" rspace="0em">∓</mo><mi>x</mi></msqrt></math>_
+ _<math><mstyle><mo form="prefix" lspace="0em" rspace="0em">∓</mo><mi>x</mi></mstyle></math>_
+
+ <br/>
+
+ <!-- These operators should have form "infix" -->
+
+ _<math><merror><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">−</mo><mi>y</mi></merror></math>_
+ _<math><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">−</mo><mi>y</mi></math>_
+ _<math><mphantom><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">−</mo><mi>y</mi></mphantom></math>_
+ _<math><mrow><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">−</mo><mi>y</mi></mrow></math>_
+ _<math><msqrt><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">−</mo><mi>y</mi></msqrt></math>_
+ _<math><mstyle><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">−</mo><mi>y</mi></mstyle></math>_
+
+ <br/>
+
+ _<math><merror><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">+</mo><mi>y</mi></merror></math>_
+ _<math><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">+</mo><mi>y</mi></math>_
+ _<math><mphantom><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">+</mo><mi>y</mi></mphantom></math>_
+ _<math><mrow><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">+</mo><mi>y</mi></mrow></math>_
+ _<math><msqrt><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">+</mo><mi>y</mi></msqrt></math>_
+ _<math><mstyle><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">+</mo><mi>y</mi></mstyle></math>_
+
+ <br/>
+
+ _<math><merror><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">±</mo><mi>y</mi></merror></math>_
+ _<math><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">±</mo><mi>y</mi></math>_
+ _<math><mphantom><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">±</mo><mi>y</mi></mphantom></math>_
+ _<math><mrow><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">±</mo><mi>y</mi></mrow></math>_
+ _<math><msqrt><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">±</mo><mi>y</mi></msqrt></math>_
+ _<math><mstyle><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">±</mo><mi>y</mi></mstyle></math>_
+
+ <br/>
+
+ _<math><merror><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">∓</mo><mi>y</mi></merror></math>_
+ _<math><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">∓</mo><mi>y</mi></math>_
+ _<math><mphantom><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">∓</mo><mi>y</mi></mphantom></math>_
+ _<math><mrow><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">∓</mo><mi>y</mi></mrow></math>_
+ _<math><msqrt><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">∓</mo><mi>y</mi></msqrt></math>_
+ _<math><mstyle><mi>x</mi><mo form="infix" lspace="0.22222em" rspace="0.22222em">∓</mo><mi>y</mi></mstyle></math>_
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-minus-plus.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-minus-plus.html
new file mode 100644
index 0000000000..eb7dbbce2a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-minus-plus.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>form plus/minus</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <meta name="assert" content="Verifies behavior of form of plus/minus etc.">
+ <link rel="match" href="mo-form-minus-plus-ref.html">
+ </head>
+ <body>
+
+ <!-- These operators should have form "prefix" -->
+
+ _<math><merror><mo>−</mo><mi>x</mi></merror></math>_
+ _<math><mo>−</mo><mi>x</mi></math>_
+ _<math><mphantom><mo>−</mo><mi>x</mi></mphantom></math>_
+ _<math><mrow><mo>−</mo><mi>x</mi></mrow></math>_
+ _<math><msqrt><mo>−</mo><mi>x</mi></msqrt></math>_
+ _<math><mstyle><mo>−</mo><mi>x</mi></mstyle></math>_
+
+ <br/>
+
+ _<math><merror><mo>+</mo><mi>x</mi></merror></math>_
+ _<math><mo>+</mo><mi>x</mi></math>_
+ _<math><mphantom><mo>+</mo><mi>x</mi></mphantom></math>_
+ _<math><mrow><mo>+</mo><mi>x</mi></mrow></math>_
+ _<math><msqrt><mo>+</mo><mi>x</mi></msqrt></math>_
+ _<math><mstyle><mo>+</mo><mi>x</mi></mstyle></math>_
+
+ <br/>
+
+ _<math><merror><mo>±</mo><mi>x</mi></merror></math>_
+ _<math><mo>±</mo><mi>x</mi></math>_
+ _<math><mphantom><mo>±</mo><mi>x</mi></mphantom></math>_
+ _<math><mrow><mo>±</mo><mi>x</mi></mrow></math>_
+ _<math><msqrt><mo>±</mo><mi>x</mi></msqrt></math>_
+ _<math><mstyle><mo>±</mo><mi>x</mi></mstyle></math>_
+
+ <br/>
+
+ _<math><merror><mo>∓</mo><mi>x</mi></merror></math>_
+ _<math><mo>∓</mo><mi>x</mi></math>_
+ _<math><mphantom><mo>∓</mo><mi>x</mi></mphantom></math>_
+ _<math><mrow><mo>∓</mo><mi>x</mi></mrow></math>_
+ _<math><msqrt><mo>∓</mo><mi>x</mi></msqrt></math>_
+ _<math><mstyle><mo>∓</mo><mi>x</mi></mstyle></math>_
+
+ <br/>
+
+ <!-- These operators should have form "infix" -->
+
+ _<math><merror><mi>x</mi><mo>−</mo><mi>y</mi></merror></math>_
+ _<math><mi>x</mi><mo>−</mo><mi>y</mi></math>_
+ _<math><mphantom><mi>x</mi><mo>−</mo><mi>y</mi></mphantom></math>_
+ _<math><mrow><mi>x</mi><mo>−</mo><mi>y</mi></mrow></math>_
+ _<math><msqrt><mi>x</mi><mo>−</mo><mi>y</mi></msqrt></math>_
+ _<math><mstyle><mi>x</mi><mo>−</mo><mi>y</mi></mstyle></math>_
+
+ <br/>
+
+ _<math><merror><mi>x</mi><mo>+</mo><mi>y</mi></merror></math>_
+ _<math><mi>x</mi><mo>+</mo><mi>y</mi></math>_
+ _<math><mphantom><mi>x</mi><mo>+</mo><mi>y</mi></mphantom></math>_
+ _<math><mrow><mi>x</mi><mo>+</mo><mi>y</mi></mrow></math>_
+ _<math><msqrt><mi>x</mi><mo>+</mo><mi>y</mi></msqrt></math>_
+ _<math><mstyle><mi>x</mi><mo>+</mo><mi>y</mi></mstyle></math>_
+
+ <br/>
+
+ _<math><merror><mi>x</mi><mo>±</mo><mi>y</mi></merror></math>_
+ _<math><mi>x</mi><mo>±</mo><mi>y</mi></math>_
+ _<math><mphantom><mi>x</mi><mo>±</mo><mi>y</mi></mphantom></math>_
+ _<math><mrow><mi>x</mi><mo>±</mo><mi>y</mi></mrow></math>_
+ _<math><msqrt><mi>x</mi><mo>±</mo><mi>y</mi></msqrt></math>_
+ _<math><mstyle><mi>x</mi><mo>±</mo><mi>y</mi></mstyle></math>_
+
+ <br/>
+
+ _<math><merror><mi>x</mi><mo>∓</mo><mi>y</mi></merror></math>_
+ _<math><mi>x</mi><mo>∓</mo><mi>y</mi></math>_
+ _<math><mphantom><mi>x</mi><mo>∓</mo><mi>y</mi></mphantom></math>_
+ _<math><mrow><mi>x</mi><mo>∓</mo><mi>y</mi></mrow></math>_
+ _<math><msqrt><mi>x</mi><mo>∓</mo><mi>y</mi></msqrt></math>_
+ _<math><mstyle><mi>x</mi><mo>∓</mo><mi>y</mi></mstyle></math>_
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_operator_spacing");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-ref.html
new file mode 100644
index 0000000000..b249fe43b5
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>&lt;mo&gt; form attribute</title>
+ </head>
+ <body>
+
+ <!-- This checks the effect of @form on a prefix operator. -->
+ _<math><mo lspace="0.27777em" rspace="0.27777em">∇</mo></math>_
+ _<math><mo lspace="0em" rspace="0em">∇</mo></math>_
+ _<math><mo lspace="0.27777em" rspace="0.27777em">∇</mo></math>_
+
+ <!-- This checks the effect of @form on an infix operator. -->
+ _<math><mo lspace="0.166666em" rspace="0.166666em">⋉</mo></math>_
+ _<math><mo lspace="0.27777em" rspace="0.27777em">⋉</mo></math>_
+ _<math><mo lspace="0.27777em" rspace="0.27777em">⋉</mo></math>_
+
+ <!-- This checks the effect of @form on a postfix operator. -->
+ _<math><mo lspace="0.27777em" rspace="0.27777em">”</mo></math>_
+ _<math><mo lspace="0.27777em" rspace="0.27777em">”</mo></math>_
+ _<math><mo lspace="0em" rspace="0em">”</mo></math>_
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form.html
new file mode 100644
index 0000000000..38cbd6bb4b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-form.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>&lt;mo&gt; form attribute</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <meta name="assert" content="Verifies behavior of form attribute.">
+ <link rel="match" href="mo-form-ref.html">
+ </head>
+ <body>
+
+ <!-- This checks the effect of @form on a prefix operator. -->
+ _<math><mo form="infix">∇</mo></math>_
+ _<math><mo form="prefix">∇</mo></math>_
+ _<math><mo form="postfix">∇</mo></math>_
+
+ <!-- This checks the effect of @form on an infix operator. -->
+ _<math><mo form="infix">⋉</mo></math>_
+ _<math><mo form="prefix">⋉</mo></math>_
+ _<math><mo form="postfix">⋉</mo></math>_
+
+ <!-- This checks the effect of @form on a postfix operator. -->
+ _<math><mo form="infix">”</mo></math>_
+ _<math><mo form="prefix">”</mo></math>_
+ _<math><mo form="postfix">”</mo></math>_
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_operator_spacing");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-2-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-2-ref.html
new file mode 100644
index 0000000000..4ffe6cbc23
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-2-ref.html
@@ -0,0 +1,363 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>mo-lspace-rspace-2 (reference)</title>
+ <style type="text/css">
+ mo,td {
+ background-color: red;
+ }
+ msub, mfrac, msup, msubsup, mmultiscripts,
+ mover, munder, munderover, mpadded, merror
+ {
+ background-color: blue
+ }
+ math[display]
+ {
+ background-color: blue
+ }
+ </style>
+ </head>
+ <body>
+
+ <p>
+ <math>
+ <mrow>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mrow>
+ </math>
+ <math>
+ <mfrac>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mfrac>
+ </math>
+ <math>
+ <msqrt>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </msqrt>
+ </math>
+ <math>
+ <mroot>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mroot>
+ </math>
+ <math>
+ <mstyle>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mstyle>
+ </math>
+ </p>
+
+ <p>
+ <table>
+ <tr>
+ <td>
+ <math>
+ <mphantom>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mphantom>
+ </math>
+ </td>
+ </tr>
+ </table>
+ </p>
+
+ <p>
+ <math>
+ <menclose notation="circle">
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </menclose>
+ </math>
+ <math>
+ <msub>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </msub>
+ </math>
+ <math>
+ <msup>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </msup>
+ </math>
+ <math>
+ <msubsup>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </msubsup>
+ </math>
+ <math>
+ <munder>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </munder>
+ </math>
+ <math>
+ <mover>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mover>
+ </math>
+ <math>
+ <munderover>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </munderover>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <mmultiscripts>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mprescripts/>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mmultiscripts>
+ </math>
+ <math>
+ <mtable>
+ <mtr>
+ <mtd>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+ <math>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </math>
+ <math>
+ <msub>
+ <mrow>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mrow>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </msub>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <msub>
+ <msub>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </msub>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </msub>
+ </math>
+ <math>
+ <munder>
+ <munder>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </munder>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </munder>
+ </math>
+ <math>
+ <mfrac>
+ <mfrac>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mfrac>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mfrac>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <menclose notation="circle">
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </menclose>
+ <menclose notation="circle">
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </menclose>
+ <mroot>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mroot>
+ </math>
+ <math>
+ <mpadded height="+1em">
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mpadded>
+ </math>
+ <math>
+ <merror>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </merror>
+ </math>
+ </p>
+
+ <math display="block">
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </math>
+
+ <p>
+ <math>
+ <mrow>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mrow>
+ <mfrac>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0" rspace="0">*</mo>
+ </mfrac>
+ <msqrt>
+ <mo lspace="0" rspace="0">*</mo>
+ </msqrt>
+ <mstyle>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mstyle>
+ </math>
+ </p>
+
+ <p>
+ <table>
+ <tr>
+ <td>
+ <math>
+ <mphantom>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mphantom>
+ </math>
+ </td>
+ </tr>
+ </table>
+ </p>
+
+ <p>
+ <math>
+ <menclose notation="circle">
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </menclose>
+ <msub>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0" rspace="0">*</mo>
+ </msub>
+ <msup>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0" rspace="0">*</mo>
+ </msup>
+ <msubsup>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0" rspace="0">*</mo>
+ <mo lspace="0" rspace="0">*</mo>
+ </msubsup>
+ <munder>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0" rspace="0">*</mo>
+ </munder>
+ <mover>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0" rspace="0">*</mo>
+ </mover>
+ <munderover>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0" rspace="0">*</mo>
+ <mo lspace="0" rspace="0">*</mo>
+ </munderover>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <mmultiscripts>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0" rspace="0">*</mo>
+ <mo lspace="0" rspace="0">*</mo>
+ <mprescripts/>
+ <mo lspace="0" rspace="0">*</mo>
+ <mo lspace="0" rspace="0">*</mo>
+ </mmultiscripts>
+ <mtable>
+ <mtr>
+ <mtd>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mtd>
+ </mtr>
+ </mtable>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <msub>
+ <mrow>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mrow>
+ <mo lspace="0" rspace="0">*</mo>
+ </msub>
+ <msub>
+ <mrow>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mrow>
+ <mo lspace="0" rspace="0">*</mo>
+ </msub>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <msub>
+ <msub>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0" rspace="0">*</mo>
+ </msub>
+ <mo lspace="0" rspace="0">*</mo>
+ </msub>
+ <munder>
+ <munder>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0" rspace="0">*</mo>
+ </munder>
+ <mo lspace="0" rspace="0">*</mo>
+ </munder>
+ <mfrac>
+ <mfrac>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0" rspace="0">*</mo>
+ </mfrac>
+ <mo lspace="0" rspace="0">*</mo>
+ </mfrac>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <mrow>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mpadded height="+1em">
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mpadded>
+ </mrow>
+ </math>
+ <math>
+ <mpadded height="+1em">
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </mpadded>
+ </math>
+ <math>
+ <merror>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </merror>
+ </math>
+ </p>
+
+ <math display="block">
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </math>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-2.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-2.html
new file mode 100644
index 0000000000..d54f45c21d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-2.html
@@ -0,0 +1,363 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>mo-lspace-rspace-2</title>
+ <link rel="match" href="mo-lspace-rspace-2-ref.html">
+ <style type="text/css">
+ mo,td {
+ background-color: red;
+ }
+ msub, mfrac, msup, msubsup, mmultiscripts,
+ mover, munder, munderover, mpadded, merror
+ {
+ background-color: blue
+ }
+ math[display]
+ {
+ background-color: blue
+ }
+ </style>
+ </head>
+ <body>
+
+ <p>
+ <math>
+ <mrow>
+ <mo>*</mo>
+ </mrow>
+ </math>
+ <math>
+ <mfrac>
+ <mo>*</mo>
+ <mo>*</mo>
+ </mfrac>
+ </math>
+ <math>
+ <msqrt>
+ <mo>*</mo>
+ </msqrt>
+ </math>
+ <math>
+ <mroot>
+ <mo>*</mo>
+ <mo>*</mo>
+ </mroot>
+ </math>
+ <math>
+ <mstyle>
+ <mo>*</mo>
+ </mstyle>
+ </math>
+ </p>
+
+ <p>
+ <table>
+ <tr>
+ <td>
+ <math>
+ <mphantom>
+ <mo>*</mo>
+ </mphantom>
+ </math>
+ </td>
+ </tr>
+ </table>
+ </p>
+
+ <p>
+ <math>
+ <menclose notation="circle">
+ <mo>*</mo>
+ </menclose>
+ </math>
+ <math>
+ <msub>
+ <mo>*</mo>
+ <mo>*</mo>
+ </msub>
+ </math>
+ <math>
+ <msup>
+ <mo>*</mo>
+ <mo>*</mo>
+ </msup>
+ </math>
+ <math>
+ <msubsup>
+ <mo>*</mo>
+ <mo>*</mo>
+ <mo>*</mo>
+ </msubsup>
+ </math>
+ <math>
+ <munder>
+ <mo>*</mo>
+ <mo>*</mo>
+ </munder>
+ </math>
+ <math>
+ <mover>
+ <mo>*</mo>
+ <mo>*</mo>
+ </mover>
+ </math>
+ <math>
+ <munderover>
+ <mo>*</mo>
+ <mo>*</mo>
+ <mo>*</mo>
+ </munderover>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <mmultiscripts>
+ <mo>*</mo>
+ <mo>*</mo>
+ <mo>*</mo>
+ <mprescripts/>
+ <mo>*</mo>
+ <mo>*</mo>
+ </mmultiscripts>
+ </math>
+ <math>
+ <mtable>
+ <mtr>
+ <mtd>
+ <mo>*</mo>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+ <math>
+ <mo>*</mo>
+ </math>
+ <math>
+ <msub>
+ <mrow>
+ <mo>*</mo>
+ </mrow>
+ <mo>*</mo>
+ </msub>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <msub>
+ <msub>
+ <mo>*</mo>
+ <mo>*</mo>
+ </msub>
+ <mo>*</mo>
+ </msub>
+ </math>
+ <math>
+ <munder>
+ <munder>
+ <mo>*</mo>
+ <mo>*</mo>
+ </munder>
+ <mo>*</mo>
+ </munder>
+ </math>
+ <math>
+ <mfrac>
+ <mfrac>
+ <mo>*</mo>
+ <mo>*</mo>
+ </mfrac>
+ <mo>*</mo>
+ </mfrac>
+ </math>
+ </p>
+ <p>
+ <math>
+ <menclose notation="circle">
+ <mo>*</mo>
+ </menclose>
+ <menclose notation="circle">
+ <mo>*</mo>
+ </menclose>
+ <mroot>
+ <mo>*</mo>
+ <mo>*</mo>
+ </mroot>
+ </math>
+ <math>
+ <mpadded height="+1em">
+ <mo>*</mo>
+ </mpadded>
+ </math>
+ <math>
+ <merror>
+ <mo>*</mo>
+ </merror>
+ </math>
+ </p>
+
+ <math display="block">
+ <mo>*</mo>
+ </math>
+
+ <p>
+ <math>
+ <mrow>
+ <mo>*</mo>
+ </mrow>
+ <mfrac>
+ <mo>*</mo>
+ <mo>*</mo>
+ </mfrac>
+ <msqrt>
+ <mo>*</mo>
+ </msqrt>
+ <mstyle>
+ <mo>*</mo>
+ </mstyle>
+ </math>
+ </p>
+
+ <p>
+ <table>
+ <tr>
+ <td>
+ <math>
+ <mphantom>
+ <mo>*</mo>
+ <mo>*</mo>
+ </mphantom>
+ </math>
+ </td>
+ </tr>
+ </table>
+ </p>
+
+ <p>
+ <math>
+ <menclose notation="circle">
+ <mo>*</mo>
+ <mo>*</mo>
+ </menclose>
+ <msub>
+ <mo>*</mo>
+ <mo>*</mo>
+ </msub>
+ <msup>
+ <mo>*</mo>
+ <mo>*</mo>
+ </msup>
+ <msubsup>
+ <mo>*</mo>
+ <mo>*</mo>
+ <mo>*</mo>
+ </msubsup>
+ <munder>
+ <mo>*</mo>
+ <mo>*</mo>
+ </munder>
+ <mover>
+ <mo>*</mo>
+ <mo>*</mo>
+ </mover>
+ <munderover>
+ <mo>*</mo>
+ <mo>*</mo>
+ <mo>*</mo>
+ </munderover>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <mmultiscripts>
+ <mo>*</mo>
+ <mo>*</mo>
+ <mo>*</mo>
+ <mprescripts/>
+ <mo>*</mo>
+ <mo>*</mo>
+ </mmultiscripts>
+ <mtable>
+ <mtr>
+ <mtd>
+ <mo>*</mo>
+ <mo>*</mo>
+ </mtd>
+ </mtr>
+ </mtable>
+ <mo>*</mo>
+ <msub>
+ <mrow>
+ <mo>*</mo>
+ </mrow>
+ <mo>*</mo>
+ </msub>
+ <msub>
+ <mrow>
+ <mo>*</mo>
+ <mo>*</mo>
+ </mrow>
+ <mo>*</mo>
+ </msub>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <msub>
+ <msub>
+ <mo>*</mo>
+ <mo>*</mo>
+ </msub>
+ <mo>*</mo>
+ </msub>
+ <munder>
+ <munder>
+ <mo>*</mo>
+ <mo>*</mo>
+ </munder>
+ <mo>*</mo>
+ </munder>
+ <mfrac>
+ <mfrac>
+ <mo>*</mo>
+ <mo>*</mo>
+ </mfrac>
+ <mo>*</mo>
+ </mfrac>
+ </math>
+ </p>
+
+ <p>
+ <math>
+ <mrow>
+ <mo>*</mo>
+ <mo>*</mo>
+ <mpadded height="+1em">
+ <mo>*</mo>
+ </mpadded>
+ </mrow>
+ </math>
+ <math>
+ <mpadded height="+1em">
+ <mo>*</mo>
+ <mo>*</mo>
+ </mpadded>
+ </math>
+ <math>
+ <merror>
+ <mo>*</mo>
+ <mo>*</mo>
+ </merror>
+ </math>
+ </p>
+
+ <math display="block">
+ <mo>*</mo>
+ <mo>*</mo>
+ </math>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-3-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-3-ref.html
new file mode 100644
index 0000000000..1830e11474
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-3-ref.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>mo-lspace-rspace-3 (reference)</title>
+ </head>
+ <body>
+ <p>
+ <math>
+ <mo id="mo1" lspace="3em" rspace="0.16666666666666666em">*</mo>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mo id="mo2" lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mo id="mo3" lspace="3em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mo id="mo4" lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mo lspace="0.16666666666666666em" rspace="0.16666666666666666em">*</mo>
+ </math>
+ </p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-3.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-3.html
new file mode 100644
index 0000000000..4574ff39c9
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-3.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <title>mo-lspace-rspace-3</title>
+ <link rel="match" href="mo-lspace-rspace-3-ref.html">
+ </head>
+ <body>
+ <p>
+ <math>
+ <mo id="mo1">*</mo>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mo id="mo2" lspace="3em">*</mo>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mo id="mo3">*</mo>
+ <mo>*</mo>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mo id="mo4" lspace="3em">*</mo>
+ <mo >*</mo>
+ </math>
+ </p>
+ <p>
+ <math id="math1">
+ <mo>*</mo>
+ </math>
+ </p>
+ <p>
+ <math id="math2">
+ <mo>*</mo>
+ <mo id="mo5">*</mo>
+ </math>
+ </p>
+ <script type="text/javascript">
+ function doTest() {
+ // Add and remove lspace
+ document.getElementById("mo1").setAttribute("lspace", "3em");
+ document.getElementById("mo2").removeAttribute("lspace");
+ // and again but with an inferred mrow
+ document.getElementById("mo3").setAttribute("lspace", "3em");
+ document.getElementById("mo4").removeAttribute("lspace");
+
+ // Change to/from inferred mrow
+ var mo1 = document.createElementNS("http://www.w3.org/1998/Math/MathML", "mo");
+ mo1.innerHTML = "*";
+ document.getElementById("math1").appendChild(mo1);
+ document.getElementById("math2").removeChild(document.getElementById("mo5"));
+
+ document.documentElement.removeAttribute("class");
+ }
+ window.addEventListener("load", doTest);
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-4-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-4-ref.html
new file mode 100644
index 0000000000..ab4c08dde1
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-4-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>mo-lspace-rspace-4 (reference)</title>
+ </head>
+ <body>
+ <p>
+ <math>
+ <mtext>_</mtext>
+ <mrow>
+ <mfrac>
+ <mo lspace="1em" rspace="2em">_</mo>
+ <mtext>_</mtext>
+ </mfrac>
+ </mrow>
+ <mtext>_</mtext>
+ </math>
+ </p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-4.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-4.html
new file mode 100644
index 0000000000..4798454868
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-4.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>mo-lspace-rspace-4</title>
+ <link rel="match" href="mo-lspace-rspace-4-ref.html">
+ </head>
+ <body>
+ <p>
+ <math>
+ <mtext>_</mtext>
+ <mfrac>
+ <mo lspace="1em" rspace="2em">_</mo>
+ <mtext>_</mtext>
+ </mfrac>
+ <mtext>_</mtext>
+ </math>
+ </p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-dynamic-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-dynamic-ref.html
new file mode 100644
index 0000000000..85cabd287d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-dynamic-ref.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>&lt;mo&gt; dynamic lspace rspace (reference)</title>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math, math * {
+ font: 60px/1 Ahem;
+ }
+ mo {
+ color: blue;
+ }
+ </style>
+ </head>
+ <body>
+ <p>
+ <math>
+ <mn>1</mn><mo id="mo_attach_lspace" lspace="2em">X</mo><mn>2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>1</mn><mo id="mo_attach_rspace" rspace="3em">X</mo><mn>2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>1</mn><mo id="mo_modify_lspace" lspace="4em" rspace="1em">X</mo><mn>2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>1</mn><mo id="mo_modify_rspace" lspace="1em" rspace="5em">X</mo><mn>2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>1</mn><mo id="mo_remove_lspace" rspace="1em">X</mo><mn>2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>1</mn><mo id="mo_remove_rspace" lspace="1em">X</mo><mn>2</mn>
+ </math>
+ </p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-dynamic.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-dynamic.html
new file mode 100644
index 0000000000..70098bebf9
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-dynamic.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8">
+ <title>&lt;mo&gt; dynamic lspace rspace</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <meta name="assert" content="Verifies dynamic setting of lspace and rspace">
+ <link rel="match" href="mo-lspace-rspace-dynamic-ref.html">
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math, math * {
+ font: 60px/1 Ahem;
+ }
+ mo {
+ color: blue;
+ }
+ </style>
+ <script>
+ window.addEventListener("load", () => {
+ document.getElementById("mo_attach_lspace").setAttribute("lspace", "2em");
+ document.getElementById("mo_attach_rspace").setAttribute("rspace", "3em");
+ document.getElementById("mo_modify_lspace").setAttribute("lspace", "4em");
+ document.getElementById("mo_modify_rspace").setAttribute("rspace", "5em");
+ document.getElementById("mo_remove_lspace").removeAttribute("lspace");
+ document.getElementById("mo_remove_rspace").removeAttribute("rspace");
+ document.documentElement.classList.remove("reftest-wait");
+ });
+ </script>
+ </head>
+ <body>
+ <p>
+ <math>
+ <mn>1</mn><mo id="mo_attach_lspace">X</mo><mn>2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>1</mn><mo id="mo_attach_rspace">X</mo><mn>2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>1</mn><mo id="mo_modify_lspace" lspace="1em" rspace="1em">X</mo><mn>2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>1</mn><mo id="mo_modify_rspace" lspace="1em" rspace="1em">X</mo><mn>2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>1</mn><mo id="mo_remove_lspace" lspace="1em" rspace="1em">X</mo><mn>2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>1</mn><mo id="mo_remove_rspace" lspace="1em" rspace="1em">X</mo><mn>2</mn>
+ </math>
+ </p>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_operator_spacing");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-ref.html
new file mode 100644
index 0000000000..46be5079e6
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace-ref.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>mo-lspace-rspace (reference)</title>
+ </head>
+
+ <body>
+
+ <p>
+ <!-- not in the operator dictionary -->
+ <math>
+ <mtext>_</mtext>
+ <mspace width="0.2777777777777778em" height="0" depth="0"></mspace>
+ <mtext>MO</mtext>
+ <mspace width="0.2777777777777778em" height="0" depth="0"></mspace>
+ <mtext>_</mtext>
+ </math>
+ </p>
+
+ <p>
+ <!-- operator.\u223F.infix = lspace:3 rspace:3 # sine wave -->
+ <math>
+ <mtext>_</mtext>
+ <mspace width="0.16666666666666666em" height="0" depth="0"></mspace>
+ <mtext>&#x0223F;</mtext>
+ <mspace width="0.16666666666666666em" height="0" depth="0"></mspace>
+ <mtext>_</mtext>
+ </math>
+ </p>
+
+ <p>
+ <!-- Invisible operator -->
+ <math>
+ <mtext>_</mtext>
+ <mtext>&#x02061;</mtext>
+ <mtext>_</mtext>
+ </math>
+ </p>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace.html
new file mode 100644
index 0000000000..5774e4ced0
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-lspace-rspace.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>mo-lspace-rspace</title>
+ <link rel="match" href="mo-lspace-rspace-ref.html">
+ </head>
+
+ <body>
+
+ <p>
+ <!-- not in the operator dictionary -->
+ <math>
+ <mtext>_</mtext>
+ <mo>MO</mo>
+ <mtext>_</mtext>
+ </math>
+ </p>
+
+ <p>
+ <!-- operator.\u223F.infix = lspace:3 rspace:3 # sine wave -->
+ <math>
+ <mtext>_</mtext>
+ <mo>&#x0223F;</mo>
+ <mtext>_</mtext>
+ </math>
+ </p>
+
+ <p>
+ <!-- Invisible operator -->
+ <math>
+ <mtext>_</mtext>
+ <mo>&#x02061;</mo>
+ <mtext>_</mtext>
+ </math>
+ </p>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-minsize-maxsize-001.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-minsize-maxsize-001.html
new file mode 100644
index 0000000000..3e7e5c9bcc
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-minsize-maxsize-001.html
@@ -0,0 +1,143 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Edge cases for minsize and maxsize</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<meta name="assert" content="Verify edge cases for minsize and maxsize .">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math {
+ font: 25px/1 Ahem;
+ }
+ @font-face {
+ font-family: operators;
+ src: url("/fonts/math/operators.woff"); /* AxisHeight == 0 */
+ }
+ mo {
+ font-family: operators;
+ }
+</style>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ var epsilon = 1;
+ var emToPx = 25;
+ test(function() {
+ assert_approx_equals(document.getElementById("negative_minsize").getBoundingClientRect().height, 5 * emToPx, epsilon);
+ }, `minsize < 0 is treated as 0`);
+
+ test(function() {
+ assert_approx_equals(document.getElementById("maxsize_less_than_minsize").getBoundingClientRect().height, 7 * emToPx, epsilon);
+ }, `maxsize < minsize is treated as maxsize = minsize`);
+
+ test(function() {
+ assert_less_than(document.getElementById("minsize_less_than_negative_maxsize").getBoundingClientRect().height, 2 * emToPx);
+ }, `minsize < maxsize < 0 is treated as maxsize = minsize = 0`);
+
+ test(function() {
+ assert_approx_equals(document.getElementById("zero_target_size_with_minsize").getBoundingClientRect().height, 2 * emToPx, epsilon);
+ assert_approx_equals(document.getElementById("zero_target_size_with_minsize").getBoundingClientRect().bottom - document.getElementById("zero_target_size_with_minsize_math_axis").getBoundingClientRect().bottom, emToPx, epsilon);
+ }, `target size = 0 is treated as Tascent = Tdescent = minsize/2`);
+
+ test(function() {
+ assert_approx_equals(document.getElementById("percent_minsize").getBoundingClientRect().height, 12 * emToPx, epsilon, "percent minsize");
+ assert_approx_equals(document.getElementById("percent_maxsize").getBoundingClientRect().height, 3 * emToPx, epsilon, "percent maxsize");
+ }, `minsize/maxsize percentages are relative to the target size`);
+
+ test(function() {
+ // These tests are not really strong:
+ // - The smallest glyph for this stretchy operator is a 1em square so
+ // it can't go under a minsize of 1em anyway.
+ // - The maxsize is theorically infinite, this only tests that a large
+ // value of 300em is clamped.
+ assert_approx_equals(document.getElementById("default_minsize").getBoundingClientRect().height, 1 * emToPx, epsilon, "default minsize is 1em");
+ assert_approx_equals(document.getElementById("default_maxsize").getBoundingClientRect().height, 300 * emToPx, epsilon, "default maxsize is infinity");
+ }, `default minsize/maxsize percentages`);
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mrow>
+ <mspace width="1em" height="5em" style="background: blue"/>
+ <mo id="negative_minsize" minsize="-10em" stretchy="true" symmetric="false">⥯</mo>
+ <mn><!-- not space like --></mn>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mspace width="1em" height="5em" style="background: blue"/>
+ <mo id="maxsize_less_than_minsize" minsize="7em" maxsize="2em" stretchy="true" symmetric="false">⥯</mo>
+ <mn><!-- not space like --></mn>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mspace width="1em" height="5em" style="background: blue"/>
+ <mo id="minsize_less_than_negative_maxsize" minsize="-2em" maxsize="-1em" stretchy="true" symmetric="false">⥯</mo>
+ <mn><!-- not space like --></mn>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mspace id="zero_target_size_with_minsize_math_axis" width="1em" height="0em" style="background: blue"/>
+ <mo id="zero_target_size_with_minsize" minsize="2em" stretchy="true" symmetric="true">⥯</mo>
+ <mn><!-- not space like --></mn>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mspace width="1em" height="6em" style="background: blue"/>
+ <mo id="percent_minsize" minsize="200%" stretchy="true" symmetric="false">⥯</mo>
+ <mn><!-- not space like --></mn>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mspace width="1em" height="6em" style="background: blue"/>
+ <mo id="percent_maxsize" maxsize="50%" stretchy="true" symmetric="false">⥯</mo>
+ <mn><!-- not space like --></mn>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mspace width="1em" height=".5em" style="background: blue"/>
+ <mo id="default_minsize" stretchy="true" symmetric="false">⥯</mo>
+ <mn><!-- not space like --></mn>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mspace width="1em" height="300em" style="background: blue"/>
+ <mo id="default_maxsize" stretchy="true" symmetric="false">⥯</mo>
+ <mn><!-- not space like --></mn>
+ </mrow>
+ </math>
+ </p>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-and-embellished-operator-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-and-embellished-operator-ref.html
new file mode 100644
index 0000000000..cca8b9b697
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-and-embellished-operator-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8"/>
+ <title>&lt;mo&gt; movablelimits and embellished operator (reference)</title>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math { font: 25px/1 Ahem; }
+ </style>
+</head>
+<body>
+ <math>
+ <msub>
+ <mrow><mtext>A</mtext></mrow>
+ <mn>2</mn>
+ </msub>
+ <munder>
+ <mrow><mtext>A</mtext></mrow>
+ <mn>2</mn>
+ </munder>
+ </math>
+ <math displaystyle="true">
+ <munder>
+ <mrow><mtext>A</mtext></mrow>
+ <mn>2</mn>
+ </munder>
+ <munder>
+ <mrow><mtext>A</mtext></mrow>
+ <mn>2</mn>
+ </munder>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-and-embellished-operator.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-and-embellished-operator.html
new file mode 100644
index 0000000000..2bdfa15bc6
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-and-embellished-operator.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>&lt;mo&gt; movablelimits and embellished operator (reference)</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#embellished-operators">
+ <meta name="assert" content="Verifies effect of movablelimits on the core operator of an embellished operator, in both displaystyle modes.">
+ <link rel="match" href="mo-movablelimits-and-embellished-operator-ref.html">
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math { font: 25px/1 Ahem; }
+ </style>
+ </head>
+ <body>
+ <math>
+ <munder>
+ <mrow><mo lspace="0px" rspace="0px" movablelimits="true">A</mo></mrow>
+ <mn>2</mn>
+ </munder>
+ <munder>
+ <mrow><mo lspace="0px" rspace="0px" movablelimits="false">A</mo></mrow>
+ <mn>2</mn>
+ </munder>
+ </math>
+ <math displaystyle="true">
+ <munder>
+ <mrow><mo lspace="0px" rspace="0px" movablelimits="true">A</mo></mrow>
+ <mn>2</mn>
+ </munder>
+ <munder>
+ <mrow><mo lspace="0px" rspace="0px" movablelimits="false">A</mo></mrow>
+ <mn>2</mn>
+ </munder>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_munderover");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-default-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-default-ref.html
new file mode 100644
index 0000000000..8328637397
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-default-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>mo movablelimits default value</title>
+ <meta charset="utf-8"/></head>
+<body>
+ <math>
+ <munder>
+ <mo movablelimits="true">∑</mo>
+ <mi>x</mi>
+ </munder>
+ <munder>
+ <mo movablelimits="false">∫</mo>
+ <mi>x</mi>
+ </munder>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-default.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-default.html
new file mode 100644
index 0000000000..4d6ee00d82
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-default.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>&lt;mo&gt; movablelimits default value</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <meta name="assert" content="Verifies default value of movablelimits for some operators.">
+ <link rel="match" href="mo-movablelimits-default-ref.html">
+ </head>
+ <body>
+ <math>
+ <munder>
+ <mo>∑</mo> <!-- This has movablelimits="true" in the operator dictionary -->
+ <mi>x</mi>
+ </munder>
+ <munder>
+ <mo>∫</mo> <!-- This has movablelimits="false" in the operator dictionary -->
+ <mi>x</mi>
+ </munder>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_munderover");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-dynamic-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-dynamic-ref.html
new file mode 100644
index 0000000000..ee5bce2ca8
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-dynamic-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Test dynamically removing movablelimits attribute</title>
+ </head>
+ <body>
+ <math>
+ <munder>
+ <mo>∑</mo>
+ <mi>x</mi>
+ </munder>
+ </math>
+ </body>
+ </html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-dynamic.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-dynamic.html
new file mode 100644
index 0000000000..647fc52321
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-dynamic.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8"/>
+ <title>Test dynamically removing movablelimits attribute</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript">
+ <meta name="assert" content="Verifies dynamically removing movablelimits.">
+ <link rel="match" href="mo-movablelimits-dynamic-ref.html">
+ <script>
+ window.addEventListener("load", () => {
+ document.getElementById('a').removeAttribute('movablelimits');
+ document.documentElement.classList.remove('reftest-wait');
+ });
+ </script>
+ </head>
+ <body>
+ <math>
+ <munder>
+ <mo id="a" movablelimits="false">∑</mo>
+ <mi>x</mi>
+ </munder>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_munderover");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-from-in-flow-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-from-in-flow-ref.html
new file mode 100644
index 0000000000..3efeaa0dfe
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-from-in-flow-ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>&lt;mo&gt; movablelimits</title>
+ <style>
+ math, math * {
+ font: 25px/1 Ahem;
+ }
+ </style>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ </head>
+ <body>
+ <math>
+ <msub>
+ <mo lspace="0px" rspace="0px">+</mo>
+ <mn>1</mn>
+ </msub>
+ <msup>
+ <mo lspace="0px" rspace="0px">+</mo>
+ <mn>1</mn>
+ </msup>
+ <msubsup>
+ <mo lspace="0px" rspace="0px">+</mo>
+ <mn>1</mn>
+ <mn>2</mn>
+ </msubsup>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-from-in-flow.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-from-in-flow.html
new file mode 100644
index 0000000000..d1a2422c98
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-from-in-flow.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>&lt;mo&gt; movablelimits</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <meta name="assert" content="Verify movablelimits is read from the first in-flow child.">
+ <style>
+ math, math * {
+ font: 25px/1 Ahem;
+ }
+ .oof1 {
+ position: absolute;
+ }
+ .oof2 {
+ position: fixed;
+ }
+ .nobox {
+ display: none;
+ }
+ </style>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <link rel="match" href="mo-movablelimits-from-in-flow-ref.html">
+ </head>
+ <body>
+ <math>
+ <munder>
+ <mo class="oof1" movablelimits="false"></mo>
+ <mo class="oof2" movablelimits="false"></mo>
+ <mo class="nobox" movablelimits="false"></mo>
+ <mo lspace="0px" rspace="0px" movablelimits="true">+</mo>
+ <mn>1</mn>
+ </munder>
+ <mover>
+ <mo class="oof1" movablelimits="false"></mo>
+ <mo class="oof2" movablelimits="false"></mo>
+ <mo class="nobox" movablelimits="false"></mo>
+ <mo lspace="0px" rspace="0px" movablelimits="true">+</mo>
+ <mn>1</mn>
+ </mover>
+ <munderover>
+ <mo class="oof1" movablelimits="false"></mo>
+ <mo class="oof2" movablelimits="false"></mo>
+ <mo class="nobox" movablelimits="false"></mo>
+ <mo lspace="0px" rspace="0px" movablelimits="true">+</mo>
+ <mn>1</mn>
+ <mn>2</mn>
+ </munderover>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_munderover");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-ref.html
new file mode 100644
index 0000000000..cb868d2400
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits-ref.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8"/>
+ <title>&lt;mo&gt; movablelimits</title>
+</head>
+<body>
+ <math>
+ <msub>
+ <mtext>A</mtext>
+ <mi>B</mi>
+ </msub>
+ <munder>
+ <mtext>A</mtext>
+ <mi>B</mi>
+ </munder>
+ </math>
+ <math displaystyle="true">
+ <munder>
+ <mtext>A</mtext>
+ <mi>B</mi>
+ </munder>
+ <munder>
+ <mtext>A</mtext>
+ <mi>B</mi>
+ </munder>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits.html
new file mode 100644
index 0000000000..e7aa17380b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-movablelimits.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>&lt;mo&gt; movablelimits</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <meta name="assert" content="Verifies effect of movablelimits on mo in both displaystyle modes.">
+ <link rel="match" href="mo-movablelimits-ref.html">
+ </head>
+ <body>
+ <math>
+ <munder>
+ <mo lspace="0px" rspace="0px" movablelimits="true">A</mo>
+ <mi>B</mi>
+ </munder>
+ <munder>
+ <mo lspace="0px" rspace="0px" movablelimits="false">A</mo>
+ <mi>B</mi>
+ </munder>
+ </math>
+ <math displaystyle="true">
+ <munder>
+ <mo lspace="0px" rspace="0px" movablelimits="true">A</mo>
+ <mi>B</mi>
+ </munder>
+ <munder>
+ <mo lspace="0px" rspace="0px" movablelimits="false">A</mo>
+ <mi>B</mi>
+ </munder>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_munderover");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-not-in-dictionary-lspace-rspace-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-not-in-dictionary-lspace-rspace-ref.html
new file mode 100644
index 0000000000..3938db19a7
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-not-in-dictionary-lspace-rspace-ref.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>lspace/rspace default value for unknown operators (reference)</title>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math {
+ font: 100px/1 Ahem;
+ }
+ mo {
+ color: blue;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if on each row, the space around the blue rectangle
+ is 0.2777777777777778em.</p>
+ <p>
+ <math>
+ <mrow>
+ <mn>p</mn>
+ <mo lspace="0.2777777777777778em" rspace="0.2777777777777778em">X</mo> <!-- Single character -->
+ <mn>p</mn>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mn>p</mn>
+ <mo lspace="0.2777777777777778em" rspace="0.2777777777777778em">XX</mo> <!-- Multiple characters -->
+ <mn>p</mn>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mn>p</mn>
+ <mo form="infix" lspace="0.2777777777777778em" rspace="0.2777777777777778em">X</mo> <!-- Explicit form -->
+ <mn>p</mn>
+ </mrow>
+ </math>
+ </p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-not-in-dictionary-lspace-rspace.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-not-in-dictionary-lspace-rspace.html
new file mode 100644
index 0000000000..e6b5b172c3
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-not-in-dictionary-lspace-rspace.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>lspace/rspace default value for unknown operators</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <meta name="assert" content="Verifies that the default lspace/rspace are 0.2777777777777778em for entries that are not in the operator dictionary.">
+ <link rel="match" href="mo-not-in-dictionary-lspace-rspace-ref.html">
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math {
+ font: 100px/1 Ahem;
+ }
+ mo {
+ color: blue;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if on each row, the space around the blue rectangle
+ is 0.2777777777777778em.</p>
+ <p>
+ <math>
+ <mrow>
+ <mn>p</mn>
+ <mo>X</mo> <!-- Single character -->
+ <mn>p</mn>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mn>p</mn>
+ <mo>XX</mo> <!-- Multiple characters -->
+ <mn>p</mn>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mn>p</mn>
+ <mo form="infix">X</mo> <!-- Explicit form -->
+ <mn>p</mn>
+ </mrow>
+ </math>
+ </p>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_operator_spacing");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-not-in-dictionary-movablelimits-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-not-in-dictionary-movablelimits-ref.html
new file mode 100644
index 0000000000..e7ffc78994
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-not-in-dictionary-movablelimits-ref.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>movablelimits default value for unknown operators (reference)</title>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math {
+ font: 50px/1 Ahem;
+ }
+ mo {
+ color: blue;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if the black scripts are attached above and below
+ the corresponding blue base.</p>
+ <p>
+ <math>
+ <munderover>
+ <mo movablelimits="false">X</mo> <!-- Single character -->
+ <mn>X</mn>
+ <mn>X</mn>
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover>
+ <mo movablelimits="false">XX</mo> <!-- Multiple characters -->
+ <mn>X</mn>
+ <mn>X</mn>
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover>
+ <mo movablelimits="false" form="infix">X</mo> <!-- Explicit form -->
+ <mn>X</mn>
+ <mn>X</mn>
+ </munderover>
+ </math>
+ </p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-not-in-dictionary-movablelimits.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-not-in-dictionary-movablelimits.html
new file mode 100644
index 0000000000..8a96e31953
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-not-in-dictionary-movablelimits.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>movablelimits default value for unknown operators</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <meta name="assert" content="Verifies that the default movablelimits is false for entries that are not in the operator dictionary.">
+ <link rel="match" href="mo-not-in-dictionary-movablelimits-ref.html">
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math {
+ font: 50px/1 Ahem;
+ }
+ mo {
+ color: blue;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if the black scripts are attached above and below
+ the corresponding blue base.</p>
+ <p>
+ <math>
+ <munderover>
+ <mo>X</mo> <!-- Single character -->
+ <mn>X</mn>
+ <mn>X</mn>
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover>
+ <mo>XX</mo> <!-- Multiple characters -->
+ <mn>X</mn>
+ <mn>X</mn>
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover>
+ <mo form="infix">X</mo> <!-- Explicit form -->
+ <mn>X</mn>
+ <mn>X</mn>
+ </munderover>
+ </math>
+ </p>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_movablelimits");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-paint-lspace-rspace-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-paint-lspace-rspace-ref.html
new file mode 100644
index 0000000000..da0b79ff9a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-paint-lspace-rspace-ref.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>&lt;mo&gt; paint lspace rspace</title>
+ <meta charset="utf-8">
+ </head>
+ <body>
+ <h1>LTR case</h1>
+
+ <p>The test passes if the arrow has a leading space of 100px, which is as wide as the black block to the left,
+ and a trailing space of 200px, which is as wide as the black block to the right.</p>
+
+ <math>
+ <mspace width="100px" height="10px" depth="10px" style="background: black"></mspace>
+ <mspace width="100px"></mspace>
+ <mo lspace="0px" rspace="0px">→</mo>
+ <mspace width="200px"></mspace>
+ <mspace width="200px" height="10px" depth="10px" style="background: black"></mspace>
+ </math>
+
+ <p>The test passes if the arrow has a leading space of 150px, which is as wide as the black block to the left,
+ and a trailing space of 150px, which is as wide as the black block to the right.</p>
+
+ <math>
+ <mspace width="150px" height="10px" depth="10px" style="background: black"></mspace>
+ <mspace width="150px"></mspace>
+ <mo lspace="0px" rspace="0px">→</mo>
+ <mspace width="150px"></mspace>
+ <mspace width="150px" height="10px" depth="10px" style="background: black"></mspace>
+ </math>
+
+ <p>The test passes if the arrow has a leading space of 200px, which is as wide as the black block to the left,
+ and a trailing space of 100px, which is as wide as the black block to the right.</p>
+
+ <math>
+ <mspace width="200px" height="10px" depth="10px" style="background: black"></mspace>
+ <mspace width="200px"></mspace>
+ <mo lspace="0px" rspace="0px">→</mo>
+ <mspace width="100px"></mspace>
+ <mspace width="100px" height="10px" depth="10px" style="background: black"></mspace>
+ </math>
+
+ <h1>RTL case</h1>
+
+ <p>The test passes if the arrow has a leading space of 100px, which is as wide as the black block to the right,
+ and a trailing space of 200px, which is as wide as the black block to the left.</p>
+
+ <math dir="rtl">
+ <mspace width="100px" height="10px" depth="10px" style="background: black"></mspace>
+ <mspace width="100px"></mspace>
+ <mo lspace="0px" rspace="0px">→</mo>
+ <mspace width="200px"></mspace>
+ <mspace width="200px" height="10px" depth="10px" style="background: black"></mspace>
+ </math>
+
+ <p>The test passes if the arrow has a leading space of 150px, which is as wide as the black block to the right,
+ and a trailing space of 150px, which is as wide as the black block to the left.</p>
+
+ <math dir="rtl">
+ <mspace width="150px" height="10px" depth="10px" style="background: black"></mspace>
+ <mspace width="150px"></mspace>
+ <mo lspace="0px" rspace="0px">→</mo>
+ <mspace width="150px"></mspace>
+ <mspace width="150px" height="10px" depth="10px" style="background: black"></mspace>
+ </math>
+
+ <p>The test passes if the arrow has a leading space of 200px, which is as wide as the black block to the right,
+ and a trailing space of 100px, which is as wide as the black block to the left.</p>
+
+ <math dir="rtl">
+ <mspace width="200px" height="10px" depth="10px" style="background: black"></mspace>
+ <mspace width="200px"></mspace>
+ <mo lspace="0px" rspace="0px">→</mo>
+ <mspace width="100px"></mspace>
+ <mspace width="100px" height="10px" depth="10px" style="background: black"></mspace>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-paint-lspace-rspace.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-paint-lspace-rspace.html
new file mode 100644
index 0000000000..a3a3ed501e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-paint-lspace-rspace.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>&lt;mo&gt; paint lspace rspace</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <meta name="assert" content="Verifies values for lspace and rspace for element mo in LTR and RTL modes.">
+ <link rel="match" href="mo-paint-lspace-rspace-ref.html">
+ </head>
+ <body>
+ <h1>LTR case</h1>
+
+ <p>The test passes if the arrow has a leading space of 100px, which is as wide as the black block to the left,
+ and a trailing space of 200px, which is as wide as the black block to the right.</p>
+
+ <math>
+ <mspace width="100px" height="10px" depth="10px" style="background: black"></mspace>
+ <mo lspace="100px" rspace="200px">→</mo>
+ <mspace width="200px" height="10px" depth="10px" style="background: black"></mspace>
+ </math>
+
+ <p>The test passes if the arrow has a leading space of 150px, which is as wide as the black block to the left,
+ and a trailing space of 150px, which is as wide as the black block to the right.</p>
+
+ <math>
+ <mspace width="150px" height="10px" depth="10px" style="background: black"></mspace>
+ <mo lspace="150px" rspace="150px">→</mo>
+ <mspace width="150px" height="10px" depth="10px" style="background: black"></mspace>
+ </math>
+
+ <p>The test passes if the arrow has a leading space of 200px, which is as wide as the black block to the left,
+ and a trailing space of 100px, which is as wide as the black block to the right.</p>
+
+ <math>
+ <mspace width="200px" height="10px" depth="10px" style="background: black"></mspace>
+ <mo lspace="200px" rspace="100px">→</mo>
+ <mspace width="100px" height="10px" depth="10px" style="background: black"></mspace>
+ </math>
+
+ <h1>RTL case</h1>
+
+ <p>The test passes if the arrow has a leading space of 100px, which is as wide as the black block to the right,
+ and a trailing space of 200px, which is as wide as the black block to the left.</p>
+
+ <math dir="rtl">
+ <mspace width="100px" height="10px" depth="10px" style="background: black"></mspace>
+ <mo lspace="100px" rspace="200px">→</mo>
+ <mspace width="200px" height="10px" depth="10px" style="background: black"></mspace>
+ </math>
+
+ <p>The test passes if the arrow has a leading space of 150px, which is as wide as the black block to the right,
+ and a trailing space of 150px, which is as wide as the black block to the left.</p>
+
+ <math dir="rtl">
+ <mspace width="150px" height="10px" depth="10px" style="background: black"></mspace>
+ <mo lspace="150px" rspace="150px">→</mo>
+ <mspace width="150px" height="10px" depth="10px" style="background: black"></mspace>
+ </math>
+
+ <p>The test passes if the arrow has a leading space of 200px, which is as wide as the black block to the right,
+ and a trailing space of 100px, which is as wide as the black block to the left.</p>
+
+ <math dir="rtl">
+ <mspace width="200px" height="10px" depth="10px" style="background: black"></mspace>
+ <mo lspace="200px" rspace="100px">→</mo>
+ <mspace width="100px" height="10px" depth="10px" style="background: black"></mspace>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_operator_spacing");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-single-char-and-children-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-single-char-and-children-ref.html
new file mode 100644
index 0000000000..6b4ccc775c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-single-char-and-children-ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>&lt;mo&gt; with a single character and children (reference)</title>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css"/>
+ <style>
+ math { font: 25px/1 Ahem; }
+ </style>
+ </head>
+ <body>
+ <p>There should be 5/18em horizontal gaps around the middle rectangles:</p>
+ <p><math><mn>p</mn><mo><span>X</span></mo><mn>p</mn></math></p>
+ <p><math><mn>p</mn><mo>X<span></span></mo><mn>p</mn></math></p>
+ <p><math><mn>p</mn><mo><span></span>X</mo><mn>p</mn></math></p>
+ <p><math><mn>p</mn><mo id="dynamic-add">X</mo><mn>p</mn></math></p>
+ <p><math><mn>p</mn><mo id="dynamic-text-add">XX</mo><mn>p</mn></math></p>
+
+ <p>There should be no horizontal gap around the middle rectangles:</p>
+
+ <p><math><mn>p</mn><mo stretchy="false" lspace="0" rspace="0">X</mo><mn>p</mn></math></p>
+ <p><math><mn>p</mn><mo id="dynamic-remove" stretchy="false" lspace="0" rspace="0"><span></span>X</mo><mn>p</mn></math></p>
+ <p><math><mn>p</mn><mo stretchy="false" lspace="0" rspace="0"><!-- COMMENT -->X</mo><mn>p</mn></math></p>
+
+ <p>There should be 4/18em horizontal gaps around the middle rectangles:</p>
+ <p><math><mn>p</mn><mo lspace="0.2222222222222222em" rspace="0.2222222222222222em">XX</mo><mn>p</mn></math></p>
+ <p><math><mn>p</mn><mo id="dynamic-text-add-2" lspace="0.2222222222222222em" rspace="0.2222222222222222em">XX</mo><mn>p</mn></math></p>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-single-char-and-children.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-single-char-and-children.html
new file mode 100644
index 0000000000..a911c44411
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-single-char-and-children.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8">
+ <title>&lt;mo&gt; with a single character and children</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#dfn-algorithm-for-determining-the-properties-of-an-embellished-operator">
+ <meta name="assert" content="Verify that the default operator properties are used for an mo element whose text is a single character but which contains children.">
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css"/>
+ <link rel="match" href="mo-single-char-and-children-ref.html">
+ <style>
+ math { font: 25px/1 Ahem; }
+ </style>
+ </head>
+ <body>
+ <p>There should be 5/18em horizontal gaps around the middle rectangles:</p>
+ <p><math><mn>p</mn><mo><span>(</span></mo><mn>p</mn></math></p>
+ <p><math><mn>p</mn><mo>(<span></span></mo><mn>p</mn></math></p>
+ <p><math><mn>p</mn><mo><span></span>(</mo><mn>p</mn></math></p>
+ <p><math><mn>p</mn><mo id="dynamic-add">(</mo><mn>p</mn></math></p>
+ <p><math><mn>p</mn><mo id="dynamic-text-add">=</mo><mn>p</mn></math></p>
+
+ <p>There should be no horizontal gap around the middle rectangles:</p>
+
+ <p><math><mn>p</mn><mo stretchy="false">(</mo><mn>p</mn></math></p>
+ <p><math><mn>p</mn><mo id="dynamic-remove" stretchy="false"><span></span>(</mo><mn>p</mn></math></p>
+ <p><math><mn>p</mn><mo stretchy="false"><!-- COMMENT -->(</mo><mn>p</mn></math></p>
+
+ <p>There should be 4/18em horizontal gaps around the middle rectangles:</p>
+ <p><math><mn>p</mn><mo>&amp;<!-- COMMENT -->&amp;</mo><mn>p</mn></math></p>
+ <p><math><mn>p</mn><mo id="dynamic-text-add-2">&amp;</mo><mn>p</mn></math></p>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>
+ MathMLFeatureDetection.ensure_for_match_reftest("has_operator_spacing");
+
+ let mo = document.getElementById("dynamic-add");
+ mo.appendChild(document.createElement("span"));
+
+ mo = document.getElementById("dynamic-text-add");
+ mo.appendChild(document.createTextNode("="));
+
+ mo = document.getElementById("dynamic-text-add-2");
+ mo.appendChild(document.createTextNode("&"));
+
+ mo = document.getElementById("dynamic-remove");
+ mo.removeChild(mo.firstElementChild);
+
+ document.documentElement.classList.remove('reftest-wait');
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-stretch-properties-001.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-stretch-properties-001.html
new file mode 100644
index 0000000000..f734253930
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-stretch-properties-001.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Stretch properties</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<meta name="assert" content="Verify ">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math {
+ font: 25px/1 Ahem;
+ }
+ @font-face {
+ font-family: operators;
+ src: url("/fonts/math/operators.woff");
+ }
+ mo {
+ font-family: operators;
+ }
+</style>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+
+ var epsilon = 1;
+ var emToPx = 25;
+ var element;
+
+ test(function() {
+ element = document.getElementById("mn_vertical_line");
+ assert_approx_equals(element.getBoundingClientRect().height, 1 * emToPx, epsilon, "<mn> element");
+
+ element = document.getElementById("mo_prefix_vertical_line");
+ assert_approx_equals(element.getBoundingClientRect().height, 6 * emToPx, epsilon, "Prefix <mo> element");
+
+ element = document.getElementById("mo_infix_vertical_line");
+ assert_approx_equals(element.getBoundingClientRect().height, 1 * emToPx, epsilon, "Infix <mo> element");
+
+ element = document.getElementById("mo_postfix_vertical_line");
+ assert_approx_equals(element.getBoundingClientRect().height, 6 * emToPx, epsilon, "Postfix <mo> element");
+ }, `Stretchy vertical line`);
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mrow>
+ <!-- Some non-element nodes before -->
+ <mo id="mo_prefix_vertical_line" style="color: green">|</mo>
+ <mn id="mn_vertical_line">|</mn>
+ <mspace width="1em" height="3em" depth="3em" style="background: blue"/>
+ <mo id="mo_infix_vertical_line" lspace="0" rspace="0">|</mo>
+ <mo id="mo_postfix_vertical_line" style="color: green">|</mo>
+ <!-- Some non-element nodes after -->
+ </mrow>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/mo-stretch-properties-dynamic-001.html b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-stretch-properties-dynamic-001.html
new file mode 100644
index 0000000000..5d447aa1d2
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/mo-stretch-properties-dynamic-001.html
@@ -0,0 +1,154 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Dynamic stretch properties</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<meta name="assert" content="Verify stretchy, symmetric, largeop, minsize and maxsize are updated dynamically.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math {
+ font: 25px/1 Ahem;
+ }
+ @font-face {
+ font-family: operators;
+ src: url("/fonts/math/operators.woff");
+ }
+ mo {
+ font-family: operators;
+ }
+</style>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+
+ var epsilon = 1;
+ var emToPx = 25;
+ var element;
+
+ test(function() {
+ element = document.getElementById("minsize_attach");
+ element.setAttribute("minsize", "4em");
+ assert_approx_equals(element.getBoundingClientRect().height, 4 * emToPx, epsilon, "attach");
+
+ element = document.getElementById("minsize_modify");
+ element.setAttribute("minsize", "5em");
+ assert_approx_equals(element.getBoundingClientRect().height, 5 * emToPx, epsilon, "modify");
+
+ element = document.getElementById("minsize_remove");
+ element.removeAttribute("minsize");
+ assert_approx_equals(element.getBoundingClientRect().height, 1 * emToPx, epsilon, "remove");
+ }, `minsize`);
+
+ test(function() {
+ element = document.getElementById("maxsize_attach");
+ element.setAttribute("maxsize", "4em");
+ assert_approx_equals(element.getBoundingClientRect().height, 4 * emToPx, epsilon, "attach");
+
+ element = document.getElementById("maxsize_modify");
+ element.setAttribute("maxsize", "5em");
+ assert_approx_equals(element.getBoundingClientRect().height, 5 * emToPx, epsilon, "modify");
+
+ element = document.getElementById("maxsize_remove");
+ element.removeAttribute("maxsize");
+ assert_approx_equals(element.getBoundingClientRect().height, 6 * emToPx, epsilon, "remove");
+ }, `maxsize`);
+
+ test(function() {
+ element = document.getElementById("largeop_set_true");
+ element.setAttribute("largeop", "true");
+ assert_approx_equals(element.getBoundingClientRect().height, 2 * emToPx, epsilon, "set true");
+
+ element = document.getElementById("largeop_set_false");
+ element.setAttribute("largeop", "false");
+ assert_approx_equals(element.getBoundingClientRect().height, 1 * emToPx, epsilon, "set false");
+ }, `largeop`);
+
+ test(function() {
+ element = document.getElementById("symmetric_set_true");
+ element.setAttribute("symmetric", "true");
+ assert_approx_equals(element.getBoundingClientRect().height, 6 * emToPx, epsilon, "set true");
+
+ element = document.getElementById("symmetric_set_false");
+ element.setAttribute("symmetric", "false");
+ assert_approx_equals(element.getBoundingClientRect().height, 3 * emToPx, epsilon, "set false");
+ }, `symmetric`);
+
+ test(function() {
+ element = document.getElementById("stretchy_set_true");
+ element.setAttribute("stretchy", "true");
+ assert_approx_equals(element.getBoundingClientRect().height, 3 * emToPx, epsilon, "set true");
+
+ element = document.getElementById("stretchy_set_false");
+ element.setAttribute("stretchy", "false");
+ assert_approx_equals(element.getBoundingClientRect().height, 1 * emToPx, epsilon, "set false");
+ }, `stretchy`);
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mrow>
+ <mspace width="1em" height="1em" style="background: blue"/>
+ <mo id="minsize_attach" stretchy="true" symmetric="false">⥯</mo>
+ <mo id="minsize_modify" minsize="3em" stretchy="true" symmetric="false">⥯</mo>
+ <mo id="minsize_remove" minsize="2em" stretchy="true" symmetric="false">⥯</mo>
+ <mn><!-- not space like --></mn>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mspace width="1em" height="6em" style="background: blue"/>
+ <mo id="maxsize_attach" stretchy="true" symmetric="false">⥯</mo>
+ <mo id="maxsize_modify" maxsize="3em" stretchy="true" symmetric="false">⥯</mo>
+ <mo id="maxsize_remove" maxsize="2em" stretchy="true" symmetric="false">⥯</mo>
+ <mn><!-- not space like --></mn>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math displaystyle="true">
+ <mspace width="1em" height="1em" style="background: blue"/>
+ <mrow>
+ <mo id="largeop_set_true" largeop="false" stretchy="false">⥯</mo>
+ <mn><!-- not space like --></mn>
+ </mrow>
+ <mrow>
+ <mo id="largeop_set_false" largeop="true" stretchy="false">⥯</mo>
+ <mn><!-- not space like --></mn>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mspace width="1em" height="3em" style="background: blue"/>
+ <mo id="symmetric_set_true" symmetric="false" stretchy="true">⥯</mo>
+ <mo id="symmetric_set_false" symmetric="true" stretchy="true">⥯</mo>
+ <mn><!-- not space like --></mn>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mspace width="1em" height="3em" style="background: blue"/>
+ <mo id="stretchy_set_true" symmetric="false" stretchy="false">⥯</mo>
+ <mo id="stretchy_set_false" symmetric="false" stretchy="true">⥯</mo>
+ <mn><!-- not space like --></mn>
+ </mrow>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-1-notref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-1-notref.html
new file mode 100644
index 0000000000..5650be1936
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-1-notref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict mo form</title>
+</head>
+<body>
+ <math>
+ <mrow>
+ <mo form="prefix">+</mo>
+ <!-- need a second child to avoid zeroing dictionary spacing -->
+ <mn>1</mn>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-1.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-1.html
new file mode 100644
index 0000000000..cdfcca4a57
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict mo form</title>
+ <link rel="mismatch" href="op-dict-1-notref.html">
+</head>
+<body>
+ <math>
+ <mrow>
+ <mo form="infix">+</mo>
+ <mn>1</mn>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-12-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-12-ref.html
new file mode 100644
index 0000000000..3365b47d39
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-12-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict mo movablelimits</title>
+</head>
+<body>
+ <math>
+ <munder>
+ <mo>&sum;</mo>
+ <mi>x</mi>
+ </munder>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-12.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-12.html
new file mode 100644
index 0000000000..7d75c4c174
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-12.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict mo movablelimits</title>
+ <link rel="match" href="op-dict-12-ref.html">
+</head>
+<body>
+ <math>
+ <munder>
+ <mo movablelimits="true">&sum;</mo>
+ <mi>x</mi>
+ </munder>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-13-notref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-13-notref.html
new file mode 100644
index 0000000000..e9e7614836
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-13-notref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict mo movablelimits</title>
+</head>
+<body>
+ <math>
+ <munder>
+ <mo movablelimits="true">&sum;</mo>
+ <mi>x</mi>
+ </munder>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-13.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-13.html
new file mode 100644
index 0000000000..1b7c6bf38f
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-13.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict mo movablelimits</title>
+ <link rel="mismatch" href="op-dict-13-notref.html">
+</head>
+<body>
+ <math>
+ <munder>
+ <mo movablelimits="false">&sum;</mo>
+ <mi>x</mi>
+ </munder>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-2-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-2-ref.html
new file mode 100644
index 0000000000..9c910f8411
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-2-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict symmetric</title>
+</head>
+<body>
+ <math>
+ <mrow>
+ <mo symmetric="true">(</mo>
+ <mspace height="5em" depth="5em"/>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-2.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-2.html
new file mode 100644
index 0000000000..0a26fcae78
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-2.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict symmetric</title>
+ <link rel="match" href="op-dict-2-ref.html">
+</head>
+<body>
+ <math>
+ <mrow>
+ <mo>(</mo>
+ <mspace height="5em" depth="5em"/>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-3-notref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-3-notref.html
new file mode 100644
index 0000000000..9c910f8411
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-3-notref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict symmetric</title>
+</head>
+<body>
+ <math>
+ <mrow>
+ <mo symmetric="true">(</mo>
+ <mspace height="5em" depth="5em"/>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-3.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-3.html
new file mode 100644
index 0000000000..bf54ef8582
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-3.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict symmetric</title>
+ <link rel="mismatch" href="op-dict-3-notref.html">
+</head>
+<body>
+ <math>
+ <mrow>
+ <mo symmetric="false">(</mo>
+ <mspace height="5em" depth="5em"/>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-4-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-4-ref.html
new file mode 100644
index 0000000000..a501e45c8c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-4-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict stretchy</title>
+</head>
+<body>
+ <math>
+ <mrow>
+ <mo>(</mo>
+ <mfrac>
+ <mi>a</mi>
+ <mi>b</mi>
+ </mfrac>
+ <mo>)</mo>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-4.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-4.html
new file mode 100644
index 0000000000..f847890aa7
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-4.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict stretchy</title>
+ <link rel="match" href="op-dict-4-ref.html">
+</head>
+<body>
+ <math>
+ <mrow>
+ <mo stretchy="true">(</mo>
+ <mfrac>
+ <mi>a</mi>
+ <mi>b</mi>
+ </mfrac>
+ <mo stretchy="true">)</mo>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-5-notref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-5-notref.html
new file mode 100644
index 0000000000..7ab29e3769
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-5-notref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict stretchy</title>
+</head>
+<body>
+ <math>
+ <mrow>
+ <mo stretchy="false">(</mo>
+ <mfrac>
+ <mi>a</mi>
+ <mi>b</mi>
+ </mfrac>
+ <mo>)</mo>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-5.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-5.html
new file mode 100644
index 0000000000..8c8260d4cd
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-5.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict stretchy</title>
+ <link rel="mismatch" href="op-dict-5-notref.html">
+</head>
+<body>
+ <math>
+ <mrow>
+ <mo>(</mo>
+ <mfrac>
+ <mi>a</mi>
+ <mi>b</mi>
+ </mfrac>
+ <mo>)</mo>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-6-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-6-ref.html
new file mode 100644
index 0000000000..cb642c4928
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-6-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict largeop</title>
+</head>
+<body>
+ <math displaystyle="true">
+ <mrow>
+ <mo largeop="true">&#x2211;</mo>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-6.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-6.html
new file mode 100644
index 0000000000..6be4cc90a7
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-6.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict largeop</title>
+ <link rel="match" href="op-dict-6-ref.html">
+</head>
+<body>
+ <math displaystyle="true">
+ <mrow>
+ <mo>&#x2211;</mo>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-7-notref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-7-notref.html
new file mode 100644
index 0000000000..78dd195558
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-7-notref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict largeop</title>
+</head>
+<body>
+ <math displaystyle="true">
+ <mrow>
+ <mo>&#x2211;</mo>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-7.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-7.html
new file mode 100644
index 0000000000..04496eb4f3
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-7.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict largeop</title>
+ <link rel="mismatch" href="op-dict-7-notref.html">
+</head>
+<body>
+ <math displaystyle="true">
+ <mrow>
+ <mo largeop="false">&#x2211;</mo>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-8-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-8-ref.html
new file mode 100644
index 0000000000..b51ce01f36
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-8-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict lspace and rspace</title>
+</head>
+<body>
+ <math>
+ <mrow>
+ <mi>x</mi><mo form="prefix" lspace="0.16666666666666666em" rspace="0em">&#x2202;</mo><mi>y</mi>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-8.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-8.html
new file mode 100644
index 0000000000..0f9b81900e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-8.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict lspace and rspace</title>
+ <link rel="match" href="op-dict-8-ref.html">
+</head>
+<body>
+ <math>
+ <mrow>
+ <mi>x</mi><mo form="prefix">&#x2202;</mo><mi>y</mi>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-9-notref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-9-notref.html
new file mode 100644
index 0000000000..b976536fac
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-9-notref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict lspace and rspace</title>
+</head>
+<body>
+ <math>
+ <mrow>
+ <!-- This spacing was specified in older MathML specification, see
+ https://www.w3.org/TR/MathML3/appendixc.html -->
+ <mi>x</mi><mo form="prefix" lspace="0.1111111111111111em" rspace="0.05555555555555555em">&#x2202;</mo><mi>y</mi>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-9.html b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-9.html
new file mode 100644
index 0000000000..1e833e31a0
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/op-dict-9.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>op-dict lspace and rspace</title>
+ <link rel="mismatch" href="op-dict-9-notref.html">
+</head>
+<body>
+ <math>
+ <mrow>
+ <mi>x</mi><mo form="prefix">&#x2202;</mo><mi>y</mi>
+ </mrow>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-arabic-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-arabic-001-ref.html
new file mode 100644
index 0000000000..88e0f5f736
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-arabic-001-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Spacing of Arabic operators (reference)</title>
+ <link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+ <style>
+ mo {
+ color: blue;
+ }
+ </style>
+ </head>
+ <body>
+
+ <p>There should be no horizontal gaps between the squares:</p>
+ <p><math><mn>_</mn><mo lspace="0" rspace="0">&#x1EEF0;</mo><mn>_</mn></math></p>
+ <p><math><mn>_</mn><mo lspace="0" rspace="0">&#x1EEF1;</mo><mn>_</mn></math></p>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-arabic-001.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-arabic-001.html
new file mode 100644
index 0000000000..05d2714af5
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-arabic-001.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Spacing of Arabic operators</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+ <meta name="assert" content="Verifies default spacing of the Arabic characters U+1EEF0 and U+1EEF1.">
+ <link rel="match" href="operator-dictionary-arabic-001-ref.html">
+ <link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+ <style>
+ mo {
+ color: blue;
+ }
+ </style>
+ </head>
+ <body>
+
+ <p>There should be no horizontal gaps between the squares:</p>
+ <p><math><mn>_</mn><mo>&#x1EEF0;</mo><mn>_</mn></math></p>
+ <p><math><mn>_</mn><mo>&#x1EEF1;</mo><mn>_</mn></math></p>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>
+ MathMLFeatureDetection.ensure_for_match_reftest("has_operator_spacing");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-arabic-002-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-arabic-002-ref.html
new file mode 100644
index 0000000000..f72fdc8403
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-arabic-002-ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Stretching of Arabic operators (reference)</title>
+ <link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+ </head>
+ <body>
+
+ <p>You should see two rectangles of width 3em and height 1em:</p>
+
+ <p>
+ <math>
+ <munder>
+ <mo stretchy="true">_</mo>
+ <mspace width="3em"/>
+ </munder>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munder>
+ <mo stretchy="true">_</mo>
+ <mspace width="3em"/>
+ </munder>
+ </math>
+ </p>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-arabic-002.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-arabic-002.html
new file mode 100644
index 0000000000..d116e1778d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-arabic-002.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Stretching of Arabic operators</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+ <meta name="assert" content="Verifies stretchy property of the Arabic characters U+1EEF0 and U+1EEF1.">
+ <link rel="match" href="operator-dictionary-arabic-002-ref.html">
+ <link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+ </head>
+ <body>
+
+ <p>You should see two rectangles of width 3em and height 1em:</p>
+
+ <p>
+ <math>
+ <munder>
+ <mo>&#x1EEF0;</mo>
+ <mspace width="3em"/>
+ </munder>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munder>
+ <mo>&#x1EEF1;</mo>
+ <mspace width="3em"/>
+ </munder>
+ </math>
+ </p>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script src="/mathml/support/feature-detection-operators.js"></script>
+ <script>
+ MathMLFeatureDetection.ensure_for_match_reftest("has_operator_stretchy");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-combining.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-combining.html
new file mode 100644
index 0000000000..8c891a2a25
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-combining.html
@@ -0,0 +1,159 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary (combining char)</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-mrow">
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<meta name="assert" content="Verify special handling of 2-char operator with a combining character">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<style>
+ mo {
+ color: blue;
+ }
+ mn {
+ background: black;
+ }
+</style>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function spaceBetween(element, i, j) {
+ return element.children[j].getBoundingClientRect().left -
+ element.children[i].getBoundingClientRect().right;
+ }
+ function runTests() {
+ var epsilon = 1;
+ var emToPx = 25;
+
+ [
+ "equal",
+ "vertical_bar",
+ "left_normal_factor_semidirect_product",
+ "there_exists",
+ ].forEach(id => {
+ var div = document.getElementById(id);
+ var ref = div.getElementsByClassName("reference")[0];
+ var totalSpaceRef = spaceBetween(ref, 0, 2);
+ var lspaceRef = spaceBetween(ref, 0, 1);
+ var rspaceRef = spaceBetween(ref, 1, 2);
+ Array.from(div.getElementsByClassName("combining")).forEach(element => {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ var totalSpace = spaceBetween(element, 0, 2);
+ var lspace = spaceBetween(element, 0, 1);
+ var rspace = spaceBetween(element, 1, 2);
+ assert_approx_equals(totalSpace, totalSpaceRef, epsilon);
+ assert_approx_equals(rspace, rspaceRef, epsilon);
+ assert_approx_equals(lspace, lspaceRef, epsilon);
+ }, `Spacing around ${element.children[1].textContent}`);
+ });
+ });
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <div id="equal">
+ <p>
+ <math class="reference">
+ <mn>&nbsp;</mn>
+ <mo>=</mo>
+ <mn>&nbsp;</mn>
+ </math>
+ </p>
+ <p>
+ <math class="combining">
+ <mn>&nbsp;</mn>
+ <mo>=&#x338;</mo>
+ <mn>&nbsp;</mn>
+ </math>
+ </p>
+ <p>
+ <math class="combining">
+ <mn>&nbsp;</mn>
+ <mo>=&#x20D2;</mo>
+ <mn>&nbsp;</mn>
+ </math>
+ </p>
+ </div>
+ <div id="vertical_bar">
+ <p>
+ <math class="reference">
+ <mn>&nbsp;</mn>
+ <mo stretchy="false">|</mo>
+ <mn>&nbsp;</mn>
+ </math>
+ </p>
+ <p>
+ <math class="combining">
+ <mn>&nbsp;</mn>
+ <mo stretchy="false">|&#x338;</mo>
+ <mn>&nbsp;</mn>
+ </math>
+ </p>
+ <p>
+ <math class="combining">
+ <mn>&nbsp;</mn>
+ <mo stretchy="false">|&#x20D2;</mo>
+ <mn>&nbsp;</mn>
+ </math>
+ </p>
+ </div>
+ <div id="left_normal_factor_semidirect_product">
+ <p>
+ <math class="reference">
+ <mn>&nbsp;</mn>
+ <mo stretchy="false">⋉</mo>
+ <mn>&nbsp;</mn>
+ </math>
+ </p>
+ <p>
+ <math class="combining">
+ <mn>&nbsp;</mn>
+ <mo stretchy="false">⋉&#x338;</mo>
+ <mn>&nbsp;</mn>
+ </math>
+ </p>
+ <p>
+ <math class="combining">
+ <mn>&nbsp;</mn>
+ <mo stretchy="false">⋉&#x20D2;</mo>
+ <mn>&nbsp;</mn>
+ </math>
+ </p>
+ </div>
+ <div id="there_exists">
+ <p>
+ <math class="reference">
+ <mn>&nbsp;</mn>
+ <mo stretchy="false">∃</mo>
+ <mn>&nbsp;</mn>
+ </math>
+ </p>
+ <p>
+ <math class="combining">
+ <mn>&nbsp;</mn>
+ <mo stretchy="false">∃&#x338;</mo>
+ <mn>&nbsp;</mn>
+ </math>
+ </p>
+ <p>
+ <math class="combining">
+ <mn>&nbsp;</mn>
+ <mo stretchy="false">∃&#x20D2;</mo>
+ <mn>&nbsp;</mn>
+ </math>
+ </p>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-empty-and-three-chars-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-empty-and-three-chars-ref.html
new file mode 100644
index 0000000000..2cbed12940
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-empty-and-three-chars-ref.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Spacing of empty and three-char operators (reference)</title>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math {
+ font: 50px/1 Ahem;
+ }
+ mn:first-child {
+ color: blue;
+ }
+ mn:last-child {
+ color: yellow;
+ }
+ </style>
+ </head>
+ <body>
+
+ <p><math><mn>_</mn><mo lspace="0.2777777777777778em" rspace="0.2777777777777778em">_</mo><mn>_</mn></math></p>
+
+ <p>The spacing after the blue squares and before the yellow squares should be the same as the above reference:</p>
+
+ <p><math><mn>_</mn><mo lspace="0.2777777777777778em" rspace="0.2777777777777778em"><!-- empty --></mo><mn>_</mn></math></p>
+ <p><math><mn>_</mn><mo lspace="0.2777777777777778em" rspace="0.2777777777777778em">...</mo><mn>_</mn></math></p>
+ <p><math><mn>_</mn><mo lspace="0.2777777777777778em" rspace="0.2777777777777778em">lim</mo><mn>_</mn></math>
+ <p><math><mn>_</mn><mo lspace="0.2777777777777778em" rspace="0.2777777777777778em">max</mo><mn>_</mn></math>
+ <p><math><mn>_</mn><mo lspace="0.2777777777777778em" rspace="0.2777777777777778em">min</mo><mn>_</mn></math>
+ <p><math><mn>_</mn><mo lspace="0.2777777777777778em" rspace="0.2777777777777778em">|||</mo><mn>_</mn></math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-empty-and-three-chars.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-empty-and-three-chars.html
new file mode 100644
index 0000000000..231041c17f
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-empty-and-three-chars.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Spacing of empty and three-char operators</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+ <meta name="assert" content="Verifies that empty and three-char operators use the default spacing.">
+ <link rel="match" href="operator-dictionary-empty-and-three-chars-ref.html">
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math {
+ font: 50px/1 Ahem;
+ }
+ mn:first-child {
+ color: blue;
+ }
+ mn:last-child {
+ color: yellow;
+ }
+ </style>
+ </head>
+ <body>
+
+ <p><math><mn>_</mn><mo lspace="0.2777777777777778em" rspace="0.2777777777777778em">_</mo><mn>_</mn></math></p>
+
+ <p>The spacing after the blue squares and before the yellow squares should be the same as the above reference:</p>
+
+ <p><math><mn>_</mn><mo><!-- empty --></mo><mn>_</mn></math></p>
+ <p><math><mn>_</mn><mo>...</mo><mn>_</mn></math></p>
+ <p><math><mn>_</mn><mo>lim</mo><mn>_</mn></math>
+ <p><math><mn>_</mn><mo>max</mo><mn>_</mn></math>
+ <p><math><mn>_</mn><mo>min</mo><mn>_</mn></math>
+ <p><math><mn>_</mn><mo>|||</mo><mn>_</mn></math>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_operator_spacing");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-001.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-001.html
new file mode 100644
index 0000000000..457deb3422
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-001.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "largeop", 0);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-002.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-002.html
new file mode 100644
index 0000000000..5f132ac3b2
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-002.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "largeop", 1);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-003.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-003.html
new file mode 100644
index 0000000000..cb1b1e6b9b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-003.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "largeop", 2);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-004.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-004.html
new file mode 100644
index 0000000000..19a6f9b2f1
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-004.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "largeop", 3);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-005.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-005.html
new file mode 100644
index 0000000000..fd04712693
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-005.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "largeop", 4);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-006.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-006.html
new file mode 100644
index 0000000000..77d23f60f7
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-largeop-006.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "largeop", 5);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-001.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-001.html
new file mode 100644
index 0000000000..0a21e277b4
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-001.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "movablelimits", 0);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-002.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-002.html
new file mode 100644
index 0000000000..2d7dc414a0
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-002.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "movablelimits", 1);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-003.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-003.html
new file mode 100644
index 0000000000..e166d7ffbb
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-003.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "movablelimits", 2);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-004.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-004.html
new file mode 100644
index 0000000000..d5dd12b383
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-004.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "movablelimits", 3);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-005.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-005.html
new file mode 100644
index 0000000000..d8e96e17a6
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-005.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "movablelimits", 4);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-006.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-006.html
new file mode 100644
index 0000000000..a6ddeb92ff
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-movablelimits-006.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "movablelimits", 5);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-001.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-001.html
new file mode 100644
index 0000000000..6839b183be
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-001.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "lspace/rspace", 0);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-002.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-002.html
new file mode 100644
index 0000000000..84113a9ac8
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-002.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "lspace/rspace", 1);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-003.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-003.html
new file mode 100644
index 0000000000..387f61922d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-003.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "lspace/rspace", 2);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-004.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-004.html
new file mode 100644
index 0000000000..b27024c2d3
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-004.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "lspace/rspace", 3);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-005.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-005.html
new file mode 100644
index 0000000000..7acf5ab20e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-005.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "lspace/rspace", 4);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-006.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-006.html
new file mode 100644
index 0000000000..928182cbe6
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-spacing-006.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "lspace/rspace", 5);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-001.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-001.html
new file mode 100644
index 0000000000..beebe77ed7
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-001.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "stretchy", 0);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-002.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-002.html
new file mode 100644
index 0000000000..2cdf0114db
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-002.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "stretchy", 1);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-003.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-003.html
new file mode 100644
index 0000000000..4f0f0b3641
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-003.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "stretchy", 2);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-004.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-004.html
new file mode 100644
index 0000000000..08428b8928
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-004.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "stretchy", 3);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-005.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-005.html
new file mode 100644
index 0000000000..94fe507755
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-005.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "stretchy", 4);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-006.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-006.html
new file mode 100644
index 0000000000..c4d5e44d43
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-stretchy-006.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "stretchy", 5);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-001.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-001.html
new file mode 100644
index 0000000000..c1154cebf5
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-001.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "symmetric", 0);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-002.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-002.html
new file mode 100644
index 0000000000..3cb4b07a55
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-002.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "symmetric", 1);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-003.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-003.html
new file mode 100644
index 0000000000..7588df48f8
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-003.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "symmetric", 2);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-004.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-004.html
new file mode 100644
index 0000000000..f7d8bdc89d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-004.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "symmetric", 3);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-005.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-005.html
new file mode 100644
index 0000000000..9303b9a482
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-005.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "symmetric", 4);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-006.html b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-006.html
new file mode 100644
index 0000000000..90a812786a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/operator-dictionary-symmetric-006.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Operator dictionary</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dictionary-based-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+<link rel="help" href="https://w3c.github.io/mathml-core/#stretchy-operator-axis">
+<meta name="assert" content="Verify default properties for characters that are in the operator dictionary, as well as for U+00A0 NO-BREAK SPACE">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/feature-detection-operators.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/operator-dictionary.js"></script>
+<script src="./support/operator-dictionary-tests.js"></script>
+<link rel="stylesheet" href="./support/operator-dictionary-tests.css"/>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ async function runTests() {
+ let json = await fetchOperatorDictionary();
+ await OperatorDictionaryTests.run(json, "symmetric", 5);
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/painting-stretchy-operator-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/operators/painting-stretchy-operator-001-ref.html
new file mode 100644
index 0000000000..0c7642a20a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/painting-stretchy-operator-001-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Painting of vertical assembly (reference)</title>
+<style>
+ .container {
+ font-size: 50px;
+ position: absolute;
+ left: 1em;
+ top: 1em;
+ padding: 5px;
+ background: green;
+ width: 4em;
+ height: 8em;
+ }
+</style>
+<body>
+ <p>This test passes if you see a green rectangle and no red.</p>
+ <div class="container">
+ </div>
+</body>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/painting-stretchy-operator-001.html b/testing/web-platform/tests/mathml/presentation-markup/operators/painting-stretchy-operator-001.html
new file mode 100644
index 0000000000..2a9578badc
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/painting-stretchy-operator-001.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>Painting of vertical assembly</title>
+<link rel="match" href="painting-stretchy-operator-001-ref.html">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://crbug.com/1409380">
+<meta name="assert" content="Verify that vertical glyph assemblies are painted at the position of their bounding box.">
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ .container {
+ font-size: 50px;
+ position: absolute;
+ left: 1em;
+ top: 1em;
+ padding: 5px;
+ background: green;
+ width: 4em;
+ height: 8em;
+ }
+ mo {
+ color: green;
+ background: red;
+ }
+ .frame {
+ position: absolute;
+ box-sizing: border-box;
+ border: 2px solid green;
+ }
+ @font-face {
+ font-family: stretchy;
+ src: url("/fonts/math/stretchy.woff");
+ }
+ @font-face {
+ font-family: stretchy-centered-on-baseline;
+ src: url("/fonts/math/stretchy-centered-on-baseline.woff");
+ }
+</style>
+<script>
+ function runTests() {
+ // Add a green frame around mo to avoid antialisasing/rounding issues.
+ Array.from(document.getElementsByTagName('mo')).forEach(mo => {
+ let box = mo.getBoundingClientRect();
+ let div = document.createElement("div");
+ div.className = 'frame';
+ div.style.left = `${box.left-1}px`;
+ div.style.top = `${box.top-1}px`;
+ div.style.width = `${box.width+1}px`;
+ div.style.height = `${box.height+1}px`;
+ document.body.appendChild(div);
+ });
+ document.documentElement.classList.remove("reftest-wait");
+ }
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+</script>
+<body>
+ <p>This test passes if you see a green rectangle and no red.</p>
+ <div class="container">
+ <!-- This font uses assembly glyphs with zero ink descent, which is what
+ Latin Modern Math does for U+007C VERTICAL LINE. -->
+ <math style="font-family: stretchy">
+ <mspace height="4em"/>
+ <mo stretchy="true" symmetric="true">&#x295C;</mo>
+ </math>
+ <!-- This font uses assembly glyphs with non-zero ink descent, which is what
+ Cambria Math does for U+007C VERTICAL LINE. -->
+ <math style="font-family: stretchy-centered-on-baseline">
+ <mspace height="4em"/>
+ <mo stretchy="true" symmetric="true">&#x295C;</mo>
+ </math>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/support/operator-dictionary-tests.css b/testing/web-platform/tests/mathml/presentation-markup/operators/support/operator-dictionary-tests.css
new file mode 100644
index 0000000000..4f80ad7f8d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/support/operator-dictionary-tests.css
@@ -0,0 +1,10 @@
+@font-face {
+ font-family: operators;
+ src: url("/fonts/math/operators.woff");
+}
+math, math * {
+ font-family: operators;
+ /* Use large enough font-size so that 1/18em = 2.77px > epsilon and
+ one can really distinguish lspace/rspace values. */
+ font-size: 50px;
+}
diff --git a/testing/web-platform/tests/mathml/presentation-markup/operators/support/operator-dictionary-tests.js b/testing/web-platform/tests/mathml/presentation-markup/operators/support/operator-dictionary-tests.js
new file mode 100644
index 0000000000..35efc2ecb9
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/operators/support/operator-dictionary-tests.js
@@ -0,0 +1,226 @@
+var OperatorDictionaryTests = {
+ "lspace/rspace": function(json, key) {
+ let parsedKey = splitKey(key);
+ let entry = json.dictionary[key];
+ let epsilon = 1;
+
+ document.body.insertAdjacentHTML("beforeend", `<div>\
+lspace/rspace for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+ <mrow>\
+ <mn>&nbsp;</mn>\
+ <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
+ <mn>&nbsp;</mn>\
+ </mrow>\
+</math>\
+ VS \
+<math>\
+ <mrow>\
+ <mn>&nbsp;</mn>\
+ <mo form="${parsedKey.form}" lspace="${defaultPropertyValue(entry, 'lspace')}" rspace="${defaultPropertyValue(entry, 'rspace')}">${parsedKey.characters}</mo>\
+ <mn>&nbsp;</mn>\
+ </mrow>\
+</math>\
+</div>`);
+ var div = document.body.lastElementChild;
+ var mrows = div.getElementsByTagName("mrow");
+ function spaceBetween(element, i, j) {
+ return element.children[j].getBoundingClientRect().left -
+ element.children[i].getBoundingClientRect().right;
+ }
+ var lspace = spaceBetween(mrows[0], 0, 1);
+ var rspace = spaceBetween(mrows[0], 1, 2);
+ var lspaceRef = spaceBetween(mrows[1], 0, 1);
+ var rspaceRef = spaceBetween(mrows[1], 1, 2);
+ assert_approx_equals(lspace, lspaceRef, epsilon, `lspace (${key})`);
+ assert_approx_equals(rspace, rspaceRef, epsilon, `rspace (${key})`);
+ div.style.display = "none";
+ },
+
+ "movablelimits": function(json, key) {
+ let parsedKey = splitKey(key);
+ let entry = json.dictionary[key];
+ let epsilon = 1;
+
+ var defaultValue = defaultPropertyValue(entry, "movablelimits");
+ document.body.insertAdjacentHTML("beforeend", `<div>\
+movablelimits for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+ <munder>\
+ <mo stretchy="false" form="${parsedKey.form}">${parsedKey.characters}</mo>\
+ <mn>&nbsp;</mn>\
+ </munder>\
+</math>\
+ VS \
+<math>\
+ <munder>\
+ <mo stretchy="false" form="${parsedKey.form}" movablelimits="${defaultValue}">${parsedKey.characters}</mo>\
+ <mn>&nbsp;</mn>\
+ </munder>\
+</math>\
+</div>`);
+ var div = document.body.lastElementChild;
+ var munders = div.getElementsByTagName("munder");
+ munder = munders[0].getBoundingClientRect()
+ munderRef = munders[1].getBoundingClientRect()
+ assert_approx_equals(munder.height, munderRef.height, epsilon, `Movablelimits property for ${key} should be '${defaultValue}'`);
+ div.style.display = "none";
+ },
+
+ "largeop": function(json, key) {
+ let parsedKey = splitKey(key);
+ let entry = json.dictionary[key];
+ let epsilon = 1;
+
+ var defaultValue = defaultPropertyValue(entry, "largeop");
+ document.body.insertAdjacentHTML("beforeend", `<div>\
+largeop for "${parsedKey.characters}" (${parsedKey.form}): \
+<math displaystyle="true">\
+ <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
+</math>\
+ VS \
+<math displaystyle="true">\
+ <mo form="${parsedKey.form}" largeop="${defaultValue}">${parsedKey.characters}</mo>\
+</math>\
+</div>`);
+ var div = document.body.lastElementChild;
+ var mos = div.getElementsByTagName("mo");
+ mo = mos[0].getBoundingClientRect()
+ moRef = mos[1].getBoundingClientRect()
+ assert_approx_equals(mo.height, moRef.height, epsilon, `Largeop property for ${key} should be '${defaultValue}'`);
+ div.style.display = "none";
+ },
+
+ "stretchy": function(json, key) {
+ let parsedKey = splitKey(key);
+ let entry = json.dictionary[key];
+ let epsilon = 1;
+
+ if (entry.horizontal) {
+ // FIXME: Should really do a MathMLFeatureDetection to verify
+ // support for *horizontal* stretching.
+ var defaultValue = defaultPropertyValue(entry, "stretchy");
+ document.body.insertAdjacentHTML("beforeend", `<div>\
+stretchy for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+ <munder>\
+ <mn>&nbsp;&nbsp;</mn>\
+ <mo form="${parsedKey.form}">${parsedKey.characters}</mo>\
+ </munder>\
+</math>\
+ VS \
+<math>\
+ <munder>\
+ <mn>&nbsp;&nbsp;</mn>\
+ <mo form="${parsedKey.form}" stretchy="${defaultValue}">${parsedKey.characters}</mo>\
+ </munder>\
+</math>\
+</div>`);
+ var div = document.body.lastElementChild;
+ var mos = div.getElementsByTagName("mo");
+ mo = mos[0].getBoundingClientRect()
+ moRef = mos[1].getBoundingClientRect()
+ assert_approx_equals(mo.width, moRef.width, epsilon, `Stretchy property for ${key} should be '${defaultValue}'`);
+ div.style.display = "none";
+ } else {
+ var defaultValue = defaultPropertyValue(entry, "stretchy");
+ document.body.insertAdjacentHTML("beforeend", `<div>\
+stretchy for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+ <mrow>\
+ <mo form="${parsedKey.form}" symmetric="false">${parsedKey.characters}</mo>\
+ <mspace height="2em"></mspace>\
+ </mrow>\
+</math>\
+ VS \
+<math>\
+ <mrow>\
+ <mo form="${parsedKey.form}" symmetric="false" stretchy="${defaultValue}">${parsedKey.characters}</mo>\
+ <mspace height="2em"></mspace>\
+ </mrow>\
+</math>\
+</div>`);
+ var div = document.body.lastElementChild;
+ var mos = div.getElementsByTagName("mo");
+ mo = mos[0].getBoundingClientRect()
+ moRef = mos[1].getBoundingClientRect()
+ assert_approx_equals(mo.height, moRef.height, epsilon, `Stretchy property for ${key} should be '${defaultValue}'`);
+ div.style.display = "none";
+ }
+ },
+
+ "symmetric": function(json, key) {
+ let parsedKey = splitKey(key);
+ let entry = json.dictionary[key];
+ let epsilon = 1;
+
+ var defaultValue = defaultPropertyValue(entry, "symmetric");
+ document.body.insertAdjacentHTML("beforeend", `<div>\
+symmetric for "${parsedKey.characters}" (${parsedKey.form}): \
+<math>\
+ <mrow>\
+ <mo form="${parsedKey.form}" stretchy="true">${parsedKey.characters}</mo>\
+ <mspace height="1.5em"></mspace>\
+ </mrow>\
+</math>\
+ VS \
+<math>\
+ <mrow>\
+ <mo form="${parsedKey.form}" stretchy="true" symmetric="${defaultValue}">${parsedKey.characters}</mo>\
+ <mspace height="1.5em"></mspace>\
+ </mrow>\
+</math>\
+</div>`);
+ var div = document.body.lastElementChild;
+ var mos = div.getElementsByTagName("mo");
+ mo = mos[0].getBoundingClientRect()
+ moRef = mos[1].getBoundingClientRect()
+ assert_approx_equals(mo.height, moRef.height, epsilon, `Symmetric property for ${key} should be '${defaultValue}'`);
+ div.style.display = "none";
+ },
+
+ run: async function(json, name, fileIndex) {
+ let has_required_feature_for_testing =
+ await MathMLFeatureDetection[`has_operator_${name}`]();
+
+ // The operator dictionary has more than one thousand of entries so the
+ // tests are grouped in chunks so that these don't get much more
+ // importance than other MathML tests. For easy debugging, one can set the
+ // chunk size to 1. Also, note that the test div will remain visible for
+ // failed tests.
+ const entryPerChunk = 50
+ const filesPerProperty = 6
+
+ var counter = 0;
+ var test;
+
+ for (key in json.dictionary) {
+
+ // Skip this key if it does not belong to that test file.
+ if (counter % filesPerProperty != fileIndex) {
+ counter++;
+ continue;
+ }
+
+ var counterInFile = (counter - fileIndex) / filesPerProperty;
+ if (counterInFile % entryPerChunk === 0) {
+ // Start of a new chunk.
+ // Complete current async tests and create new ones for the next chunk.
+ if (test) test.done();
+ test = async_test(`Operator dictionary chunk ${1 + counterInFile / entryPerChunk} - ${name}`);
+
+ test.step(function() {
+ assert_true(has_required_feature_for_testing, `${name} is supported`);
+ });
+ }
+ test.step(function() {
+ OperatorDictionaryTests[name](json, key);
+ });
+
+ counter++;
+ }
+
+ // Complete current async test.
+ if (test) test.done();
+ }
+};
diff --git a/testing/web-platform/tests/mathml/presentation-markup/radicals/dynamic-radical-paint-invalidation-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/radicals/dynamic-radical-paint-invalidation-001-ref.html
new file mode 100644
index 0000000000..632d6739db
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/radicals/dynamic-radical-paint-invalidation-001-ref.html
@@ -0,0 +1,125 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Dynamic radical: paint invalidation (expectation)</title>
+<style>
+ @font-face {
+ font-family: RadicalFont;
+ src: url("/fonts/math/radical-displaystyleverticalgap7000-rulethickness1000.woff");
+ }
+ math {
+ font-family: RadicalFont;
+ font-size: 10px;
+ }
+ #container > div {
+ height: 80px;
+ border-top: solid;
+ }
+ .withPaddingBorderAndMargin {
+ padding: 5px;
+ border: 5px solid yellow;
+ margin: 5px;
+ }
+</style>
+</head>
+<body>
+ <div id="container">
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <msqrt>
+ <mspace width="60px" height="10px" depth="10px" style="background: blue"/>
+ </msqrt>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <mroot>
+ <mspace width="60px" height="10px" depth="10px" style="background: blue"/>
+ <mspace width="20px" height="10px" depth="10px" style="background: lightblue"/>
+ </mroot>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <msqrt>
+ <mspace width="20px" height="20px" depth="10px" style="background: blue"/>
+ </msqrt>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <mroot>
+ <mspace width="20px" height="20px" depth="10px" style="background: blue"/>
+ <mspace width="20px" height="10px" depth="10px" style="background: lightblue"/>
+ </mroot>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <msqrt>
+ <mspace width="20px" height="10px" depth="40px" style="background: blue"/>
+ </msqrt>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <mroot>
+ <mspace width="20px" height="10px" depth="40px" style="background: blue"/>
+ <mspace width="20px" height="10px" depth="10px" style="background: lightblue"/>
+ </mroot>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <msqrt>
+ <mspace width="20px" height="10px" depth="10px" style="background: blue"/>
+ </msqrt>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <mroot>
+ <mspace width="20px" height="10px" depth="10px" style="background: blue"/>
+ <mspace width="20px" height="10px" depth="10px" style="background: lightblue"/>
+ </mroot>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <msqrt class="withPaddingBorderAndMargin">
+ <mspace width="20px" height="10px" depth="10px" style="background: blue"/>
+ </msqrt>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <mroot class="withPaddingBorderAndMargin">
+ <mspace width="20px" height="10px" depth="10px" style="background: blue"/>
+ <mspace width="20px" height="10px" depth="10px" style="background: lightblue"/>
+ </mroot>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/radicals/dynamic-radical-paint-invalidation-001.html b/testing/web-platform/tests/mathml/presentation-markup/radicals/dynamic-radical-paint-invalidation-001.html
new file mode 100644
index 0000000000..4e9375842d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/radicals/dynamic-radical-paint-invalidation-001.html
@@ -0,0 +1,167 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>Dynamic radical: paint invalidation</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#radicals-msqrt-mroot">
+<meta name="assert" content="">
+<link rel="match" href="dynamic-radical-paint-invalidation-001-ref.html">
+<style>
+ @font-face {
+ font-family: RadicalFont;
+ src: url("/fonts/math/radical-displaystyleverticalgap7000-rulethickness1000.woff");
+ }
+ @font-face {
+ font-family: RadicalFont2;
+ src: url("/fonts/math/radical-kernbeforedegree4000-rulethickness1000.woff");
+ }
+ math {
+ font-family: RadicalFont;
+ font-size: 10px;
+ }
+ #container > div {
+ height: 80px;
+ border-top: solid;
+ }
+ .withPaddingBorderAndMargin {
+ padding: 5px;
+ border: 5px solid yellow;
+ margin: 5px;
+ }
+</style>
+<script src="/mathml/support/fonts.js"></script>
+<script>
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ function runTests() {
+ // force initial layout so we're sure what we're testing against
+ document.documentElement.getBoundingClientRect();
+
+ var mroot = document.getElementsByTagName("mroot");
+ var msqrt = document.getElementsByTagName("msqrt");
+
+ // Modify base's width.
+ msqrt[0].firstElementChild.setAttribute("width", "60px")
+ mroot[0].firstElementChild.setAttribute("width", "60px")
+
+ // Modify base's ascent.
+ msqrt[1].firstElementChild.setAttribute("height", "20px")
+ mroot[1].firstElementChild.setAttribute("height", "20px")
+
+ // Modify base's descent.
+ msqrt[2].firstElementChild.setAttribute("depth", "40px")
+ mroot[2].firstElementChild.setAttribute("depth", "40px")
+
+ // Modify the radical's font family.
+ msqrt[3].parentNode.removeAttribute("style");
+ mroot[3].parentNode.removeAttribute("style");
+
+ // Modify radical's margin/border/padding
+ msqrt[4].setAttribute("class", "withPaddingBorderAndMargin");
+ mroot[4].setAttribute("class", "withPaddingBorderAndMargin");
+
+ document.documentElement.classList.remove('reftest-wait');
+ };
+</script>
+</head>
+<body>
+ <div id="container">
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <msqrt>
+ <mspace width="20px" height="10px" depth="10px" style="background: blue"/>
+ </msqrt>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <mroot>
+ <mspace width="20px" height="10px" depth="10px" style="background: blue"/>
+ <mspace width="20px" height="10px" depth="10px" style="background: lightblue"/>
+ </mroot>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <msqrt>
+ <mspace width="20px" height="10px" depth="10px" style="background: blue"/>
+ </msqrt>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <mroot>
+ <mspace width="20px" height="10px" depth="10px" style="background: blue"/>
+ <mspace width="20px" height="10px" depth="10px" style="background: lightblue"/>
+ </mroot>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <msqrt>
+ <mspace width="20px" height="10px" depth="10px" style="background: blue"/>
+ </msqrt>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <mroot>
+ <mspace width="20px" height="10px" depth="10px" style="background: blue"/>
+ <mspace width="20px" height="10px" depth="10px" style="background: lightblue"/>
+ </mroot>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math style="font-family: RadicalFont2">
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <msqrt>
+ <mspace width="20px" height="10px" depth="10px" style="background: blue"/>
+ </msqrt>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math style="font-family: RadicalFont2">
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <mroot>
+ <mspace width="20px" height="10px" depth="10px" style="background: blue"/>
+ <mspace width="20px" height="10px" depth="10px" style="background: lightblue"/>
+ </mroot>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <msqrt>
+ <mspace width="20px" height="10px" depth="10px" style="background: blue"/>
+ </msqrt>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ <div>
+ <math>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ <mroot>
+ <mspace width="20px" height="10px" depth="10px" style="background: blue"/>
+ <mspace width="20px" height="10px" depth="10px" style="background: lightblue"/>
+ </mroot>
+ <mspace width="20px" height="10px" depth="10px" style="background: gray"/>
+ </math>
+ </div>
+ </div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/radicals/radical-rendering-from-in-flow-ref.html b/testing/web-platform/tests/mathml/presentation-markup/radicals/radical-rendering-from-in-flow-ref.html
new file mode 100644
index 0000000000..e1b8c3d161
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/radicals/radical-rendering-from-in-flow-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>radicals rendering from in-flow children</title>
+ </head>
+ <body>
+ <math>
+ <msqrt>
+ <mspace width="64px" height="8px" style="background: lightblue"></mspace>
+ </msqrt>
+ <mroot>
+ <mspace width="64px" height="12px" style="background: lightblue"></mspace>
+ <mspace width="128px" height="24px" style="background: lightgreen"></mspace>
+ </mroot>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/radicals/radical-rendering-from-in-flow.html b/testing/web-platform/tests/mathml/presentation-markup/radicals/radical-rendering-from-in-flow.html
new file mode 100644
index 0000000000..7a5de3811b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/radicals/radical-rendering-from-in-flow.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>radicals rendering from in-flow children</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#radicals-msqrt-mroot">
+ <meta name="assert" content="Verify rendering of radicals is only affected by in-flow children.">
+ <style>
+ .oof1 {
+ position: absolute;
+ }
+ .oof2 {
+ position: fixed;
+ }
+ .nobox {
+ display: none;
+ }
+ </style>
+ <link rel="match" href="radical-rendering-from-in-flow-ref.html">
+ </head>
+ <body>
+ <math>
+ <msqrt>
+ <mspace width="32px" class="oof1"/>
+ <mspace width="16px" class="oof2"/>
+ <mspace width="8px" class="nobox"/>
+ <mspace width="64px" height="8px" style="background: lightblue"></mspace>
+ <mspace width="32px" class="oof1"/>
+ <mspace width="16px" class="oof2"/>
+ <mspace width="8px" class="nobox"/>
+ </msqrt>
+ <mroot>
+ <mspace width="32px" class="oof1"/>
+ <mspace width="16px" class="oof2"/>
+ <mspace width="8px" class="nobox"/>
+ <mspace width="64px" height="12px" style="background: lightblue"></mspace>
+ <mspace width="32px" class="oof1"/>
+ <mspace width="16px" class="oof2"/>
+ <mspace width="8px" class="nobox"/>
+ <mspace width="128px" height="24px" style="background: lightgreen"></mspace>
+ <mspace width="32px" class="oof1"/>
+ <mspace width="16px" class="oof2"/>
+ <mspace width="8px" class="nobox"/>
+ </mroot>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_msqrt");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/radicals/root-parameters-1.html b/testing/web-platform/tests/mathml/presentation-markup/radicals/root-parameters-1.html
new file mode 100644
index 0000000000..7600c35c59
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/radicals/root-parameters-1.html
@@ -0,0 +1,222 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Radical parameters</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#radicals-msqrt-mroot">
+<meta name="assert" content="Elements msqrt and mroot correctly use the radical parameters from the MATH table.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math, mspace {
+ font-size: 10px;
+ }
+ @font-face {
+ font-family: degreebottomraisepercent25-rulethickness1000;
+ src: url("/fonts/math/radical-degreebottomraisepercent25-rulethickness1000.woff");
+ }
+ @font-face {
+ font-family: displaystyleverticalgap7000-rulethickness1000;
+ src: url("/fonts/math/radical-displaystyleverticalgap7000-rulethickness1000.woff");
+ }
+ @font-face {
+ font-family: extraascender3000-rulethickness1000;
+ src: url("/fonts/math/radical-extraascender3000-rulethickness1000.woff");
+ }
+ @font-face {
+ font-family: kernafterdegreeminus5000-rulethickness1000;
+ src: url("/fonts/math/radical-kernafterdegreeminus5000-rulethickness1000.woff");
+ }
+ @font-face {
+ font-family: kernbeforedegree4000-rulethickness1000;
+ src: url("/fonts/math/radical-kernbeforedegree4000-rulethickness1000.woff");
+ }
+ @font-face {
+ font-family: verticalgap6000-rulethickness1000;
+ src: url("/fonts/math/radical-verticalgap6000-rulethickness1000.woff");
+ }
+ @font-face {
+ font-family: rulethickness8000;
+ src: url("/fonts/math/radical-rulethickness8000.woff");
+ }
+</style>
+<script>
+ var emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+ var epsilon = 1;
+
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 25;
+ var v2 = 1000 * emToPx;
+ var radicalHeight = getBox("base001").height + v2;
+ assert_approx_equals(getBox("ref001").top - getBox("index001").bottom,
+ v1 * radicalHeight / 100, epsilon,
+ "mroot: vertical position of index");
+ }, "RadicalDegreeBottomRaisePercent");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 7000 * emToPx;
+ var v2 = 1000 * emToPx;
+ assert_approx_equals(getBox("base0021").top - getBox("radical0021").top,
+ v1 + v2, epsilon,
+ "msqrt: vertical gap");
+ assert_approx_equals(getBox("base0022").top - getBox("radical0022").top,
+ v1 + v2, epsilon,
+ "mroot: vertical gap");
+ }, "RadicalDisplayStyleVerticalGap");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 3000 * emToPx;
+ var v2 = 1000 * emToPx;
+ assert_approx_equals(getBox("base0031").top - getBox("radical0031").top,
+ v1 + v2, epsilon,
+ "msqrt: vertical gap");
+ assert_approx_equals(getBox("base0032").top - getBox("radical0032").top,
+ v1 + v2, epsilon,
+ "mroot: vertical gap");
+ }, "RadicalExtraAscender");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ // Note: the size variants of U+221A in this font have width 1000.
+ var v1 = 5000 * emToPx;
+ var radicalSymbolWidth = 1000 * emToPx;
+ var radicalLeft = getBox("base004").left - radicalSymbolWidth;
+ assert_approx_equals(getBox("index004").right - radicalLeft,
+ v1, epsilon,
+ "mroot: kern after degree");
+ }, "RadicalKernAfterDegree");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 4000 * emToPx;
+ assert_approx_equals(getBox("index005").left - getBox("radical005").left,
+ v1, epsilon,
+ "mroot: kern before degree");
+ }, "RadicalKernBeforeDegree");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 8000 * emToPx;
+ assert_approx_equals(getBox("base0061").top - getBox("radical0061").top,
+ v, epsilon,
+ "msqrt: vertical gap");
+ assert_approx_equals(getBox("base0062").top - getBox("radical0062").top,
+ v, epsilon,
+ "msqrt: vertical gap");
+ }, "RadicalRuleThickness");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 6000 * emToPx;
+ var v2 = 1000 * emToPx;
+ assert_approx_equals(getBox("base0071").top - getBox("radical0071").top,
+ v1 + v2, epsilon,
+ "msqrt: vertical gap");
+ assert_approx_equals(getBox("base0072").top - getBox("radical0072").top,
+ v1 + v2, epsilon,
+ "msqrt: vertical gap");
+ }, "RadicalVerticalGap");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math style="font-family: degreebottomraisepercent25-rulethickness1000;">
+ <mspace id="ref001" width="3em" depth="1em" style="background: green"/>
+ <mroot>
+ <mspace id="base001" width="3em" height="10em" style="background: green"/>
+ <mspace id="index001" width="3em" height="1em" style="background: blue"/>
+ </mroot>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math display="block"
+ style="font-family: displaystyleverticalgap7000-rulethickness1000;">
+ <msqrt style="background: green" id="radical0021">
+ <mspace id="base0021" width="3em" height="1em" style="background: blue"/>
+ </msqrt>
+ <mroot style="background: green" id="radical0022">
+ <mspace id="base0022" width="3em" height="1em" style="background: blue"/>
+ <mspace width="3em" height="1em" style="background: black"/>
+ </mroot>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: extraascender3000-rulethickness1000;">
+ <msqrt style="background: green" id="radical0031">
+ <mspace id="base0031" width="3em" height="1em" style="background: blue"/>
+ </msqrt>
+ <mroot style="background: green" id="radical0032">
+ <mspace id="base0032" width="3em" height="1em" style="background: blue"/>
+ <mspace width="3em" height="1em" style="background: black"/>
+ </mroot>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: kernafterdegreeminus5000-rulethickness1000;">
+ <mroot>
+ <mspace id="base004" width="3em" height="2em" style="background: blue"/>
+ <mspace id="index004" width="7em" height="1em" style="background: green"/>
+ </mroot>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: kernbeforedegree4000-rulethickness1000;">
+ <mroot id="radical005" style="background: blue">
+ <mspace width="3em" height="1em"/>
+ <mspace id="index005" width="3em" height="1em" style="background: green"/>
+ </mroot>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: rulethickness8000;">
+ <msqrt style="background: green" id="radical0061">
+ <mspace id="base0061" width="3em" height="1em" style="background: blue"/>
+ </msqrt>
+ <mroot style="background: green" id="radical0062">
+ <mspace id="base0062" width="3em" height="1em" style="background: blue"/>
+ <mspace width="3em" height="1em" style="background: black"/>
+ </mroot>
+ </math>
+ </p>
+ <p>
+ <math style="font-family: verticalgap6000-rulethickness1000;">
+ <msqrt style="background: green" id="radical0071">
+ <mspace id="base0071" width="3em" height="1em" style="background: blue"/>
+ </msqrt>
+ <mroot style="background: green" id="radical0072">
+ <mspace id="base0072" width="3em" height="1em" style="background: blue"/>
+ <mspace width="3em" height="1em" style="background: black"/>
+ </mroot>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/radicals/root-parameters-2.html b/testing/web-platform/tests/mathml/presentation-markup/radicals/root-parameters-2.html
new file mode 100644
index 0000000000..01d636b522
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/radicals/root-parameters-2.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Radical parameters</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#radicals-msqrt-mroot">
+<meta name="assert" content="Test edge kerning values for radicals.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ @font-face {
+ font-family: radical-negativekernbeforedegree1000-rulethickness1000;
+ src: url("/fonts/math/radical-negativekernbeforedegree1000-rulethickness1000.woff");
+ }
+ @font-face {
+ font-family: radical-kernafterdegreeminus5000-rulethickness1000;
+ src: url("/fonts/math/radical-kernafterdegreeminus5000-rulethickness1000.woff");
+ }
+ math, mspace {
+ font-size: 10px;
+ }
+ mspace {
+ opacity: .5;
+ }
+</style>
+<script>
+ var emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+ var epsilon = 1;
+
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_approx_equals(getBox("index001").left - getBox("mroot001").left,
+ 0, epsilon, "should be clamped to 0");
+ }, "RadicalKernBeforeDegree = -1em < 0");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var radicalSymbolWidth = 1000 * emToPx;
+ var radicalLeft = getBox("base002").left - radicalSymbolWidth;
+ assert_approx_equals(getBox("index002").right - radicalLeft,
+ 30, epsilon, "should be clamped to 3em");
+ }, "RadicalKernBeforeAfterDegree = -5em < -3em = -degree's inline size");
+
+ done();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math style="font-family: radical-negativekernbeforedegree1000-rulethickness1000">
+ <mroot id="mroot001">
+ <mspace id="base001" height="6em" width="6em" style="background: blue"/>
+ <mspace id="index001" height="6em" width="6em" style="background: green"/>
+ </mroot>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: radical-kernafterdegreeminus5000-rulethickness1000">
+ <mroot id="mroot002">
+ <mspace id="base002" height="3em" width="3em" style="background: blue"/>
+ <mspace id="index002" height="3em" width="3em" style="background: green"/>
+ </mroot>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/cramped-001.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/cramped-001.html
new file mode 100644
index 0000000000..e03b4d968d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/cramped-001.html
@@ -0,0 +1,627 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Cramped elements</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<link rel="help" href="https://w3c.github.io/mathml-core/#radicals-msqrt-mroot">
+<link rel="help" href="https://w3c.github.io/mathml-core/#displaystyle-and-scriptlevel-in-scripts">
+<link rel="help" href="https://w3c.github.io/mathml-core/#user-agent-stylesheet">
+<meta name="assert" content="Verify default calculation of math-shift on MathML elements">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script src="/mathml/support/box-navigation.js"></script>
+<style>
+ math {
+ font-family: superscriptshiftupcramped5000;
+ }
+ math, math * {
+ font-size: 10px;
+ background: lightyellow;
+ }
+ @font-face {
+ font-family: superscriptshiftupcramped5000;
+ src: url("/fonts/math/scripts-superscriptshiftupcramped5000.woff");
+ }
+ .testedElement *:first-child {
+ background: lightblue;
+ }
+ .testedElement *:last-child {
+ background: pink;
+ }
+</style>
+<script>
+ function assert_cramped(id, expected, name) {
+ const emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+ const superscriptshiftupcramped = 5000 * emToPx;
+ var container = document.getElementById(id);
+ var msup = container.getElementsByClassName("testedElement")[0];
+ var base = firstInFlowChild(msup);
+ var script = nextInFlowSibling(base);
+ var shift = base.getBoundingClientRect().bottom - script.getBoundingClientRect().bottom;
+ if (expected)
+ assert_greater_than(shift, superscriptshiftupcramped / 2, `${name || id} should be cramped`);
+ else
+ assert_less_than(shift, superscriptshiftupcramped / 2, `${name || id} should not be cramped`);
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_cramped("math-001", false);
+ assert_cramped("mrow-001", false, "mrow");
+ }, "child of non-cramped element");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_cramped("mrow-002", true);
+ }, "child of cramped element");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_cramped("msqrt-001", true);
+ }, "child of msqrt");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_cramped("mroot-001", true);
+ }, "child of mroot");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_cramped("mfrac-001", false, "numerator");
+ assert_cramped("mfrac-002", true, "denominator");
+ }, "child of mfrac");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_cramped("msub-001", false, "base");
+ assert_cramped("msub-002", true, "subscript");
+ }, "child of msub");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_cramped("msup-001", false, "base");
+ assert_cramped("msup-002", false, "superscript");
+ }, "child of msup");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_cramped("msubsup-001", false, "base");
+ assert_cramped("msubsup-002", true, "subscript");
+ assert_cramped("msubsup-003", false, "superscript");
+ }, "child of msubsup");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_cramped("munder-001", false, "base");
+ assert_cramped("munder-002", false, "underscript");
+ }, "child of munder");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_cramped("mover-001", false, "base");
+ assert_cramped("mover-002", false, "overscript");
+ }, "child of mover (non-accent overscript)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_cramped("munderover-001", false, "base");
+ assert_cramped("munderover-002", false, "underscript");
+ assert_cramped("munderover-003", false, "overscript");
+ }, "child of munderover (non-accent overscript)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_cramped("mover-003", true, "base");
+ assert_cramped("mover-004", false, "overscript");
+ }, "accent child of mover (accent overscript)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_cramped("munderover-004", true, "base");
+ assert_cramped("munderover-005", false, "underscript");
+ assert_cramped("munderover-006", false, "overscript");
+ }, "accent child of munderover (accent overscript)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_cramped("mmultiscripts-001", false, "base");
+ assert_cramped("mmultiscripts-002", true, "post-subscript");
+ assert_cramped("mmultiscripts-003", false, "post-superscript");
+ assert_cramped("mmultiscripts-004", true, "pre-subscript");
+ assert_cramped("mmultiscripts-005", false, "post-superscript");
+ }, "mmultiscripts");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_cramped("css-001", false);
+ assert_cramped("css-002", true);
+ assert_cramped("css-003", true);
+ assert_cramped("css-004", false);
+ }, "element with specified CSS math-style");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math id="math-001">
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ </math>
+ <math>
+ <mrow id="mrow-001">
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msqrt>
+ <!-- This is a child of a msqrt so it is cramped. As a consequence,
+ all its descendants are cramped too. -->
+ <munderover>
+ <mover>
+ <munder>
+ <msubsup>
+ <msup>
+ <msub>
+ <mfrac>
+ <mrow id="mrow-002">
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ </mrow>
+ <mspace/>
+ </mfrac>
+ <mspace/>
+ </msub>
+ <mspace/>
+ </msup>
+ <mspace/>
+ <mspace/>
+ </msubsup>
+ <mspace/>
+ </munder>
+ <mspace/>
+ </mover>
+ <mspace/>
+ <mspace/>
+ </munderover>
+ </msqrt>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msqrt id="msqrt-001">
+ <mn>0</mn>
+ <mn>1</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>3</mn>
+ <mn>4</mn>
+ </msqrt>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mroot id="mroot-001">
+ <mn>0</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ </mroot>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mroot id="mroot-002">
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>1</mn>
+ </mroot>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mfrac id="mfrac-001">
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>1</mn>
+ </mfrac>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mfrac id="mfrac-002">
+ <mn>0</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ </mfrac>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msub id="msub-001">
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>1</mn>
+ </msub>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msub id="msub-002">
+ <mn>0</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ </msub>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msup id="msup-001">
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>1</mn>
+ </msup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msup id="msup-002">
+ <mn>0</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ </msup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msubsup id="msubsup-001">
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>1</mn>
+ <mn>2</mn>
+ </msubsup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msubsup id="msubsup-002">
+ <mn>0</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>2</mn>
+ </msubsup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msubsup id="msubsup-003">
+ <mn>0</mn>
+ <mn>1</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ </msubsup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munder id="munder-001">
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>1</mn>
+ </munder>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munder id="munder-002">
+ <mn>0</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ </munder>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mover id="mover-001">
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>1</mn>
+ </mover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mover id="mover-002">
+ <mn>0</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ </mover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mover accent="true" id="mover-003">
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>1</mn>
+ </mover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mover accent="true" id="mover-004">
+ <mn>0</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ </mover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover id="munderover-001">
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>1</mn>
+ <mn>2</mn>
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover id="munderover-002">
+ <mn>0</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>2</mn>
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover id="munderover-003">
+ <mn>0</mn>
+ <mn>1</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover accent="true" id="munderover-004">
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>1</mn>
+ <mn>2</mn>
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover accent="true" id="munderover-005">
+ <mn>0</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>2</mn>
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover accent="true" id="munderover-006">
+ <mn>0</mn>
+ <mn>1</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts id="mmultiscripts-001">
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>1</mn>
+ <mn>2</mn>
+ <mn>3</mn>
+ <mn>4</mn>
+ <mn>5</mn>
+ <mn>6</mn>
+ <mprescripts/>
+ <mn>7</mn>
+ <mn>8</mn>
+ <mn>9</mn>
+ <mn>10</mn>
+ <mn>11</mn>
+ <mn>12</mn>
+ </mmultiscripts>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts id="mmultiscripts-002">
+ <mn>0</mn>
+ <mn>1</mn>
+ <mn>2</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>4</mn>
+ <mn>5</mn>
+ <mn>6</mn>
+ <mprescripts/>
+ <mn>7</mn>
+ <mn>8</mn>
+ <mn>9</mn>
+ <mn>10</mn>
+ <mn>11</mn>
+ <mn>12</mn>
+ </mmultiscripts>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts id="mmultiscripts-003">
+ <mn>0</mn>
+ <mn>1</mn>
+ <mn>2</mn>
+ <mn>3</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>5</mn>
+ <mn>6</mn>
+ <mprescripts/>
+ <mn>7</mn>
+ <mn>8</mn>
+ <mn>9</mn>
+ <mn>10</mn>
+ <mn>11</mn>
+ <mn>12</mn>
+ </mmultiscripts>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts id="mmultiscripts-004">
+ <mn>0</mn>
+ <mn>1</mn>
+ <mn>2</mn>
+ <mn>3</mn>
+ <mn>4</mn>
+ <mn>5</mn>
+ <mn>6</mn>
+ <mprescripts/>
+ <mn>7</mn>
+ <mn>8</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>10</mn>
+ <mn>11</mn>
+ <mn>12</mn>
+ </mmultiscripts>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts id="mmultiscripts-005">
+ <mn>0</mn>
+ <mn>1</mn>
+ <mn>2</mn>
+ <mn>3</mn>
+ <mn>4</mn>
+ <mn>5</mn>
+ <mn>6</mn>
+ <mprescripts/>
+ <mn>7</mn>
+ <mn>8</mn>
+ <mn>9</mn>
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ <mn>11</mn>
+ <mn>12</mn>
+ </mmultiscripts>
+ </math>
+ </p>
+ <p>
+ <math id="css-001" style="math-shift: normal">
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ </math>
+ <math id="css-002" style="math-shift: compact">
+ <msup class="testedElement">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ </math>
+ <math id="css-003" style="math-shift: normal">
+ <msup class="testedElement" style="math-shift: compact">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ </math>
+ <math id="css-004" style="math-shift: compact">
+ <msup class="testedElement" style="math-shift: normal">
+ <mspace height="2em" width="2em"/>
+ <mspace height="1em" width="1em"/>
+ </msup>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/empty-underover.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/empty-underover.html
new file mode 100644
index 0000000000..b5fcc9c4ca
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/empty-underover.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Test Script and Limit Schemata</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#script-and-limit-schemata">
+<meta name="assert" content="Script and Limit Schemata should not render anything when empty.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script>
+ var epsilon = 1;
+
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ ["over", "under", "underover", "sub", "sup", "subsup", "multiscripts"].forEach(function(name) {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_approx_equals(getBox(name).width, 0, epsilon, "width of empty " + name);
+ assert_approx_equals(getBox(name).height, 0, epsilon, "height of empty " + name);
+ });
+ }, "Size of empty script elements");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <munderover id="underover">
+ </munderover>
+ </math>
+ <math>
+ <munder id="under">
+ </munder>
+ </math>
+ <math>
+ <mover id="over">
+ </mover>
+ </math>
+ <math>
+ <msub id="sub">
+ </msub>
+ </math>
+ <math>
+ <msup id="sup">
+ </msup>
+ </math>
+ <math>
+ <msubsup id="subsup">
+ </msubsup>
+ </math>
+ <math>
+ <mmultiscripts id="multiscripts">
+ </mmultiscripts>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/mover-accent-dynamic-change-ref.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/mover-accent-dynamic-change-ref.html
new file mode 100644
index 0000000000..a4f16aa07f
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/mover-accent-dynamic-change-ref.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>MathML Reference</title>
+<p>The 1's below should have the same size</p>
+<math>
+ <mover accent="true">
+ <mn>1</mn>
+ <mn>1</mn>
+ </mover>
+</math>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/mover-accent-dynamic-change.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/mover-accent-dynamic-change.html
new file mode 100644
index 0000000000..a744149e60
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/mover-accent-dynamic-change.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>MathML: Dynamically change accent on mover</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#displaystyle-and-scriptlevel-in-scripts">
+<link rel="match" href="mover-accent-dynamic-change-ref.html">
+<meta name="assert" content="Test that setting the accent attribute on mover takes effect">
+<p>The 1's below should have the same size</p>
+<math>
+ <mover id="m">
+ <mn>1</mn>
+ <mn>1</mn>
+ </mover>
+</math>
+<script>
+ document.body.offsetTop;
+ m.setAttribute("accent", "true");
+</script>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/mprescripts-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/mprescripts-001-ref.html
new file mode 100644
index 0000000000..f8631539c0
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/mprescripts-001-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>mprescripts should render as an mrow (reference)</title>
+ </head>
+ <body>
+ <math>
+ <mrow>
+ <mspace width="10px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="30px" height="10px" depth="5px" style="background: blue;"></mspace>
+ <mspace width="20px" height="15px" depth="30px" style="background: lightblue;"></mspace>
+ <mspace width="25px" depth="20px" style="background: cyan;"></mspace>
+ <mspace width="40px" height="5px" depth="15px" style="background: blue;"></mspace>
+ <mspace width="20px" height="35px" depth="5px" style="background: lightblue;"></mspace>
+ </mrow>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/mprescripts-001.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/mprescripts-001.html
new file mode 100644
index 0000000000..2435b6291d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/mprescripts-001.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>mprescripts should render as an mrow</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+ <meta name="assert" content="Verify that mprescripts uses mrow layout">
+ <link rel="match" href="mprescripts-001-ref.html">
+ </head>
+ <body>
+ <math>
+ <mprescripts>
+ <mspace width="10px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="30px" height="10px" depth="5px" style="background: blue;"></mspace>
+ <mspace width="20px" height="15px" depth="30px" style="background: lightblue;"></mspace>
+ <mspace width="25px" depth="20px" style="background: cyan;"></mspace>
+ <mspace width="40px" height="5px" depth="15px" style="background: blue;"></mspace>
+ <mspace width="20px" height="35px" depth="5px" style="background: lightblue;"></mspace>
+ </mprescripts>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>
+ MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/none-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/none-001-ref.html
new file mode 100644
index 0000000000..55add01415
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/none-001-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>none should render as an mrow (reference)</title>
+ </head>
+ <body>
+ <math>
+ <mrow>
+ <mspace width="10px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="30px" height="10px" depth="5px" style="background: blue;"></mspace>
+ <mspace width="20px" height="15px" depth="30px" style="background: lightblue;"></mspace>
+ <mspace width="25px" depth="20px" style="background: cyan;"></mspace>
+ <mspace width="40px" height="5px" depth="15px" style="background: blue;"></mspace>
+ <mspace width="20px" height="35px" depth="5px" style="background: lightblue;"></mspace>
+ </mrow>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/none-001.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/none-001.html
new file mode 100644
index 0000000000..f1bfb442f7
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/none-001.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>none should render as an mrow</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+ <meta name="assert" content="Verify that none uses mrow layout">
+ <link rel="match" href="none-001-ref.html">
+ </head>
+ <body>
+ <math>
+ <none>
+ <mspace width="10px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="30px" height="10px" depth="5px" style="background: blue;"></mspace>
+ <mspace width="20px" height="15px" depth="30px" style="background: lightblue;"></mspace>
+ <mspace width="25px" depth="20px" style="background: cyan;"></mspace>
+ <mspace width="40px" height="5px" depth="15px" style="background: blue;"></mspace>
+ <mspace width="20px" height="35px" depth="5px" style="background: lightblue;"></mspace>
+ </none>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>
+ MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/none-002-ref.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/none-002-ref.html
new file mode 100644
index 0000000000..dac4dab553
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/none-002-ref.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>none used at other places than mmultiscripts' script (reference)</title>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math { font: 25px/1 Ahem; }
+ </style>
+ </head>
+ <body>
+ <p>
+ <math>
+ <msub>
+ <mrow></mrow>
+ <mn>2</mn>
+ </msub>
+ </math>
+ <math>
+ <msub>
+ <mn>1</mn>
+ <mrow></mrow>
+ </msub>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msup>
+ <mrow></mrow>
+ <mn>2</mn>
+ </msup>
+ </math>
+ <math>
+ <msup>
+ <mn>1</mn>
+ <mrow></mrow>
+ </msup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msubsup>
+ <mrow></mrow>
+ <mn>2</mn>
+ <mn>3</mn>
+ </msubsup>
+ </math>
+ <math>
+ <msubsup>
+ <mn>1</mn>
+ <mrow></mrow>
+ <mn>3</mn>
+ </msubsup>
+ </math>
+ <math>
+ <msubsup>
+ <mn>1</mn>
+ <mn>2</mn>
+ <mrow></mrow>
+ </msubsup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts>
+ <mrow></mrow>
+ <mn>2</mn>
+ <mn>3</mn>
+ </mmultiscripts>
+ </math>
+ </p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/none-002.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/none-002.html
new file mode 100644
index 0000000000..d1f3a3a0e1
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/none-002.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>none used at other places than mmultiscripts' script</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+ <meta name="assert" content="none can be used at other places than mmultiscripts' script, without triggering 'invalid markup'">
+ <link rel="match" href="none-002-ref.html">
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math { font: 25px/1 Ahem; }
+ </style>
+ </head>
+ <body>
+ <p>
+ <math>
+ <msub>
+ <none/>
+ <mn>2</mn>
+ </msub>
+ </math>
+ <math>
+ <msub>
+ <mn>1</mn>
+ <none/>
+ </msub>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msup>
+ <none/>
+ <mn>2</mn>
+ </msup>
+ </math>
+ <math>
+ <msup>
+ <mn>1</mn>
+ <none/>
+ </msup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msubsup>
+ <none/>
+ <mn>2</mn>
+ <mn>3</mn>
+ </msubsup>
+ </math>
+ <math>
+ <msubsup>
+ <mn>1</mn>
+ <none/>
+ <mn>3</mn>
+ </msubsup>
+ </math>
+ <math>
+ <msubsup>
+ <mn>1</mn>
+ <mn>2</mn>
+ <none/>
+ </msubsup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts>
+ <none/>
+ <mn>2</mn>
+ <mn>3</mn>
+ </mmultiscripts>
+ </math>
+ </p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-1.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-1.html
new file mode 100644
index 0000000000..1117e1008e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-1.html
@@ -0,0 +1,114 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Subscripts and Superscripts metrics</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+<meta name="assert" content="Basic metrics for elements msub, msup and msubsup.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ math, mspace {
+ font: 25px/1 Ahem;
+ }
+</style>
+<script>
+ /* This test does not use a font with a MATH table and does not verify layout
+ rules in a very strict way. */
+
+ function getBox(aId) {
+ var box = document.getElementById(aId).getBoundingClientRect();
+ box.middle = (box.bottom + box.top) / 2;
+ return box;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 1;
+ assert_less_than_equal(getBox("msubBase").right, getBox("msubSub").left, e, "msub: subscript is after base");
+ assert_less_than_equal(getBox("msupBase").right, getBox("msupSup").left, e, "msup: superscript is after base");
+ assert_less_than_equal(getBox("msubsupBase").right, getBox("msubsupSub").left, e, "msubsup: subscript is after base");
+ assert_less_than_equal(getBox("msubsupBase").right, getBox("msubsupSup").left, e, "msubsup: superscript is after base");
+
+ e = 3;
+ assert_approx_equals(getBox("msubBase").right, getBox("msubSub").left, e, "msub: space between base and subscript is small");
+ assert_approx_equals(getBox("msubBase").right, getBox("msubSub").left, e, "msub: subscript is after base");
+ assert_approx_equals(getBox("msupBase").right, getBox("msupSup").left, e, "msup: superscript is after base");
+ assert_approx_equals(getBox("msubsupBase").right, getBox("msubsupSub").left, e, "msubsup: subscript is after base");
+ assert_approx_equals(getBox("msubsupBase").right, getBox("msubsupSup").left, e, "msubsup: superscript is after base");
+ }, "Respective horizontal positions");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 1;
+ assert_approx_equals(getBox("msubBase").middle, getBox("baseline").bottom, e, "msub: base is placed on the baseline");
+ assert_approx_equals(getBox("msupBase").middle, getBox("baseline").bottom, e, "msup: base is placed on the baseline");
+ assert_approx_equals(getBox("msubsupBase").middle, getBox("baseline").bottom, e, "msubsup: base is placed on the baseline");
+ }, "Alignment of the base on the baseline");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ assert_greater_than(getBox("msubSub").middle, getBox("msubBase").middle, "msub: script is placed at the bottom of the base");
+ assert_less_than(getBox("msupSup").middle, getBox("msupBase").middle, "msup: script is placed at the top of the base");
+ assert_greater_than(getBox("msubsupSub").middle, getBox("msubsupBase").middle, "msubsup: script is placed at the bottom of the base");
+ assert_less_than(getBox("msubsupSup").middle, getBox("msubsupBase").middle, "msubsup: script is placed at the top of the base");
+ }, "Vertical position of scripts");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 5;
+ assert_approx_equals(getBox("msub").width, getBox("msubSub").right - getBox("msubBase").left, e, "msub: width is determined by the left/right sides of base/script (+ some space after script)");
+ assert_approx_equals(getBox("msup").width, getBox("msupSup").right - getBox("msupBase").left, e, "msup: width is determined by the left/right sides of base/script (+ some space after script)");
+ assert_approx_equals(getBox("msubsup").width, Math.max(getBox("msubsupSub").right, getBox("msubsupSup").right) - getBox("msubsupBase").left, e, "msubsup: width is determined by the left/right sides of base/scripts (+ some space after script)");
+ }, "Width of scripted elements");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 1;
+ assert_greater_than_equal(getBox("msub").height, getBox("msubBase").height, e, "msub: height is at least the one of the base");
+ assert_greater_than_equal(getBox("msup").height, getBox("msupBase").height, e, "msup: height is at least the one of the base");
+ assert_greater_than_equal(getBox("msubsup").height, getBox("msubsupBase").height, e, "msubsup: height is at least the one of the base");
+
+ assert_approx_equals(getBox("msub").height, Math.max(getBox("msubSub").bottom, getBox("msubBase").bottom) - getBox("msubBase").top, e, "msub: height is determined by the top/bottom sides of base/scripts");
+ assert_approx_equals(getBox("msup").height, getBox("msupBase").bottom - Math.min(getBox("msupSup").top, getBox("msupBase").top), e, "msup: height is determined by the top/bottom sides of base/scripts");
+ assert_approx_equals(getBox("msubsup").height, Math.max(getBox("msubSub").bottom, getBox("msubBase").bottom) - Math.min(getBox("msupSup").top, getBox("msupBase").top), e, "msubsup: height is determined by the top/bottom sides of base/scripts");
+ }, "Height of scripted elements");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mspace id="baseline" width="30px" height="2px" depth="0px" style="background: blue"/>
+ <msub id="msub" style="background: green">
+ <mspace id="msubBase" width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace id="msubSub" width="10px" height="5px" depth="5px" style="background: black"/>
+ </msub>
+ <msup id="msup" style="background: blue">
+ <mspace id="msupBase" width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace id="msupSup" width="10px" height="5px" depth="5px" style="background: black"/>
+ </msup>
+ <msubsup id="msubsup" style="background: green">
+ <mspace id="msubsupBase" width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace id="msubsupSub" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="msubsupSup" width="10px" height="5px" depth="5px" style="background: black"/>
+ </msubsup>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-2.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-2.html
new file mode 100644
index 0000000000..9c89dd3727
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-2.html
@@ -0,0 +1,173 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Subscripts and Superscripts metrics</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+<meta name="assert" content="Basic metrics for the mmultiscript element.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ math, mspace {
+ font: 25px/1 Ahem;
+ }
+</style>
+<script>
+ /* This test does not use a font with a MATH table and does not verify layout
+ rules in a very strict way. */
+
+ function getBox(aId) {
+ var box = document.getElementById(aId).getBoundingClientRect();
+ box.middle = (box.bottom + box.top) / 2;
+ return box;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 1;
+ assert_less_than_equal(getBox("msubBase").right, getBox("msubSub").left, e, "subscript is after base");
+ assert_less_than_equal(getBox("msupBase").right, getBox("msupSup").left, e, "superscript is after base");
+ assert_less_than_equal(getBox("msubsupBase").right, getBox("msubsupSub").left, e, "subscript is after base");
+ assert_less_than_equal(getBox("msubsupBase").right, getBox("msubsupSup").left, e, "superscript is after base");
+
+ assert_greater_than_equal(getBox("premsubBase").right, getBox("premsubSub").left, e, "subscript is before base");
+ assert_greater_than_equal(getBox("premsupBase").right, getBox("premsupSup").left, e, "superscript is before base");
+ assert_greater_than_equal(getBox("premsubsupBase").right, getBox("premsubsupSub").left, e, "subscript is before base");
+ assert_greater_than_equal(getBox("premsubsupBase").right, getBox("premsubsupSup").left, e, "superscript is before base");
+
+ e = 3;
+ assert_approx_equals(getBox("msubBase").right, getBox("msubSub").left, e, "msub: space between base and subscript is small");
+ assert_approx_equals(getBox("msubBase").right, getBox("msubSub").left, e, "msub: subscript is after base");
+ assert_approx_equals(getBox("msupBase").right, getBox("msupSup").left, e, "msup: superscript is after base");
+ assert_approx_equals(getBox("msubsupBase").right, getBox("msubsupSub").left, e, "msubsup: subscript is after base");
+ assert_approx_equals(getBox("msubsupBase").right, getBox("msubsupSup").left, e, "msubsup: superscript is after base");
+
+ assert_approx_equals(getBox("premsubBase").left, getBox("premsubSub").right, e, "msub: space between base and subscript is small");
+ assert_approx_equals(getBox("premsubBase").left, getBox("premsubSub").right, e, "msub: subscript is after base");
+ assert_approx_equals(getBox("premsupBase").left, getBox("premsupSup").right, e, "msup: superscript is after base");
+ assert_approx_equals(getBox("premsubsupBase").left, getBox("premsubsupSub").right, e, "msubsup: subscript is after base");
+ assert_approx_equals(getBox("premsubsupBase").left, getBox("premsubsupSup").right, e, "msubsup: superscript is after base");
+ }, "Respective horizontal positions");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 1;
+ assert_approx_equals(getBox("msubBase").middle, getBox("baseline").bottom, e, "base is placed on the baseline");
+ assert_approx_equals(getBox("msupBase").middle, getBox("baseline").bottom, e, "base is placed on the baseline");
+ assert_approx_equals(getBox("msubsupBase").middle, getBox("baseline").bottom, e, "base is placed on the baseline");
+ assert_approx_equals(getBox("premsubBase").middle, getBox("baseline").bottom, e, "base is placed on the baseline");
+ assert_approx_equals(getBox("premsupBase").middle, getBox("baseline").bottom, e, "base is placed on the baseline");
+ assert_approx_equals(getBox("premsubsupBase").middle, getBox("baseline").bottom, e, "base is placed on the baseline");
+ }, "Alignment of the base on the baseline");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ assert_greater_than(getBox("msubSub").middle, getBox("msubBase").middle, "script is placed at the bottom of the base");
+ assert_less_than(getBox("msupSup").middle, getBox("msupBase").middle, "script is placed at the top of the base");
+ assert_greater_than(getBox("msubsupSub").middle, getBox("msubsupBase").middle, "script is placed at the bottom of the base");
+ assert_less_than(getBox("msubsupSup").middle, getBox("msubsupBase").middle, "script is placed at the top of the base");
+
+ assert_greater_than(getBox("premsubSub").middle, getBox("premsubBase").middle, "script is placed at the bottom of the base");
+ assert_less_than(getBox("premsupSup").middle, getBox("premsupBase").middle, "script is placed at the top of the base");
+ assert_greater_than(getBox("premsubsupSub").middle, getBox("premsubsupBase").middle, "script is placed at the bottom of the base");
+ assert_less_than(getBox("premsubsupSup").middle, getBox("premsubsupBase").middle, "script is placed at the top of the base");
+ }, "Vertical position of scripts");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 3;
+ assert_approx_equals(getBox("msub").width, getBox("msubSub").right - getBox("msubBase").left, e, "width is determined by the left/right sides of base/script (+ some space after script)");
+ assert_approx_equals(getBox("msup").width, getBox("msupSup").right - getBox("msupBase").left, e, "width is determined by the left/right sides of base/script (+ some space after script)");
+ assert_approx_equals(getBox("msubsup").width, Math.max(getBox("msubsupSub").right, getBox("msubsupSup").right) - getBox("msubsupBase").left, e, "width is determined by the left/right sides of base/scripts (+ some space after script)");
+
+ assert_approx_equals(getBox("premsub").width, getBox("premsubBase").right - getBox("premsubSub").left, e, "width is determined by the right/left sides of base/script (+ some space after script)");
+ assert_approx_equals(getBox("premsup").width, getBox("premsupBase").right - getBox("premsupSup").left, e, "width is determined by the right/left sides of base/script (+ some space after script)");
+ assert_approx_equals(getBox("premsubsup").width, getBox("premsubsupBase").right - Math.min(getBox("premsubsupSub").left, getBox("premsubsupSup").left), e, "width is determined by the right/left sides of base/scripts (+ some space after script)");
+ }, "Width of scripted elements");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 5;
+ assert_greater_than_equal(getBox("msub").height, getBox("msubBase").height, e, "height is at least the one of the base");
+ assert_greater_than_equal(getBox("msup").height, getBox("msupBase").height, e, "height is at least the one of the base");
+ assert_greater_than_equal(getBox("msubsup").height, getBox("msubsupBase").height, e, "height is at least the one of the base");
+ assert_greater_than_equal(getBox("premsub").height, getBox("premsubBase").height, e, "height is at least the one of the base");
+ assert_greater_than_equal(getBox("premsup").height, getBox("premsupBase").height, e, "height is at least the one of the base");
+ assert_greater_than_equal(getBox("premsubsup").height, getBox("premsubsupBase").height, e, "height is at least the one of the base");
+
+ assert_approx_equals(getBox("msub").height, Math.max(getBox("msubSub").bottom, getBox("msubBase").bottom) - getBox("msubBase").top, e, "msub height is determined by the top/bottom sides of base/scripts");
+ assert_approx_equals(getBox("msup").height, getBox("msupBase").bottom - Math.min(getBox("msupSup").top, getBox("msupBase").top), e, "msup height is determined by the top/bottom sides of base/scripts");
+ assert_approx_equals(getBox("msubsup").height, Math.max(getBox("msubSub").bottom, getBox("msubBase").bottom) - Math.min(getBox("msupSup").top, getBox("msupBase").top), e, "msubsup height is determined by the top/bottom sides of base/scripts");
+ assert_approx_equals(getBox("premsub").height, Math.max(getBox("premsubSub").bottom, getBox("premsubBase").bottom) - getBox("premsubBase").top, e, "msub height is determined by the top/bottom sides of base/scripts");
+ assert_approx_equals(getBox("premsup").height, getBox("premsupBase").bottom - Math.min(getBox("premsupSup").top, getBox("premsupBase").top), e, "msup height is determined by the top/bottom sides of base/scripts");
+ assert_approx_equals(getBox("premsubsup").height, Math.max(getBox("premsubSub").bottom, getBox("premsubBase").bottom) - Math.min(getBox("premsupSup").top, getBox("premsupBase").top), e, "msubsup height is determined by the top/bottom sides of base/scripts");
+ }, "Height of scripted elements");
+
+ test(function() {
+ ["none", "mprescripts"].forEach(function(name) {
+ var elements = document.getElementsByTagName(name);
+ for (var i = 0; i < elements.length; i++) {
+ var box = elements[i].getBoundingClientRect();
+ assert_equals(box.height * box.width, 0, "<" + name + "> " + i + " has zero is empty");
+ }
+ });
+ }, "Size of empty elements");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mspace id="baseline" width="30px" height="2px" depth="0px" style="background: blue"/>
+ <mmultiscripts id="msub" style="background: green">
+ <mspace id="msubBase" width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace id="msubSub" width="10px" height="5px" depth="5px" style="background: black"/>
+ <none/>
+ </mmultiscripts>
+ <mmultiscripts id="msup" style="background: green">
+ <mspace id="msupBase" width="30px" height="15px" depth="15px" style="background: black"/>
+ <none/>
+ <mspace id="msupSup" width="10px" height="5px" depth="5px" style="background: black"/>
+ </mmultiscripts>
+ <mmultiscripts id="msubsup" style="background: green">
+ <mspace id="msubsupBase" width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace id="msubsupSub" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="msubsupSup" width="10px" height="5px" depth="5px" style="background: black"/>
+ </mmultiscripts>
+ <mmultiscripts id="premsub" style="background: green">
+ <mspace id="premsubBase" width="30px" height="15px" depth="15px" style="background: black"/>
+ <mprescripts/>
+ <mspace id="premsubSub" width="10px" height="5px" depth="5px" style="background: black"/>
+ <none/>
+ </mmultiscripts>
+ <mmultiscripts id="premsup" style="background: green">
+ <mspace id="premsupBase" width="30px" height="15px" depth="15px" style="background: black"/>
+ <mprescripts/>
+ <none/>
+ <mspace id="premsupSup" width="10px" height="5px" depth="5px" style="background: black"/>
+ </mmultiscripts>
+ <mmultiscripts id="premsubsup" style="background: green">
+ <mspace id="premsubsupBase" width="30px" height="15px" depth="15px" style="background: black"/>
+ <mprescripts/>
+ <mspace id="premsubsupSub" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="premsubsupSup" width="10px" height="5px" depth="5px" style="background: black"/>
+ </mmultiscripts>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-3.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-3.html
new file mode 100644
index 0000000000..28db9b70cc
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-3.html
@@ -0,0 +1,192 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Subscripts and Superscripts metrics</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+<meta name="assert" content="Basic metrics for the mmultiscript element with many scripts.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ math, mspace {
+ font: 25px/1 Ahem;
+ }
+</style>
+<script>
+ /* This test does not use a font with a MATH table and does not verify layout
+ rules in a very strict way. */
+
+ function getBox(aId) {
+ var box = document.getElementById(aId).getBoundingClientRect();
+ box.middle = (box.bottom + box.top) / 2;
+ return box;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 1;
+ for (var i = 0; i < 5; i++)
+ assert_approx_equals(getBox("multi" + i + "base").middle, getBox("baseline").bottom, e, "base " + i + "is placed on the baseline");
+ }, "Alignment of the base on the baseline");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 5;
+ assert_approx_equals(getBox("multi0").width, 30, e, "width of multi0");
+ assert_approx_equals(getBox("multi0").height, 30, e, "height of multi0");
+ assert_approx_equals(getBox("multi1").width, 30, e, "width of multi1");
+ assert_approx_equals(getBox("multi1").height, 30, e, "height of multi1");
+ for (i = 2; i <= 4; i++) {
+ var scriptedBox = getBox("multi" + i);
+ var lastPostScript = getBox("multi" + i + "postsup" + (i - 1));
+ var firstPreScript = getBox("multi" + i + "presub1");
+ assert_approx_equals(scriptedBox.height, firstPreScript.bottom - lastPostScript.top, e, "height of multiscript" + i);
+ assert_approx_equals(scriptedBox.width, lastPostScript.right - firstPreScript.left, e, "width of multiscript" + i);
+ }
+ }, "Dimensions of the scripted elements");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 3;
+ for (var i = 2; i <= 4; i++) {
+ var base = getBox("multi" + i + "base");
+ for (var j = 1; j < i; j++) {
+ var presup = getBox("multi" + i + "presup" + j);
+ var postsup = getBox("multi" + i + "postsup" + j);
+ var presub = getBox("multi" + i + "presub" + j);
+ var postsub = getBox("multi" + i + "postsub" + j);
+ assert_approx_equals(base.top, presup.middle, e, "multi" + i + " " + j + " presup script");
+ assert_approx_equals(base.top, postsup.middle, e, "multi" + i + " " + j + " postsup script");
+ assert_approx_equals(base.bottom, presub.middle, e, "multi" + i + " " + j + " presub script");
+ assert_approx_equals(base.bottom, postsub.middle, e, "multi" + i + " " + j + " postsub script");
+ }
+ }
+ }, "Vertical positions of scripts");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 1;
+ for (var i = 2; i <= 4; i++) {
+ var base = getBox("multi" + i + "base");
+ for (var j = 1; j < i; j++) {
+ var presup = getBox("multi" + i + "presup" + j);
+ var postsup = getBox("multi" + i + "postsup" + j);
+ var presub = getBox("multi" + i + "presub" + j);
+ var postsub = getBox("multi" + i + "postsub" + j);
+ assert_approx_equals(presup.right, presub.right, e, "multi" + i + "pre");
+ assert_approx_equals(postsup.left, postsub.left, e, "multi" + i + "post");
+ }
+ }
+ }, "Horizontal alignment of scripts");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ for (var i = 2; i <= 4; i++) {
+ var base = getBox("multi" + i + "base");
+ var firstPostScript = getBox("multi" + i + "postsub1");
+ var lastPreScript = getBox("multi" + i + "presup" + (i - 1));
+ assert_less_than_equal(base.right, firstPostScript.left, 1, "postcripts are after base");
+ assert_less_than_equal(lastPreScript.right, base.left, 1, "prescripts are before base");
+ assert_approx_equals(base.right, firstPostScript.left, 5, "spacing after base is not too large");
+ assert_approx_equals(lastPreScript.right, base.left, 5, "spacing before base is not too large");
+ for (var j = 1; j < i - 1; j++) {
+ var post = getBox("multi" + i + "postsub" + j);
+ var postNext = getBox("multi" + i + "postsub" + (j + 1));
+ var pre = getBox("multi" + i + "presup" + j);
+ var preNext = getBox("multi" + i + "presup" + (j + 1));
+ assert_less_than_equal(post.right, postNext.left, 1, "multi" + i + "order post" + j + " is before its successor");
+ assert_less_than_equal(pre.right, preNext.left, 1, "multi" + i + "order pre" + j + " is before its successor");
+ assert_approx_equals(post.right, postNext.left, 5, "multi" + i + "space after post" + j + " is not too large");
+ assert_approx_equals(pre.right, preNext.left, 5, "multi" + i + "space after pre" + j + " is not too large");
+ }
+ }
+ }, "Horizontal positions of scripts");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mspace id="baseline" width="30px" height="2px" depth="0px" style="background: blue"/>
+ <mmultiscripts id="multi0" style="background: green">
+ <mspace id="multi0base" width="30px" height="15px" depth="15px" style="background: black"/>
+ </mmultiscripts>
+ <mmultiscripts id="multi1" style="background: green">
+ <mspace id="multi1base" width="30px" height="15px" depth="15px" style="background: black"/>
+ <mprescripts/>
+ </mmultiscripts>
+ <mmultiscripts id="multi2" style="background: green">
+ <mspace id="multi2base" width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace id="multi2postsub1" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi2postsup1" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mprescripts/>
+ <mspace id="multi2presub1" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi2presup1" width="10px" height="5px" depth="5px" style="background: black"/>
+ </mmultiscripts>
+ <mmultiscripts id="multi3" style="background: green">
+ <mspace id="multi3base" width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace id="multi3postsub1" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi3postsup1" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi3postsub2" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi3postsup2" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mprescripts/>
+ <mspace id="multi3presub1" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi3presup1" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi3presub2" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi3presup2" width="10px" height="5px" depth="5px" style="background: black"/>
+ </mmultiscripts>
+ <mmultiscripts id="multi4" style="background: green">
+ <mspace id="multi4base" width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace id="multi4postsub1" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi4postsup1" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi4postsub2" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi4postsup2" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi4postsub3" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi4postsup3" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mprescripts/>
+ <mspace id="multi4presub1" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi4presup1" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi4presub2" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi4presup2" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi4presub3" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi4presup3" width="10px" height="5px" depth="5px" style="background: black"/>
+ </mmultiscripts>
+ <mmultiscripts id="multi5" style="background: green">
+ <mspace id="multi5base" width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace id="multi5postsub1" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi5postsup1" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi5postsub2" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi5postsup2" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi5postsub3" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi5postsup3" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi5postsub4" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi5postsup4" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mprescripts/>
+ <mspace id="multi5presub1" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi5presup1" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi5presub2" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi5presup2" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi5presub3" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi5presup3" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi5presub4" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi5presup4" width="10px" height="5px" depth="5px" style="background: black"/>
+ </mmultiscripts>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-4.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-4.html
new file mode 100644
index 0000000000..cdf6cbe20e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-4.html
@@ -0,0 +1,129 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Subscripts and Superscripts metrics</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+<meta name="assert" content="Verify metrics of scripted elements for bases of different heights.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<style>
+ math, mspace {
+ font-size: 10px;
+ }
+</style>
+<script>
+ /* This test does not use any specific fonts and so the exact rules are not
+ specified precisely. We assume reasonable values for script shifts and
+ spacing. */
+
+ function getBox(aId) {
+ var box = document.getElementById(aId).getBoundingClientRect();
+ box.middle = (box.bottom + box.top) / 2;
+ return box;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ var sizeArray = [50, 75, 100];
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 1;
+ sizeArray.forEach(function(size) {
+ assert_approx_equals(getBox("msub" + size + "base").middle, getBox("baseline").bottom, e, "msub base " + size + "is placed on the baseline");
+ assert_approx_equals(getBox("msup" + size + "base").middle, getBox("baseline").bottom, e, "msup base " + size + "is placed on the baseline");
+ assert_approx_equals(getBox("msubsup" + size + "base").middle, getBox("baseline").bottom, e, "msubsup base " + size + "is placed on the baseline");
+ assert_approx_equals(getBox("multi" + size + "base").middle, getBox("baseline").bottom, e, "mmultiscripts base " + size + "is placed on the baseline");
+ });
+ }, "Alignment on the baseline for bases of different heights");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 5;
+ sizeArray.forEach(function(size) {
+ assert_approx_equals(getBox("msub" + size + "sub").middle, getBox("msub" + size + "base").bottom, e, "msub script " + size + "is placed at the top of of the base");
+ });
+ }, "Vertical position of the scripts for bases of different heights");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mspace id="baseline" width="30px" height="2px" depth="0px" style="background: blue"/>
+ <msub id="msub50">
+ <mspace id="msub50base" width="30px" height="50px" depth="50px" style="background: black"/>
+ <mspace id="msub50sub" width="10px" height="5px" depth="5px" style="background: black"/>
+ </msub>
+ <msup id="msup50">
+ <mspace id="msup50base" width="30px" height="50px" depth="50px" style="background: black"/>
+ <mspace id="msup50sup" width="10px" height="5px" depth="5px" style="background: black"/>
+ </msup>
+ <msubsup id="msubsup50">
+ <mspace id="msubsup50base" width="30px" height="50px" depth="50px" style="background: black"/>
+ <mspace id="msubsup50sub" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="msubsup50sup" width="10px" height="5px" depth="5px" style="background: black"/>
+ </msubsup>
+ <mmultiscripts id="multi50">
+ <mspace id="multi50base" width="30px" height="50px" depth="50px" style="background: black"/>
+ <mspace id="multi50postsub" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi50postsup" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mprescripts/>
+ <mspace id="multi50presub" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi50presup" width="10px" height="5px" depth="5px" style="background: black"/>
+ </mmultiscripts>
+ <msub id="msub75">
+ <mspace id="msub75base" width="30px" height="75px" depth="75px" style="background: black"/>
+ <mspace id="msub75sub" width="10px" height="5px" depth="5px" style="background: black"/>
+ </msub>
+ <msup id="msup75">
+ <mspace id="msup75base" width="30px" height="75px" depth="75px" style="background: black"/>
+ <mspace id="msup75sup" width="10px" height="5px" depth="5px" style="background: black"/>
+ </msup>
+ <msubsup id="msubsup75">
+ <mspace id="msubsup75base" width="30px" height="75px" depth="75px" style="background: black"/>
+ <mspace id="msubsup75sub" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="msubsup75sup" width="10px" height="5px" depth="5px" style="background: black"/>
+ </msubsup>
+ <mmultiscripts id="multi75">
+ <mspace id="multi75base" width="30px" height="75px" depth="75px" style="background: black"/>
+ <mspace id="multi75postsub" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi75postsup" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mprescripts/>
+ <mspace id="multi75presub" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi75presub" width="10px" height="5px" depth="5px" style="background: black"/>
+ </mmultiscripts>
+ <msub id="msub100">
+ <mspace id="msub100base" width="30px" height="100px" depth="100px" style="background: black"/>
+ <mspace id="msub100sub" width="10px" height="5px" depth="5px" style="background: black"/>
+ </msub>
+ <msup id="msup100">
+ <mspace id="msup100base" width="30px" height="100px" depth="100px" style="background: black"/>
+ <mspace id="msup100sup" width="10px" height="5px" depth="5px" style="background: black"/>
+ </msup>
+ <msubsup id="msubsup100">
+ <mspace id="msubsup100base" width="30px" height="100px" depth="100px" style="background: black"/>
+ <mspace id="msubsup100sub" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="msubsup100sup" width="10px" height="5px" depth="5px" style="background: black"/>
+ </msubsup>
+ <mmultiscripts id="multi100">
+ <mspace id="multi100base" width="30px" height="100px" depth="100px" style="background: black"/>
+ <mspace id="multi100postsub" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi100postsup" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mprescripts/>
+ <mspace id="multi100presub" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="multi100presup" width="10px" height="5px" depth="5px" style="background: black"/>
+ </mmultiscripts>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-5.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-5.html
new file mode 100644
index 0000000000..1743c2e499
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-5.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Subscripts and Superscripts metrics</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+<meta name="assert" content="Verify metrics of scripted elements with tall scripts.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<style>
+ math, mspace {
+ font-size: 10px;
+ }
+</style>
+<script>
+ /* This test does not use any specific fonts and so the exact rules are not
+ specified precisely. We assume reasonable values for script shifts and
+ spacing. */
+
+ function getBox(aId) {
+ var box = document.getElementById(aId).getBoundingClientRect();
+ box.middle = (box.bottom + box.top) / 2;
+ return box;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ var sizeArray = [50, 75, 100];
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 1;
+ assert_approx_equals(getBox("msubbase").middle, getBox("baseline").bottom, e, "msub base is placed on the baseline");
+ assert_approx_equals(getBox("msupbase").middle, getBox("baseline").bottom, e, "msup base is placed on the baseline");
+ assert_approx_equals(getBox("msubsupbase").middle, getBox("baseline").bottom, e, "msubsup base is placed on the baseline");
+ assert_approx_equals(getBox("multibase").middle, getBox("baseline").bottom, e, "mmultiscripts baseis placed on the baseline");
+ }, "Alignment on the baseline with different and large script heights");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ assert_greater_than(getBox("msubsub").top, getBox("msubbase").top, "msub: subscript is below the top of the base");
+ assert_less_than(getBox("msupsup").bottom, getBox("msupbase").bottom, "msup: supscript is above the bottom of the base");
+ assert_greater_than(getBox("msubsupsub").top, getBox("msubsupbase").top, "msubsup: subscript is below the top of the base");
+ assert_less_than(getBox("msubsupsup").bottom, getBox("msubsupbase").bottom, "msubsup: supscript is above the bottom of the base");
+ assert_greater_than(getBox("multipostsub").top, getBox("multibase").top, "mmultiscripts: postsubscript is below the top of the base");
+ assert_less_than(getBox("multipostsup").bottom, getBox("multibase").bottom, "mmultiscripts: postsupscript is above the bottom of the base");
+ assert_greater_than(getBox("multipresub").top, getBox("multibase").top, "mmultiscripts: presubscript is below the top of the base");
+ assert_less_than(getBox("multipresup").bottom, getBox("multibase").bottom, "mmultiscripts: presupscript is above the bottom of the base");
+ }, "Tall subscripts/superscripts are not placed too high/low");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ assert_greater_than(getBox("msubsupsub").top, getBox("msubsupsup").bottom, "msubsup: subscript is below the superscript");
+ assert_greater_than(getBox("multipresub").top, getBox("multipresup").bottom, "mmultiscripts: presubscript is below the presuperscript");
+ assert_greater_than(getBox("multipostsub").top, getBox("multipostsup").bottom, "mmultiscripts: postsubscript is below the postsuperscript");
+ }, "No collisions for tall subscripts and superscripts");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mspace id="baseline" width="30px" height="2px" depth="0px" style="background: blue"/>
+ <msub id="msub">
+ <mspace id="msubbase" width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace id="msubsub" width="10px" height="50px" depth="50px" style="background: black"/>
+ </msub>
+ <msup id="msup">
+ <mspace id="msupbase" width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace id="msupsup" width="10px" height="75px" depth="75px" style="background: black"/>
+ </msup>
+ <msubsup id="msubsup">
+ <mspace id="msubsupbase" width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace id="msubsupsub" width="10px" height="50px" depth="50px" style="background: black"/>
+ <mspace id="msubsupsup" width="10px" height="75px" depth="75px" style="background: black"/>
+ </msubsup>
+ <mmultiscripts id="multi">
+ <mspace id="multibase" width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace id="multipostsub" width="10px" height="50px" depth="50px" style="background: black"/>
+ <mspace id="multipostsup" width="10px" height="75px" depth="75px" style="background: black"/>
+ <mprescripts/>
+ <mspace id="multipresub" width="10px" height="50px" depth="50px" style="background: black"/>
+ <mspace id="multipresup" width="10px" height="75px" depth="75px" style="background: black"/>
+ </mmultiscripts>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-6.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-6.html
new file mode 100644
index 0000000000..9666c80f9f
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-6.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>mprescripts</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+<meta name="assert" content="Position and size of mprescripts in mmultiscript element.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ math, mspace {
+ font: 25px/1 Ahem;
+ }
+</style>
+<script>
+ /* This test does not use a font with a MATH table and does not verify layout
+ rules in a very strict way. */
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ Array.from(document.getElementsByTagName("mprescripts")).
+ forEach(prescript => {
+ let prescript_box = prescript.getBoundingClientRect();
+ let mmultiscripts = prescript.parentNode;
+ let name = mmultiscripts.getAttribute("data-name");
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var e = 1;
+ let base_box = mmultiscripts.firstElementChild.getBoundingClientRect();
+ assert_approx_equals(prescript_box.left, base_box.left, e, `${name}, left`);
+ assert_approx_equals((prescript_box.top + prescript_box.bottom) / 2, (base_box.top + base_box.bottom) / 2, e, `${name}, top`);
+
+ if (name == "prescripts with padding/border/margin") {
+ assert_approx_equals(prescript_box.width, 2*(15 + 25), e, `${name}, width`);
+ assert_approx_equals(prescript_box.height, 2*(10 + 20), e, `${name}, height`);
+ } else {
+ assert_approx_equals(prescript_box.width, 0, e, `${name}, width`);
+ assert_approx_equals(prescript_box.height, 0, e, `${name}, height`);
+ }
+ }, `mprescripts coordinates and sizes (${name})`);
+ });
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mmultiscripts data-name="2 postscripts">
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mprescripts/>
+ </mmultiscripts>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts data-name="2 prescripts">
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mprescripts/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ </mmultiscripts>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts data-name="2 prescripts, 4 postscripts">
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mprescripts/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ </mmultiscripts>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts data-name="4 prescripts, 2 postscripts">
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mprescripts/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ </mmultiscripts>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts data-name="prescripts with padding/border/margin">
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mprescripts style="background: blue;
+ padding-top: 10px; border-top: 20px solid green;
+ padding-bottom: 10px; border-bottom: 20px solid green;
+ padding-left: 15px; border-left: 25px solid green;
+ padding-right: 15px; border-right: 25px solid green;
+ margin-top: 50px;"/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ <mspace width="30px" height="15px" depth="15px" style="background: black"/>
+ </mmultiscripts>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-legacy-scriptshift-attributes-001.tentative-ref.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-legacy-scriptshift-attributes-001.tentative-ref.html
new file mode 100644
index 0000000000..c1bf2e4695
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-legacy-scriptshift-attributes-001.tentative-ref.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>msub/msup/msubsup/mmultiscripts subscriptshift and superscriptshift attributes (reference)</title>
+ </head>
+ <body>
+ <p>Test passes if the green squares are not about 300px away from the blue squares.</p>
+ <p>
+ <math>
+ <mmultiscripts>
+ <mspace width="30px" height="30px" style="background: blue;"></mspace>
+ <mspace width="10px" height="10px" style="background: lightgreen;"></mspace>
+ <mspace width="10px" height="10px" style="background: lightgreen;"></mspace>
+ <mprescripts/>
+ <mspace width="10px" height="10px" style="background: lightgreen;"></mspace>
+ <mspace width="10px" height="10px" style="background: lightgreen;"></mspace>
+ </mmultiscripts>
+ <msub>
+ <mspace width="30px" height="30px" style="background: blue;"></mspace>
+ <mspace width="10px" height="10px" style="background: lightgreen;"></mspace>
+ </msub>
+ <msup>
+ <mspace width="30px" height="30px" style="background: blue;"></mspace>
+ <mspace width="10px" height="10px" style="background: lightgreen;"></mspace>
+ </msup>
+ <msubsup>
+ <mspace width="30px" height="30px" style="background: blue;"></mspace>
+ <mspace width="10px" height="10px" style="background: lightgreen;"></mspace>
+ <mspace width="10px" height="10px" style="background: lightgreen;"></mspace>
+ </msubsup>
+ </math>
+ </p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-legacy-scriptshift-attributes-001.tentative.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-legacy-scriptshift-attributes-001.tentative.html
new file mode 100644
index 0000000000..2f29db401d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-legacy-scriptshift-attributes-001.tentative.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>msub/msup/msubsup/mmultiscripts subscriptshift and superscriptshift attributes</title>
+ <link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.msub">
+ <link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.msup">
+ <link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.msunsup">
+ <link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.mmultiscripts">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#prescripts-and-tensor-indices-mmultiscripts">
+ <link rel="match" href="subsup-legacy-scriptshift-attributes-001.tentative-ref.html">
+ </head>
+ <body>
+ <p>Test passes if the green squares are not about 300px away from the blue squares.</p>
+ <p>
+ <math>
+ <mmultiscripts subscriptshift="300px" superscriptshift="300px">
+ <mspace width="30px" height="30px" style="background: blue;"></mspace>
+ <mspace width="10px" height="10px" style="background: lightgreen;"></mspace>
+ <mspace width="10px" height="10px" style="background: lightgreen;"></mspace>
+ <mprescripts/>
+ <mspace width="10px" height="10px" style="background: lightgreen;"></mspace>
+ <mspace width="10px" height="10px" style="background: lightgreen;"></mspace>
+ </mmultiscripts>
+ <msub subscriptshift="300px">
+ <mspace width="30px" height="30px" style="background: blue;"></mspace>
+ <mspace width="10px" height="10px" style="background: lightgreen;"></mspace>
+ </msub>
+ <msup superscriptshift="300px">
+ <mspace width="30px" height="30px" style="background: blue;"></mspace>
+ <mspace width="10px" height="10px" style="background: lightgreen;"></mspace>
+ </msup>
+ <msubsup subscriptshift="300px" superscriptshift="300px">
+ <mspace width="30px" height="30px" style="background: blue;"></mspace>
+ <mspace width="10px" height="10px" style="background: lightgreen;"></mspace>
+ <mspace width="10px" height="10px" style="background: lightgreen;"></mspace>
+ </msubsup>
+ </math>
+ </p>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>
+ MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");
+ MathMLFeatureDetection.ensure_for_match_reftest("has_msubsup");
+ MathMLFeatureDetection.ensure_for_match_reftest("has_mmultiscripts");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-parameters-1.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-parameters-1.html
new file mode 100644
index 0000000000..3f49b1d53b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-parameters-1.html
@@ -0,0 +1,354 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Subscripts and Superscripts parameters</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+<meta name="assert" content="Elements msub, msup, subsup and msubsup correctly use the subscript and superscript parameters from the MATH table.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math, mspace {
+ font-size: 10px;
+ }
+ @font-face {
+ font-family: spaceafterscript3000;
+ src: url("/fonts/math/scripts-spaceafterscript3000.woff");
+ }
+ @font-face {
+ font-family: superscriptshiftup7000;
+ src: url("/fonts/math/scripts-superscriptshiftup7000.woff");
+ }
+ @font-face {
+ font-family: superscriptshiftupcramped5000;
+ src: url("/fonts/math/scripts-superscriptshiftupcramped5000.woff");
+ }
+ @font-face {
+ font-family: subscriptshiftdown6000;
+ src: url("/fonts/math/scripts-subscriptshiftdown6000.woff");
+ }
+ @font-face {
+ font-family: subsuperscriptgapmin11000;
+ src: url("/fonts/math/scripts-subsuperscriptgapmin11000.woff");
+ }
+ @font-face {
+ font-family: subsuperscriptgapmin11000superscriptbottommaxwithsubscript3000;
+ src: url("/fonts/math/scripts-subsuperscriptgapmin11000-superscriptbottommaxwithsubscript3000.woff");
+ }
+ @font-face {
+ font-family: subscripttopmax4000;
+ src: url("/fonts/math/scripts-subscripttopmax4000.woff");
+ }
+ @font-face {
+ font-family: superscriptbottommin8000;
+ src: url("/fonts/math/scripts-superscriptbottommin8000.woff");
+ }
+ @font-face {
+ font-family: subscriptbaselinedropmin9000;
+ src: url("/fonts/math/scripts-subscriptbaselinedropmin9000.woff");
+ }
+ @font-face {
+ font-family: superscriptbaselinedropmax10000;
+ src: url("/fonts/math/scripts-superscriptbaselinedropmax10000.woff");
+ }
+</style>
+<script>
+ var emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+ var epsilon = 1;
+
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 3000 * emToPx;
+ assert_approx_equals(getBox("ref001").left - getBox("sub001").right, v, epsilon, "msub: Space after subscript");
+ assert_approx_equals(getBox("ref002").left - getBox("sup002").right, v, epsilon, "msup: Space after superscript");
+ assert_approx_equals(getBox("ref003").left - getBox("sup003").right, v, epsilon, "msubsup: Space after superscript");
+ assert_approx_equals(getBox("sup0042").left - getBox("sup0041").right, v, epsilon, "mmultiscripts: Space after first superscript");
+ assert_approx_equals(getBox("sup0043").left - getBox("sup0042").right, v, epsilon, "mmultiscripts: Space after second superscript");
+ assert_approx_equals(getBox("ref004").left - getBox("sup0043").right, v, epsilon, "mmultiscripts: Space after last superscript");
+ }, "SpaceAfterScript");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 7000 * emToPx;
+ assert_approx_equals(getBox("ref101").bottom - getBox("sup102").bottom, v, epsilon, "msup: Superscript shift");
+ assert_approx_equals(getBox("ref101").bottom - getBox("sup103").bottom, v, epsilon, "msubsup: Superscript shift");
+ assert_approx_equals(getBox("ref101").bottom - getBox("sup1041").bottom, v, epsilon, "mmultiscripts: First superscript shift");
+ assert_approx_equals(getBox("ref101").bottom - getBox("sup1042").bottom, v, epsilon, "mmultiscripts: Second superscript shift");
+ assert_approx_equals(getBox("ref101").bottom - getBox("sup1043").bottom, v, epsilon, "mmultiscripts: Last superscript shift");
+ }, "SuperscriptShiftUp");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 5000 * emToPx;
+ assert_approx_equals(getBox("ref201").bottom - getBox("sup202").bottom, v, epsilon, "msup: Superscript shift");
+ assert_approx_equals(getBox("ref201").bottom - getBox("sup203").bottom, v, epsilon, "msubsup: Superscript shift");
+ assert_approx_equals(getBox("ref201").bottom - getBox("sup2041").bottom, v, epsilon, "mmultiscripts: First superscript shift");
+ assert_approx_equals(getBox("ref201").bottom - getBox("sup2042").bottom, v, epsilon, "mmultiscripts: Second superscript shift");
+ assert_approx_equals(getBox("ref201").bottom - getBox("sup2043").bottom, v, epsilon, "mmultiscripts: Last superscript shift");
+ }, "SuperscriptShiftUpCramped");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 6000 * emToPx;
+ assert_approx_equals(getBox("sub301").bottom - getBox("ref300").bottom, v, epsilon, "msup: Subscript shift");
+ assert_approx_equals(getBox("sub302").bottom - getBox("ref300").bottom, v, epsilon, "msubsup: Subscript shift");
+ assert_approx_equals(getBox("sub303").bottom - getBox("ref300").bottom, v, epsilon, "mmultiscripts: First subscript shift");
+ assert_approx_equals(getBox("sub304").bottom - getBox("ref300").bottom, v, epsilon, "mmultiscripts: Second subscript shift");
+ }, "SubscriptShiftDown");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 11000 * emToPx;
+ assert_approx_equals(getBox("sub4011").top - getBox("sup4012").bottom, v, epsilon, "msubsup: SubSuperscript gap");
+ assert_approx_equals(getBox("sub4021").top - getBox("sup4022").bottom, v, epsilon, "mmultiscripts: SubSuperscript gap");
+ }, "SubSuperscriptGapMin");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 11000 * emToPx;
+ var v2 = 3000 * emToPx;
+ assert_approx_equals(getBox("sub501").top - getBox("sup501").bottom, v1, epsilon, "msubsup: SubSuperscript gap");
+ assert_approx_equals(getBox("ref500").bottom - getBox("sup501").bottom, v2, epsilon, "msubsup: Superscript bottom");
+ assert_approx_equals(getBox("sub502").top - getBox("sup502").bottom, v1, epsilon, "mmultiscripts: SubSuperscript gap");
+ assert_approx_equals(getBox("ref500").bottom - getBox("sup502").bottom, v2, epsilon, "mmultiscripts: Superscript bottom");
+ }, "SuperscriptBottomMaxWithSubscript");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 4000 * emToPx;
+ assert_approx_equals(getBox("ref600").bottom - getBox("sub601").top, v, epsilon, "msub: Subscript top");
+ }, "SubscriptTopMax");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 8000 * emToPx;
+ assert_approx_equals(getBox("ref700").bottom - getBox("sub701").bottom, v, epsilon, "msub: Superscript bottom");
+ }, "SuperscriptBottomMin");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 9000 * emToPx;
+ assert_approx_equals(getBox("sub801").bottom - getBox("base801").bottom, v, epsilon, "msub: Superscript drop");
+ }, "SubscriptBaselineDrop");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 10000 * emToPx;
+ assert_approx_equals(getBox("sup901").bottom - getBox("base901").top, v, epsilon, "msup: Superscript drop");
+ }, "SuperscriptBaselineDrop");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math style="font-family: spaceafterscript3000;">
+ <msub>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <mspace id="sub001" height="1em" width="1em" style="background: red"/>
+ </msub>
+ <mspace id="ref001" height="1em" width="1em" style="background: green"/>
+ </math>
+ <math style="font-family: spaceafterscript3000;">
+ <msup>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <mspace id="sup002" height="1em" width="1em" style="background: red"/>
+ </msup>
+ <mspace id="ref002" height="1em" width="1em" style="background: green"/>
+ </math>
+ <math style="font-family: spaceafterscript3000;">
+ <msubsup>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <mspace/>
+ <mspace id="sup003" height="1em" width="1em" style="background: red"/>
+ </msubsup>
+ <mspace id="ref003" height="1em" width="1em" style="background: green"/>
+ </math>
+ <math style="font-family: spaceafterscript3000;">
+ <mmultiscripts>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <none/>
+ <mspace id="sup0041" height="1em" width="1em" style="background: red"/>
+ <none/>
+ <mspace id="sup0042" height="1em" width="1em" style="background: red"/>
+ <none/>
+ <mspace id="sup0043" height="1em" width="1em" style="background: red"/>
+ </mmultiscripts>
+ <mspace id="ref004" height="1em" width="1em" style="background: green"/>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: superscriptshiftup7000;">
+ <mspace id="ref101" height="1em" width="1em" style="background: green"/>
+ <msup>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <mspace id="sup102" height="1em" width="1em" style="background: red"/>
+ </msup>
+ <msubsup>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <mspace height="1em" width="1em" style="background: red"/>
+ <mspace id="sup103" height="1em" width="1em" style="background: red"/>
+ </msubsup>
+ <mmultiscripts>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <none/>
+ <mspace id="sup1041" height="1em" width="1em" style="background: red"/>
+ <none/>
+ <mspace id="sup1042" height="1em" width="1em" style="background: red"/>
+ <none/>
+ <mspace id="sup1043" height="1em" width="1em" style="background: red"/>
+ </mmultiscripts>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: superscriptshiftupcramped5000;">
+ <msqrt>
+ <mspace id="ref201" height="1em" width="1em" style="background: green"/>
+ <msup>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <mspace id="sup202" height="1em" width="1em" style="background: red"/>
+ </msup>
+ <msubsup>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <mspace height="1em" width="1em" style="background: blue"/>
+ <mspace id="sup203" height="1em" width="1em" style="background: red"/>
+ </msubsup>
+ <mmultiscripts>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <none/>
+ <mspace id="sup2041" height="1em" width="1em" style="background: red"/>
+ <none/>
+ <mspace id="sup2042" height="1em" width="1em" style="background: red"/>
+ <none/>
+ <mspace id="sup2043" height="1em" width="1em" style="background: red"/>
+ </mmultiscripts>
+ </msqrt>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: subscriptshiftdown6000;">
+ <mspace id="ref300" height="1em" width="1em" style="background: green"/>
+ <msub>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <mspace id="sub301" height="1em" width="1em" style="background: red"/>
+ </msub>
+ <msubsup>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <mspace id="sub302" height="1em" width="1em" style="background: red"/>
+ <mspace height="1em" width="1em" style="background: blue"/>
+ </msubsup>
+ <mmultiscripts>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <mspace id="sub303" height="1em" width="1em" style="background: red"/>
+ <none/>
+ <mspace id="sub304" height="1em" width="1em" style="background: red"/>
+ <none/>
+ </mmultiscripts>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: subsuperscriptgapmin11000;">
+ <msubsup>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <mspace id="sub4011" height="1em" width="1em" style="background: red"/>
+ <mspace id="sup4012" height="1em" width="1em" style="background: red"/>
+ </msubsup>
+ <mmultiscripts>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <none/>
+ <none/>
+ <mspace id="sub4021" height="1em" width="1em" style="background: red"/>
+ <mspace id="sup4022" height="1em" width="1em" style="background: red"/>
+ </mmultiscripts>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: subsuperscriptgapmin11000superscriptbottommaxwithsubscript3000;">
+ <mspace id="ref500" height="1em" width="1em" style="background: green"/>
+ <msubsup>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <mspace id="sub501" height="1em" width="1em" style="background: red"/>
+ <mspace id="sup501" height="1em" width="1em" style="background: red"/>
+ </msubsup>
+ <mmultiscripts>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <none/>
+ <none/>
+ <mspace id="sub502" height="1em" width="1em" style="background: red"/>
+ <mspace id="sup502" height="1em" width="1em" style="background: red"/>
+ </mmultiscripts>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: subscripttopmax4000;">
+ <mspace id="ref600" height="1em"
+ width="1em" style="background: green"/>
+ <msub>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <mspace id="sub601" height="10em"
+ width="1em" style="background: red"/>
+ </msub>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: superscriptbottommin8000;">
+ <mspace id="ref700" height="1em"
+ width="1em" style="background: green"/>
+ <msup>
+ <mspace height="2em" width="2em" style="background: blue"/>
+ <mspace id="sub701" depth="1em"
+ width="1em" style="background: red"/>
+ </msup>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: subscriptbaselinedropmin9000;">
+ <msub>
+ <mspace id="base801" height="2em" width="2em" style="background: blue"/>
+ <mspace id="sub801" height="1em"
+ width="1em" style="background: red"/>
+ </msub>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: superscriptbaselinedropmax10000;">
+ <msup>
+ <mspace id="base901" height="15em" width="2em" style="background: blue"/>
+ <mspace id="sup901" height="1em"
+ width="1em" style="background: red"/>
+ </msup>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-parameters-2.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-parameters-2.html
new file mode 100644
index 0000000000..205697f4e4
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/subsup-parameters-2.html
@@ -0,0 +1,181 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Subscripts and Superscripts parameters</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+<meta name="assert" content="Elements msub, msup, subsup and msubsup correctly use the italic correction from the MATH table.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math, mspace {
+ font-size: 10px;
+ }
+ @font-face {
+ font-family: largeop-displayoperatorminheight5000;
+ src: url("/fonts/math/largeop-displayoperatorminheight5000.woff");
+ }
+ @font-face {
+ font-family: largeop-displayoperatorminheight2000-2AFF-italiccorrection3000;
+ src: url("/fonts/math/largeop-displayoperatorminheight2000-2AFF-italiccorrection3000.woff");
+ }
+ @font-face {
+ font-family: largeop-displayoperatorminheight7000-2AFF-italiccorrection5000;
+ src: url("/fonts/math/largeop-displayoperatorminheight7000-2AFF-italiccorrection5000.woff");
+ }
+</style>
+<script>
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ /*
+ These two tests verify that:
+ - In msub, the script is at the right of the base minus the italic correction.
+ - In msup, the script is just at the right of the base.
+ - In msubsup, the scripts are shifted by the italic correction.
+ - In mmultiscripts, postscript pairs are shifted by the italic correction.
+ - In mmultiscripts, prescript pairs are vertically aligned.
+ */
+ var epsilon = 1;
+ var emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 0;
+ assert_approx_equals(getBox("base001").right - getBox("sub001").left, v, epsilon, "msub");
+ assert_approx_equals(getBox("sup002").left, getBox("base002").right, epsilon, "msup");
+ assert_approx_equals(getBox("sup003").left - getBox("sub003").left, v, epsilon, "msubsup");
+ assert_approx_equals(getBox("sup004").left - getBox("sub004").left, v, epsilon, "mmultiscripts postscripts");
+ assert_approx_equals(getBox("sup005").left - getBox("sub005").left, 0, epsilon, "mmultiscripts prescripts");
+ }, "Null Italic Correction");
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 3000 * emToPx;
+ assert_approx_equals(getBox("base011").right - getBox("sub011").left, v, epsilon, "msub");
+ assert_approx_equals(getBox("sup012").left, getBox("base012").right, epsilon, "msup");
+ assert_approx_equals(getBox("sup013").left - getBox("sub013").left, v, epsilon, "msubsup");
+ assert_approx_equals(getBox("sup014").left - getBox("sub014").left, v, epsilon, "mmultiscripts postscripts");
+ assert_approx_equals(getBox("sup015").left - getBox("sub015").left, 0, epsilon, "mmultiscripts prescripts");
+ }, "NonNull Italic Correction (MathGlyphVariantRecord)");
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 5000 * emToPx;
+ assert_approx_equals(getBox("base021").right - getBox("sub021").left, v, epsilon, "msub");
+ assert_approx_equals(getBox("sup022").left, getBox("base022").right, epsilon, "msup");
+ assert_approx_equals(getBox("sup023").left - getBox("sub023").left, v, epsilon, "msubsup");
+ assert_approx_equals(getBox("sup024").left - getBox("sub024").left, v, epsilon, "mmultiscripts postscripts");
+ assert_approx_equals(getBox("sup025").left - getBox("sub025").left, 0, epsilon, "mmultiscripts prescripts");
+ }, "NonNull Italic Correction (GlyphAssembly)");
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <h2>Null Italic Correction</h2>
+ <p>
+ <math displaystyle="true" style="font-family: largeop-displayoperatorminheight5000;">
+ <msub>
+ <mo id="base001" lspace="0px" rspace="0px">&#x2AFF;</mo>
+ <mspace id="sub001" height="1em" width="1em" style="background: blue"/>
+ </msub>
+ </math>
+ <math displaystyle="true" style="font-family: largeop-displayoperatorminheight5000;">
+ <msup>
+ <mo id="base002" lspace="0px" rspace="0px">&#x2AFF;</mo>
+ <mspace id="sup002" height="1em" width="1em" style="background: blue"/>
+ </msup>
+ </math>
+ <math displaystyle="true" style="font-family: largeop-displayoperatorminheight5000;">
+ <msubsup>
+ <mo lspace="0px" rspace="0px">&#x2AFF;</mo>
+ <mspace id="sub003" height="1em" width="1em" style="background: blue"/>
+ <mspace id="sup003" height="1em" width="1em" style="background: green"/>
+ </msubsup>
+ </math>
+ <math displaystyle="true" style="font-family: largeop-displayoperatorminheight5000;">
+ <mmultiscripts>
+ <mo lspace="0px" rspace="0px">&#x2AFF;</mo>
+ <mspace id="sub004" height="1em" width="1em" style="background: blue"/>
+ <mspace id="sup004" height="1em" width="1em" style="background: green"/>
+ <mprescripts/>
+ <mspace id="sub005" height="1em" width="1em" style="background: magenta"/>
+ <mspace id="sup005" height="1em" width="1em" style="background: cyan"/>
+ </mmultiscripts>
+ </math>
+ </p>
+ <h2>NonNull Italic Correction (MathGlyphVariantRecord)</h2>
+ <p>
+ <math displaystyle="true" style="font-family: largeop-displayoperatorminheight2000-2AFF-italiccorrection3000;">
+ <msub>
+ <mo id="base011" lspace="0px" rspace="0px">&#x2AFF;</mo>
+ <mspace id="sub011" height="1em" width="1em" style="background: blue"/>
+ </msub>
+ </math>
+ <math displaystyle="true" style="font-family: largeop-displayoperatorminheight2000-2AFF-italiccorrection3000;">
+ <msup>
+ <mo id="base012" lspace="0px" rspace="0px">&#x2AFF;</mo>
+ <mspace id="sup012" height="1em" width="1em" style="background: blue"/>
+ </msup>
+ </math>
+ <math displaystyle="true" style="font-family: largeop-displayoperatorminheight2000-2AFF-italiccorrection3000;">
+ <msubsup>
+ <mo lspace="0px" rspace="0px">&#x2AFF;</mo>
+ <mspace id="sub013" height="1em" width="1em" style="background: blue"/>
+ <mspace id="sup013" height="1em" width="1em" style="background: green"/>
+ </msubsup>
+ </math>
+ <math displaystyle="true" style="font-family: largeop-displayoperatorminheight2000-2AFF-italiccorrection3000;">
+ <mmultiscripts>
+ <mo lspace="0px" rspace="0px">&#x2AFF;</mo>
+ <mspace id="sub014" height="1em" width="1em" style="background: blue"/>
+ <mspace id="sup014" height="1em" width="1em" style="background: green"/>
+ <mprescripts/>
+ <mspace id="sub015" height="1em" width="1em" style="background: magenta"/>
+ <mspace id="sup015" height="1em" width="1em" style="background: cyan"/>
+ </mmultiscripts>
+ </math>
+ </p>
+ <h2>NonNull Italic Correction (GlyphAssembly)</h2>
+ <p>
+ <math displaystyle="true" style="font-family: largeop-displayoperatorminheight7000-2AFF-italiccorrection5000;">
+ <msub>
+ <mo id="base021" lspace="0px" rspace="0px">&#x2AFF;</mo>
+ <mspace id="sub021" height="1em" width="1em" style="background: blue"/>
+ </msub>
+ </math>
+ <math displaystyle="true" style="font-family: largeop-displayoperatorminheight7000-2AFF-italiccorrection5000;">
+ <msup>
+ <mo id="base022" lspace="0px" rspace="0px">&#x2AFF;</mo>
+ <mspace id="sup022" height="1em" width="1em" style="background: blue"/>
+ </msup>
+ </math>
+ <math displaystyle="true" style="font-family: largeop-displayoperatorminheight7000-2AFF-italiccorrection5000;">
+ <msubsup>
+ <mo lspace="0px" rspace="0px">&#x2AFF;</mo>
+ <mspace id="sub023" height="1em" width="1em" style="background: blue"/>
+ <mspace id="sup023" height="1em" width="1em" style="background: green"/>
+ </msubsup>
+ </math>
+ <math displaystyle="true" style="font-family: largeop-displayoperatorminheight7000-2AFF-italiccorrection5000;">
+ <mmultiscripts>
+ <mo lspace="0px" rspace="0px">&#x2AFF;</mo>
+ <mspace id="sub024" height="1em" width="1em" style="background: blue"/>
+ <mspace id="sup024" height="1em" width="1em" style="background: green"/>
+ <mprescripts/>
+ <mspace id="sub025" height="1em" width="1em" style="background: magenta"/>
+ <mspace id="sup025" height="1em" width="1em" style="background: cyan"/>
+ </mmultiscripts>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-1.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-1.html
new file mode 100644
index 0000000000..ae4a945404
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-1.html
@@ -0,0 +1,175 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Underscripts and Overscripts parameters</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+<meta name="assert" content="Elements munder, mover, munderover correctly .">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ math, mspace, mo {
+ font-family: Ahem;
+ font-size: 10px;
+ }
+</style>
+<script>
+ /* This test does not use any specific fonts and so the exact rules are not
+ specified precisely. We assume reasonable values for script shifts and
+ spacing. */
+
+ function getBox(aId) {
+ var box = document.getElementById(aId).getBoundingClientRect();
+ box.middle = (box.bottom + box.top) / 2;
+ box.center = (box.left + box.right) / 2;
+ return box;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 1;
+ for (var i = 0; i <= 3; i++) {
+ assert_approx_equals(getBox("under" + i + "base").middle, getBox("baseline").bottom, e, "munder " + i + ": base is placed on the baseline");
+ assert_approx_equals(getBox("over" + i + "base").middle, getBox("baseline").bottom, e, "mover " + i + ": base is placed on the baseline");
+ }
+ for (var i = 0; i <= 5; i++) {
+ assert_approx_equals(getBox("underover" + i + "base").middle, getBox("baseline").bottom, e, "munderover " + i + ": base is placed on the baseline");
+ }
+ }, "Alignment of the base on the baseline");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 1;
+ for (var i = 0; i <= 3; i++) {
+ assert_approx_equals(getBox("under" + i + "under").center, getBox("under" + i + "base").center, e, "munder " + i + ": base and script are horizontally centered");
+ assert_approx_equals(getBox("over" + i + "over").center, getBox("over" + i + "base").center, e, "mover " + i + ": base and script are horizontally centered");
+ }
+ for (var i = 0; i <= 5; i++) {
+ assert_approx_equals(getBox("underover" + i + "under").center, getBox("underover" + i + "base").center, e, "munderover " + i + ": base and underscript are horizontally centered");
+ assert_approx_equals(getBox("underover" + i + "over").center, getBox("underover" + i + "base").center, e, "munderover " + i + ": base and overscript are horizontally centered");
+ }
+ }, "Horizontal alignments of base and scripts");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ for (var i = 0; i <= 3; i++) {
+ assert_greater_than_equal(getBox("under" + i + "under").top, getBox("under" + i + "base").bottom, "munder " + i + ": script is under base");
+ assert_less_than_equal(getBox("over" + i + "over").bottom, getBox("over" + i + "base").top, "mover " + i + ": script is over base");
+ }
+ for (var i = 0; i <= 5; i++) {
+ assert_greater_than_equal(getBox("underover" + i + "under").top, getBox("underover" + i + "base").bottom, "munderover " + i + ": underscript is under base");
+ assert_less_than_equal(getBox("underover" + i + "over").bottom, getBox("underover" + i + "base").top, "munderover " + i + ": overscript is over base");
+ }
+ }, "Relative vertical positions of base and scripts");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 1;
+ for (var i = 0; i <= 3; i++) {
+ assert_approx_equals(getBox("under" + i).width, Math.max(getBox("under" + i + "base").width, getBox("under" + i + "under").width), e, "munder " + i + ": width is determined by the maximum of width of base and script");
+ assert_approx_equals(getBox("over" + i).width, Math.max(getBox("over" + i + "base").width, getBox("over" + i + "over").width), e, "mover " + i + ": width is determined by the maximum of width of base and script");
+ }
+ for (var i = 0; i <= 5; i++) {
+ assert_approx_equals(getBox("underover" + i).width, Math.max(getBox("underover" + i + "base").width, getBox("underover" + i + "under").width, getBox("underover" + i + "over").width), e, "munderover " + i + ": width is determined by the maximum of width of base and scripts");
+ }
+ }, "Width of scripted elements");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var e = 4;
+ for (var i = 0; i <= 3; i++) {
+ assert_approx_equals(getBox("under" + i).height, getBox("under" + i + "base").height + getBox("under" + i + "under").height, e, "munder " + i + ": height is determined by the sum of heights of base and script plus some spacing.");
+ assert_approx_equals(getBox("over" + i).height, getBox("over" + i + "base").height + getBox("over" + i + "over").height, e, "mover " + i + ": height is determined by the sum of heights of base and script plus some spacing.");
+ }
+ for (var i = 0; i <= 5; i++) {
+ assert_approx_equals(getBox("underover" + i).height, getBox("underover" + i + "base").height + getBox("underover" + i + "under").height + getBox("underover" + i + "over").height, e, "munderover " + i + ": height is determined by the sum heights of base and scripts");
+ }
+ }, "Height of scripted elements");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mspace id="baseline" width="30px" height="2px" depth="0px" style="background: blue"/>
+ <munder id="under0">
+ <mspace id="under0base" width="30px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="under0under" width="10px" height="5px" depth="5px" style="background: black"/>
+ </munder>
+ <munder id="under1">
+ <mspace id="under1base" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="under1under" width="30px" height="5px" depth="5px" style="background: black"/>
+ </munder>
+ <munder id="under2">
+ <mspace id="under2base" width="10px" height="15px" depth="15px" style="background: black"/>
+ <mspace id="under2under" width="10px" height="5px" depth="5px" style="background: black"/>
+ </munder>
+ <munder id="under3">
+ <mspace id="under3base" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="under3under" width="10px" height="15px" depth="15px" style="background: black"/>
+ </munder>
+ <mover id="over0">
+ <mspace id="over0base" width="30px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="over0over" width="10px" height="5px" depth="5px" style="background: black"/>
+ </mover>
+ <mover id="over1">
+ <mspace id="over1base" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="over1over" width="30px" height="5px" depth="5px" style="background: black"/>
+ </mover>
+ <mover id="over2">
+ <mspace id="over2base" width="10px" height="15px" depth="15px" style="background: black"/>
+ <mspace id="over2over" width="10px" height="5px" depth="5px" style="background: black"/>
+ </mover>
+ <mover id="over3">
+ <mspace id="over3base" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="over3over" width="10px" height="15px" depth="15px" style="background: black"/>
+ </mover>
+ <munderover id="underover0">
+ <mspace id="underover0base" width="30px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="underover0under" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="underover0over" width="10px" height="5px" depth="5px" style="background: black"/>
+ </munderover>
+ <munderover id="underover1">
+ <mspace id="underover1base" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="underover1under" width="30px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="underover1over" width="10px" height="5px" depth="5px" style="background: black"/>
+ </munderover>
+ <munderover id="underover2">
+ <mspace id="underover2base" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="underover2under" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="underover2over" width="30px" height="5px" depth="5px" style="background: black"/>
+ </munderover>
+ <munderover id="underover3">
+ <mspace id="underover3base" width="10px" height="15px" depth="15px" style="background: black"/>
+ <mspace id="underover3under" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="underover3over" width="10px" height="5px" depth="5px" style="background: black"/>
+ </munderover>
+ <munderover id="underover4">
+ <mspace id="underover4base" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="underover4under" width="10px" height="15px" depth="15px" style="background: black"/>
+ <mspace id="underover4over" width="10px" height="5px" depth="5px" style="background: black"/>
+ </munderover>
+ <munderover id="underover5">
+ <mspace id="underover5base" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="underover5under" width="10px" height="5px" depth="5px" style="background: black"/>
+ <mspace id="underover5over" width="10px" height="15px" depth="15px" style="background: black"/>
+ </munderover>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-legacy-align-attribute-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-legacy-align-attribute-001-ref.html
new file mode 100644
index 0000000000..a9545c60f4
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-legacy-align-attribute-001-ref.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>munder/mover/munderover align (reference)</title>
+ </head>
+ <body>
+ <p>Test passes if the center of the following rectangles is aligned
+ on the same vertical axis.</p>
+ <p>
+ <math>
+ <munder>
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ </munder>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munder>
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ </munder>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mover>
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ </mover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mover>
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ </mover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover>
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover>
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ </munderover>
+ </math>
+ </p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-legacy-align-attribute-001.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-legacy-align-attribute-001.html
new file mode 100644
index 0000000000..aa2460e062
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-legacy-align-attribute-001.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>munder/mover/munderover align</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+ <link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.munder">
+ <link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.mover">
+ <link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.munderover">
+ <meta name="assert" content="Check that the legacy align attribute is ignored.">
+ <link rel="match" href="underover-legacy-align-attribute-001-ref.html">
+ </head>
+ <body>
+ <p>Test passes if the center of the following rectangles is aligned
+ on the same vertical axis.</p>
+ <p>
+ <math>
+ <munder align="left">
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ </munder>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munder align="right">
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ </munder>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mover align="left">
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ </mover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mover align="right">
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ </mover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover align="left">
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover align="right">
+ <mspace width="30px" height="20px" style="background: cyan;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ <mspace width="10px" height="20px" style="background: blue;"></mspace>
+ </munderover>
+ </math>
+ </p>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>
+ MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");
+ MathMLFeatureDetection.ensure_for_match_reftest("has_munderover");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-1.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-1.html
new file mode 100644
index 0000000000..eb2e0512e0
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-1.html
@@ -0,0 +1,151 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Underscripts and Overscripts parameters</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+<meta name="assert" content="Elements munder, mover, munderover correctly use the limit parameters from the MATH table.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math, mspace, mo {
+ font-size: 10px;
+ }
+ @font-face {
+ font-family: lowerlimitbaselinedropmin3000;
+ src: url("/fonts/math/limits-lowerlimitbaselinedropmin3000.woff");
+ }
+ @font-face {
+ font-family: lowerlimitgapmin11000;
+ src: url("/fonts/math/limits-lowerlimitgapmin11000.woff");
+ }
+ @font-face {
+ font-family: upperlimitbaselinerisemin5000;
+ src: url("/fonts/math/limits-upperlimitbaselinerisemin5000.woff");
+ }
+ @font-face {
+ font-family: upperlimitgapmin7000;
+ src: url("/fonts/math/limits-upperlimitgapmin7000.woff");
+ }
+</style>
+<script>
+ var emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+ var epsilon = 1;
+
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 3000 * emToPx;
+ assert_approx_equals(getBox("under00011").top - getBox("ref0001").bottom,
+ v, epsilon, "munder: under shift");
+ assert_approx_equals(getBox("under00012").top - getBox("ref0001").bottom,
+ v, epsilon, "munderover: under shift");
+ }, "LowerLimitBaselineDropMin");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 11000 * emToPx;
+ assert_approx_equals(getBox("under00021").top - getBox("ref0002").bottom,
+ v, epsilon, "munder: under gap");
+ assert_approx_equals(getBox("under00022").top - getBox("ref0002").bottom,
+ v, epsilon, "munderover: under gap");
+ }, "LowerLimitGapMin");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 5000 * emToPx;
+ assert_approx_equals(getBox("ref0003").top - getBox("over00031").bottom,
+ v, epsilon, "mover: over shift");
+ assert_approx_equals(getBox("ref0003").top - getBox("over00032").bottom,
+ v, epsilon, "munderover: over shift");
+ }, "UpperLimitBaselineRiseMin");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 7000 * emToPx;
+ assert_approx_equals(getBox("ref0004").top - getBox("over00041").bottom,
+ v, epsilon, "mover: over shift");
+ assert_approx_equals(getBox("ref0004").top - getBox("over00042").bottom,
+ v, epsilon, "munderover: over shift");
+ }, "UpperLimitGapMin");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math style="font-family: lowerlimitbaselinedropmin3000;">
+ <mspace id="ref0001" height="1em" width="3em" style="background: green"/>
+ <munder>
+ <mo movablelimits="false">&#x2211;</mo>
+ <mspace id="under00011" depth="1em" width="3em" style="background: blue"/>
+ </munder>
+ <munderover>
+ <mo movablelimits="false">&#x2211;</mo>
+ <mspace id="under00012" depth="1em" width="3em" style="background: blue"/>
+ <mspace height="1em" width="3em" style="background: black"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: lowerlimitgapmin11000;">
+ <mspace id="ref0002" height="1em" width="3em" style="background: green"/>
+ <munder>
+ <mo movablelimits="false">&#x2211;</mo>
+ <mspace id="under00021" depth="1em" width="3em" style="background: blue"/>
+ </munder>
+ <munderover>
+ <mo movablelimits="false">&#x2211;</mo>
+ <mspace id="under00022" depth="1em" width="3em" style="background: blue"/>
+ <mspace height="1em" width="3em" style="background: black"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: upperlimitbaselinerisemin5000;">
+ <mspace id="ref0003" height="1em" width="3em" style="background: green"/>
+ <mover>
+ <mo movablelimits="false">&#x2211;</mo>
+ <mspace id="over00031" height="1em" width="3em" style="background: blue"/>
+ </mover>
+ <munderover>
+ <mo movablelimits="false">&#x2211;</mo>
+ <mspace height="1em" width="3em" style="background: black"/>
+ <mspace id="over00032" height="1em" width="3em" style="background: blue"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: upperlimitgapmin7000;">
+ <mspace id="ref0004" height="1em" width="3em" style="background: green"/>
+ <mover>
+ <mo movablelimits="false">&#x2211;</mo>
+ <mspace id="over00041" depth="1em" width="3em" style="background: blue"/>
+ </mover>
+ <munderover>
+ <mo movablelimits="false">&#x2211;</mo>
+ <mspace height="1em" width="3em" style="background: black"/>
+ <mspace id="over00042" depth="1em" width="3em" style="background: blue"/>
+ </munderover>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-2.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-2.html
new file mode 100644
index 0000000000..aad03a3863
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-2.html
@@ -0,0 +1,151 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Underscripts and Overscripts parameters</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+<meta name="assert" content="Elements munder, mover, munderover correctly use the stretch stack parameters from the MATH table.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math, mspace, mo {
+ font-size: 10px;
+ }
+ @font-face {
+ font-family: bottomshiftdown3000;
+ src: url("/fonts/math/stretchstack-bottomshiftdown3000.woff");
+ }
+ @font-face {
+ font-family: gapbelowmin11000;
+ src: url("/fonts/math/stretchstack-gapbelowmin11000.woff");
+ }
+ @font-face {
+ font-family: topshiftup5000;
+ src: url("/fonts/math/stretchstack-topshiftup5000.woff");
+ }
+ @font-face {
+ font-family: gapabovemin7000;
+ src: url("/fonts/math/stretchstack-gapabovemin7000.woff");
+ }
+</style>
+<script>
+ var emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+ var epsilon = 1;
+
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 3000 * emToPx;
+ assert_approx_equals(getBox("under00011").top - getBox("ref0001").bottom,
+ v, epsilon, "munder: under shift");
+ assert_approx_equals(getBox("under00012").top - getBox("ref0001").bottom,
+ v, epsilon, "munderover: under shift");
+ }, "StretchStackBottomShiftDown");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 11000 * emToPx;
+ assert_approx_equals(getBox("under00021").top - getBox("ref0002").bottom,
+ v, epsilon, "munder: under gap");
+ assert_approx_equals(getBox("under00022").top - getBox("ref0002").bottom,
+ v, epsilon, "munderover: under gap");
+ }, "StretchStackGapBelowMin");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 5000 * emToPx;
+ assert_approx_equals(getBox("ref0003").top - getBox("over00031").bottom,
+ v, epsilon, "mover: over shift");
+ assert_approx_equals(getBox("ref0003").top - getBox("over00032").bottom,
+ v, epsilon, "munderover: over shift");
+ }, "StretchStackTopShiftUp");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 7000 * emToPx;
+ assert_approx_equals(getBox("ref0004").top - getBox("over00041").bottom,
+ v, epsilon, "mover: over shift");
+ assert_approx_equals(getBox("ref0004").top - getBox("over00042").bottom,
+ v, epsilon, "munderover: over shift");
+ }, "StretchStackGapAboveMin");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math style="font-family: bottomshiftdown3000;">
+ <mspace id="ref0001" height="1em" width="3em" style="background: green"/>
+ <munder>
+ <mo>&#x2192;</mo>
+ <mspace id="under00011" depth="1em" width="3em" style="background: blue"/>
+ </munder>
+ <munderover>
+ <mo>&#x2192;</mo>
+ <mspace id="under00012" depth="1em" width="3em" style="background: blue"/>
+ <mspace height="1em" width="3em" style="background: black"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: gapbelowmin11000;">
+ <mspace id="ref0002" height="1em" width="3em" style="background: green"/>
+ <munder>
+ <mo>&#x2192;</mo>
+ <mspace id="under00021" depth="1em" width="3em" style="background: blue"/>
+ </munder>
+ <munderover>
+ <mo>&#x2192;</mo>
+ <mspace id="under00022" depth="1em" width="3em" style="background: blue"/>
+ <mspace height="1em" width="3em" style="background: black"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: topshiftup5000;">
+ <mspace id="ref0003" height="1em" width="3em" style="background: green"/>
+ <mover>
+ <mo>&#x2192;</mo>
+ <mspace id="over00031" height="1em" width="3em" style="background: blue"/>
+ </mover>
+ <munderover>
+ <mo>&#x2192;</mo>
+ <mspace height="1em" width="3em" style="background: black"/>
+ <mspace id="over00032" height="1em" width="3em" style="background: blue"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: gapabovemin7000;">
+ <mspace id="ref0004" height="1em" width="3em" style="background: green"/>
+ <mover>
+ <mo>&#x2192;</mo>
+ <mspace id="over00041" depth="1em" width="3em" style="background: blue"/>
+ </mover>
+ <munderover>
+ <mo>&#x2192;</mo>
+ <mspace height="1em" width="3em" style="background: black"/>
+ <mspace id="over00042" depth="1em" width="3em" style="background: blue"/>
+ </munderover>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-3.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-3.html
new file mode 100644
index 0000000000..9ec9dbf47e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-3.html
@@ -0,0 +1,452 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Underscripts and Overscripts parameters</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+<meta name="assert" content="Elements munder, mover, munderover correctly use underbar/overbar and AccentBaseHeight parameters from the MATH table.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math, mspace, mo {
+ font-size: 10px;
+ }
+ @font-face {
+ font-family: accentbaseheight4000underbarextradescender5000;
+ src: url("/fonts/math/underover-accentbaseheight4000-underbarextradescender5000.woff");
+ }
+ @font-face {
+ font-family: accentbaseheight4000underbarverticalgap7000;
+ src: url("/fonts/math/underover-accentbaseheight4000-underbarverticalgap7000.woff");
+ }
+ @font-face {
+ font-family: accentbaseheight4000overbarextraascender3000;
+ src: url("/fonts/math/underover-accentbaseheight4000-overbarextraascender3000.woff");
+ }
+ @font-face {
+ font-family: accentbaseheight4000overbarverticalgap11000;
+ src: url("/fonts/math/underover-accentbaseheight4000-overbarverticalgap11000.woff");
+ }
+</style>
+<script>
+ var emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+ var epsilon = 2;
+ var axisBaseHeight = 4000 * emToPx;
+ var shortBaseHeight = 3000 * emToPx; // shortBaseHeight < axisBaseHeight
+ var tallBaseHeight = 5000 * emToPx; // tallBaseHeight > axisBaseHeight
+
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function getBooleanValue(element, name) {
+ return (element.getAttribute(name) || "").toLowerCase() === "true";
+ }
+ let dynamicBooleanAttributeChanges = {
+ "Invert boolean value using absent attribute": function(element, name) {
+ if (getBooleanValue(element, name)) {
+ element.removeAttribute(name);
+ } else {
+ element.setAttribute(name, "true");
+ }
+ },
+
+ "Invert boolean value using invalid attribute": function(element, name) {
+ if (getBooleanValue(element, name)) {
+ element.setAttribute(name, "invalid");
+ } else {
+ element.setAttribute(name, "true");
+ }
+ },
+
+ "Change case of boolean attribute": function(element, name) {
+ if (getBooleanValue(element, name)) {
+ element.setAttribute(name, "TrUe");
+ } else {
+ element.setAttribute(name, "FaLsE");
+ }
+ }
+ };
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ for (var i = 1; i <= 4; i++) {
+ for (var j = 1; j <= 6; j++) {
+ var baseId = ("base00" + i) + j;
+ assert_approx_equals(getBox("ref00" + i).bottom,
+ getBox(baseId).bottom,
+ epsilon,
+ "alignment of " + baseId);
+ }
+ }
+ }, "Baseline alignment");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ for (var i = 1; i <= 4; i++) {
+ for (var j = 1; j <= 6; j++) {
+ var baseId = ("base00" + i) + j;
+ assert_approx_equals(getBox(baseId).height,
+ j == 2 || j == 5 ?
+ tallBaseHeight :shortBaseHeight,
+ epsilon,
+ "height of " + baseId);
+ }
+ }
+ }, "Heights of bases");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 5000 * emToPx;
+ assert_approx_equals(getBox("ref001").bottom - getBox("over0014").bottom,
+ shortBaseHeight, epsilon,
+ "munderover: nonaccent over short base");
+ assert_approx_equals(getBox("ref001").bottom - getBox("over0015").bottom,
+ tallBaseHeight, epsilon,
+ "munderover: accent over tall base");
+ assert_approx_equals(getBox("ref001").bottom - getBox("over0016").bottom,
+ axisBaseHeight, epsilon,
+ "munderover: accent over short base");
+ for (var j = 1; j <= 6; j++) {
+ var elId = "el001" + j;
+ var baseId = "base001" + j;
+ var underId = "under001" + j;
+ assert_approx_equals(getBox(underId).top - getBox(baseId).bottom,
+ 0, epsilon,
+ "gap between " + baseId + " and " + underId);
+ assert_approx_equals(getBox(elId).bottom - getBox(underId).bottom,
+ v, epsilon,
+ "extra descender below " + underId);
+ }
+ }, "AccentBaseHeight, UnderbarExtraDescender");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 7000 * emToPx;
+ assert_approx_equals(getBox("ref002").bottom - getBox("over0024").bottom,
+ shortBaseHeight, epsilon,
+ "munderover: nonaccent over short base");
+ assert_approx_equals(getBox("ref002").bottom - getBox("over0025").bottom,
+ tallBaseHeight, epsilon,
+ "munderover: accent over tall base");
+ assert_approx_equals(getBox("ref002").bottom - getBox("over0026").bottom,
+ axisBaseHeight, epsilon,
+ "munderover: accent over short base");
+ for (var j = 1; j <= 6; j++) {
+ var elId = "el002" + j;
+ var baseId = "base002" + j;
+ var underId = "under002" + j;
+ var gap = (j == 2 || j == 3 ? 0 : v);
+ assert_approx_equals(getBox(underId).top - getBox(baseId).bottom,
+ gap, epsilon,
+ "gap between " + baseId + " and " + underId);
+ }
+ }, "AccentBaseHeight, UnderbarVerticalGap");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 3000 * emToPx;
+ assert_approx_equals(getBox("ref003").bottom - getBox("over0031").bottom,
+ shortBaseHeight, epsilon,
+ "mover: nonaccent over short base");
+ assert_approx_equals(getBox("ref003").bottom - getBox("over0032").bottom,
+ tallBaseHeight, epsilon,
+ "mover: accent over tall base");
+ assert_approx_equals(getBox("ref003").bottom - getBox("over0033").bottom,
+ axisBaseHeight, epsilon,
+ "mover: accent over short base");
+ assert_approx_equals(getBox("ref003").bottom - getBox("over0034").bottom,
+ shortBaseHeight, epsilon,
+ "munderover: nonaccent over short base");
+ assert_approx_equals(getBox("ref003").bottom - getBox("over0035").bottom,
+ tallBaseHeight, epsilon,
+ "munderover: accent over tall base");
+ assert_approx_equals(getBox("ref003").bottom - getBox("over0036").bottom,
+ axisBaseHeight, epsilon,
+ "munderover: accent over short base");
+ for (var j = 1; j <= 6; j++) {
+ var elId = "el003" + j;
+ var baseId = "base003" + j;
+ if (j >= 4) {
+ var underId = "under003" + j;
+ assert_approx_equals(getBox(underId).top - getBox(baseId).bottom,
+ 0, epsilon,
+ "gap between " + baseId + " and " + underId);
+ }
+ var overId = "over003" + j;
+ assert_approx_equals(getBox(overId).top - getBox(elId).top,
+ v, epsilon,
+ "extra ascender below " + overId);
+ }
+ }, "AccentBaseHeight, OverbarExtraAscender");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ v = 11000 * emToPx;
+ assert_approx_equals(getBox("ref004").bottom - getBox("over0041").bottom,
+ shortBaseHeight + v, epsilon,
+ "mover: nonaccent over short base");
+ assert_approx_equals(getBox("ref004").bottom - getBox("over0042").bottom,
+ tallBaseHeight, epsilon,
+ "mover: accent over tall base");
+ assert_approx_equals(getBox("ref004").bottom - getBox("over0043").bottom,
+ axisBaseHeight, epsilon,
+ "mover: accent over short base");
+ assert_approx_equals(getBox("ref004").bottom - getBox("over0044").bottom,
+ shortBaseHeight + v, epsilon,
+ "munderover: nonaccent over short base");
+ assert_approx_equals(getBox("ref004").bottom - getBox("over0045").bottom,
+ tallBaseHeight, epsilon,
+ "munderover: accent over tall base");
+ assert_approx_equals(getBox("ref004").bottom - getBox("over0046").bottom,
+ axisBaseHeight, epsilon,
+ "munderover: accent over short base");
+ for (var j = 4; j <= 6; j++) {
+ var baseId = "base004" + j;
+ var underId = "under004" + j;
+ assert_approx_equals(getBox(underId).top - getBox(baseId).bottom,
+ 0, epsilon,
+ "gap between " + baseId + " and " + underId);
+ }
+ }, "AccentBaseHeight, OverbarVerticalGap");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var v = 7000 * emToPx;
+
+ for (var j = 1; j <= 4; j++) {
+ var elId = `el005${j}`;
+ var baseId = `base005${j}`;
+ var underId = `under005${j}`;
+
+ for (name in dynamicBooleanAttributeChanges) {
+ let element = document.getElementById(elId);
+ dynamicBooleanAttributeChanges[name](element, "accentunder");
+ var value = getBooleanValue(element, "accentunder");
+ var gap = value ? 0 : v;
+ assert_approx_equals(getBox(underId).top - getBox(baseId).bottom,
+ gap, epsilon,
+ `${elId}: gap between base and underscript ; ${name}`);
+ };
+ }
+ }, "Dynamic change of accentunder attribute");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ v = 11000 * emToPx;
+ for (var j = 1; j <= 4; j++) {
+ var elId = `el006${j}`;
+ var refId = `base006${j}`;
+ var overId = `over006${j}`;
+ for (name in dynamicBooleanAttributeChanges) {
+ let element = document.getElementById(elId);
+ dynamicBooleanAttributeChanges[name](element, "accent");
+ var value = getBooleanValue(element, "accent");
+ assert_approx_equals(getBox(refId).bottom - getBox(overId).bottom,
+ value ? axisBaseHeight : shortBaseHeight + v,
+ epsilon,
+ `${elId}: accent=${value} ; short base ; ${name}`);
+ }
+ }
+ }, "Dynamic change of accent attribute");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math style="font-family: accentbaseheight4000underbarextradescender5000;">
+ <mspace id="ref001" height="1em" width="3em" style="background: green"/>
+ <munder style="background: cyan" id="el0011">
+ <mspace id="base0011" height="3em" width="1em" style="background: black"/>
+ <mspace id="under0011" height="1em" width="3em" style="background: blue"/>
+ </munder>
+ <munder style="background: cyan" id="el0012" accentunder="true">
+ <mspace id="base0012" height="5em" width="1em" style="background: black"/>
+ <mspace id="under0012" height="1em" width="3em" style="background: blue"/>
+ </munder>
+ <munder style="background: cyan" id="el0013" accentunder="true">
+ <mspace id="base0013" height="3em" width="1em" style="background: black"/>
+ <mspace id="under0013" height="1em" width="3em" style="background: blue"/>
+ </munder>
+ <munderover style="background: cyan" id="el0014">
+ <mspace id="base0014" height="3em" width="1em" style="background: black"/>
+ <mspace id="under0014" height="1em" width="3em" style="background: blue"/>
+ <mspace id="over0014" height="1em" width="3em" style="background: red"/>
+ </munderover>
+ <munderover style="background: cyan" id="el0015" accent="true">
+ <mspace id="base0015" height="5em" width="1em" style="background: black"/>
+ <mspace id="under0015" height="1em" width="3em" style="background: blue"/>
+ <mspace id="over0015" height="1em" width="3em" style="background: red"/>
+ </munderover>
+ <munderover style="background: cyan" id="el0016" accent="true">
+ <mspace id="base0016" height="3em" width="1em" style="background: black"/>
+ <mspace id="under0016" height="1em" width="3em" style="background: blue"/>
+ <mspace id="over0016" height="1em" width="3em" style="background: red"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: accentbaseheight4000underbarverticalgap7000;">
+ <mspace id="ref002" height="1em" width="3em" style="background: green"/>
+ <munder style="background: cyan" id="el0021">
+ <mspace id="base0021" height="3em" width="1em" style="background: black"/>
+ <mspace id="under0021" height="1em" width="3em" style="background: blue"/>
+ </munder>
+ <munder style="background: cyan" id="el0022" accentunder="true">
+ <mspace id="base0022" height="5em" width="1em" style="background: black"/>
+ <mspace id="under0022" height="1em" width="3em" style="background: blue"/>
+ </munder>
+ <munder style="background: cyan" id="el0023" accentunder="true">
+ <mspace id="base0023" height="3em" width="1em" style="background: black"/>
+ <mspace id="under0023" height="1em" width="3em" style="background: blue"/>
+ </munder>
+ <munderover style="background: cyan" id="el0024">
+ <mspace id="base0024" height="3em" width="1em" style="background: black"/>
+ <mspace id="under0024" height="1em" width="3em" style="background: blue"/>
+ <mspace id="over0024" height="1em" width="3em" style="background: red"/>
+ </munderover>
+ <munderover style="background: cyan" id="el0025" accent="true">
+ <mspace id="base0025" height="5em" width="1em" style="background: black"/>
+ <mspace id="under0025" height="1em" width="3em" style="background: blue"/>
+ <mspace id="over0025" height="1em" width="3em" style="background: red"/>
+ </munderover>
+ <munderover style="background: cyan" id="el0026" accent="true">
+ <mspace id="base0026" height="3em" width="1em" style="background: black"/>
+ <mspace id="under0026" height="1em" width="3em" style="background: blue"/>
+ <mspace id="over0026" height="1em" width="3em" style="background: red"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: accentbaseheight4000overbarextraascender3000;">
+ <mspace id="ref003" height="1em" width="3em" style="background: green"/>
+ <mover style="background: cyan" id="el0031">
+ <mspace id="base0031" height="3em" width="1em" style="background: black"/>
+ <mspace id="over0031" height="1em" width="3em" style="background: red"/>
+ </mover>
+ <mover style="background: cyan" id="el0032" accent="true">
+ <mspace id="base0032" height="5em" width="1em" style="background: black"/>
+ <mspace id="over0032" height="1em" width="3em" style="background: red"/>
+ </mover>
+ <mover style="background: cyan" id="el0033" accent="true">
+ <mspace id="base0033" height="3em" width="1em" style="background: black"/>
+ <mspace id="over0033" height="1em" width="3em" style="background: red"/>
+ </mover>
+ <munderover style="background: cyan" id="el0034">
+ <mspace id="base0034" height="3em" width="1em" style="background: black"/>
+ <mspace id="under0034" height="1em" width="3em" style="background: blue"/>
+ <mspace id="over0034" height="1em" width="3em" style="background: red"/>
+ </munderover>
+ <munderover style="background: cyan" id="el0035" accent="true">
+ <mspace id="base0035" height="5em" width="1em" style="background: black"/>
+ <mspace id="under0035" height="1em" width="3em" style="background: blue"/>
+ <mspace id="over0035" height="1em" width="3em" style="background: red"/>
+ </munderover>
+ <munderover style="background: cyan" id="el0036" accent="true">
+ <mspace id="base0036" height="3em" width="1em" style="background: black"/>
+ <mspace id="under0036" height="1em" width="3em" style="background: blue"/>
+ <mspace id="over0036" height="1em" width="3em" style="background: red"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: accentbaseheight4000overbarverticalgap11000;">
+ <mspace id="ref004" height="1em" width="3em" style="background: green"/>
+ <mover style="background: cyan" id="el0041">
+ <mspace id="base0041" height="3em" width="1em" style="background: black"/>
+ <mspace id="over0041" height="1em" width="3em" style="background: red"/>
+ </mover>
+ <mover style="background: cyan" id="el0042" accent="true">
+ <mspace id="base0042" height="5em" width="1em" style="background: black"/>
+ <mspace id="over0042" height="1em" width="3em" style="background: red"/>
+ </mover>
+ <mover style="background: cyan" id="el0043" accent="true">
+ <mspace id="base0043" height="3em" width="1em" style="background: black"/>
+ <mspace id="over0043" height="1em" width="3em" style="background: red"/>
+ </mover>
+ <munderover style="background: cyan" id="el0044">
+ <mspace id="base0044" height="3em" width="1em" style="background: black"/>
+ <mspace id="under0044" height="1em" width="3em" style="background: blue"/>
+ <mspace id="over0044" height="1em" width="3em" style="background: red"/>
+ </munderover>
+ <munderover style="background: cyan" id="el0045" accent="true">
+ <mspace id="base0045" height="5em" width="1em" style="background: black"/>
+ <mspace id="under0045" height="1em" width="3em" style="background: blue"/>
+ <mspace id="over0045" height="1em" width="3em" style="background: red"/>
+ </munderover>
+ <munderover style="background: cyan" id="el0046" accent="true">
+ <mspace id="base0046" height="3em" width="1em" style="background: black"/>
+ <mspace id="under0046" height="1em" width="3em" style="background: blue"/>
+ <mspace id="over0046" height="1em" width="3em" style="background: red"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: accentbaseheight4000underbarverticalgap7000;">
+ <mspace id="ref005" height="1em" width="3em" style="background: green"/>
+ <munder style="background: cyan" id="el0051">
+ <mspace id="base0051" height="5em" width="1em" style="background: black"/>
+ <mspace id="under0051" height="1em" width="3em" style="background: blue"/>
+ </munder>
+ <munder style="background: cyan" id="el0052" accentunder="true">
+ <mspace id="base0052" height="5em" width="1em" style="background: black"/>
+ <mspace id="under0052" height="1em" width="3em" style="background: blue"/>
+ </munder>
+ <munderover style="background: cyan" id="el0053">
+ <mspace id="base0053" height="5em" width="1em" style="background: black"/>
+ <mspace id="under0053" height="1em" width="3em" style="background: blue"/>
+ <mspace id="over0053" height="1em" width="3em" style="background: red"/>
+ </munderover>
+ <munderover style="background: cyan" id="el0054" accentunder="true">
+ <mspace id="base0054" height="5em" width="1em" style="background: black"/>
+ <mspace id="under0054" height="1em" width="3em" style="background: blue"/>
+ <mspace id="over0054" height="1em" width="3em" style="background: red"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: accentbaseheight4000overbarverticalgap11000;">
+ <mspace id="ref006" height="1em" width="3em" style="background: green"/>
+ <mover style="background: cyan" id="el0061">
+ <mspace id="base0061" height="3em" width="1em" style="background: black"/>
+ <mspace id="over0061" height="1em" width="3em" style="background: red"/>
+ </mover>
+ <mover style="background: cyan" id="el0062" accent="true">
+ <mspace id="base0062" height="3em" width="1em" style="background: black"/>
+ <mspace id="over0062" height="1em" width="3em" style="background: red"/>
+ </mover>
+ <munderover style="background: cyan" id="el0063">
+ <mspace id="base0063" height="3em" width="1em" style="background: black"/>
+ <mspace id="under0063" height="1em" width="3em" style="background: blue"/>
+ <mspace id="over0063" height="1em" width="3em" style="background: red"/>
+ </munderover>
+ <munderover style="background: cyan" id="el0064" accent="true">
+ <mspace id="base0064" height="3em" width="1em" style="background: black"/>
+ <mspace id="under0064" height="1em" width="3em" style="background: blue"/>
+ <mspace id="over0064" height="1em" width="3em" style="background: red"/>
+ </munderover>
+ </math>
+ </p>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-4.tentative.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-4.tentative.html
new file mode 100644
index 0000000000..5000d24f18
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-4.tentative.html
@@ -0,0 +1,335 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Underscripts and Overscripts parameters</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+<link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.mo.attrs">
+<meta name="assert" content="Elements munder, mover, munderover correctly use underbar/overbar and AccentBaseHeight parameters from the MATH table ; interaction with MathML3 mo@accent.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math, mspace, mo {
+ font-size: 10px;
+ }
+ @font-face {
+ font-family: accentbaseheight4000underbarextradescender5000;
+ src: url("/fonts/math/underover-accentbaseheight4000-underbarextradescender5000.woff");
+ }
+ @font-face {
+ font-family: accentbaseheight4000underbarverticalgap7000;
+ src: url("/fonts/math/underover-accentbaseheight4000-underbarverticalgap7000.woff");
+ }
+ @font-face {
+ font-family: accentbaseheight4000overbarextraascender3000;
+ src: url("/fonts/math/underover-accentbaseheight4000-overbarextraascender3000.woff");
+ }
+ @font-face {
+ font-family: accentbaseheight4000overbarverticalgap11000;
+ src: url("/fonts/math/underover-accentbaseheight4000-overbarverticalgap11000.woff");
+ }
+</style>
+<script>
+ var emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+ var epsilon = 2;
+ var axisBaseHeight = 4000 * emToPx;
+ var shortBaseHeight = 3000 * emToPx; // shortBaseHeight < axisBaseHeight
+ var tallBaseHeight = 5000 * emToPx; // tallBaseHeight > axisBaseHeight
+
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ for (var i = 1; i <= 4; i++) {
+ for (var j = 1; j <= 6; j++) {
+ var baseId = ("base00" + i) + j;
+ assert_approx_equals(getBox("ref00" + i).bottom,
+ getBox(baseId).bottom,
+ epsilon,
+ "alignment of " + baseId);
+ }
+ }
+ }, "Baseline alignment");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ for (var i = 1; i <= 4; i++) {
+ for (var j = 1; j <= 6; j++) {
+ var baseId = ("base00" + i) + j;
+ assert_approx_equals(getBox(baseId).height,
+ j == 2 || j == 5 ?
+ tallBaseHeight :shortBaseHeight,
+ epsilon,
+ "height of " + baseId);
+ }
+ }
+ }, "Heights of bases");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 5000 * emToPx;
+ assert_approx_equals(getBox("ref001").bottom - getBox("over0014").bottom,
+ shortBaseHeight, epsilon,
+ "munderover: nonaccent over short base");
+ assert_approx_equals(getBox("ref001").bottom - getBox("over0015").bottom,
+ tallBaseHeight, epsilon,
+ "munderover: accent over tall base");
+ assert_approx_equals(getBox("ref001").bottom - getBox("over0016").bottom,
+ axisBaseHeight, epsilon,
+ "munderover: accent over short base");
+ for (var j = 1; j <= 6; j++) {
+ var elId = "el001" + j;
+ var baseId = "base001" + j;
+ var underId = "under001" + j;
+ assert_approx_equals(getBox(underId).top - getBox(baseId).bottom,
+ 0, epsilon,
+ "gap between " + baseId + " and " + underId);
+ assert_approx_equals(getBox(elId).bottom - getBox(underId).bottom,
+ v, epsilon,
+ "extra descender below " + underId);
+ }
+ }, "AccentBaseHeight, UnderbarExtraDescender");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 7000 * emToPx;
+ assert_approx_equals(getBox("ref002").bottom - getBox("over0024").bottom,
+ shortBaseHeight, epsilon,
+ "munderover: nonaccent over short base");
+ assert_approx_equals(getBox("ref002").bottom - getBox("over0025").bottom,
+ tallBaseHeight, epsilon,
+ "munderover: accent over tall base");
+ assert_approx_equals(getBox("ref002").bottom - getBox("over0026").bottom,
+ axisBaseHeight, epsilon,
+ "munderover: accent over short base");
+ for (var j = 1; j <= 6; j++) {
+ var elId = "el002" + j;
+ var baseId = "base002" + j;
+ var underId = "under002" + j;
+ var gap = (j == 2 || j == 3 ? 0 : v);
+ assert_approx_equals(getBox(underId).top - getBox(baseId).bottom,
+ gap, epsilon,
+ "gap between " + baseId + " and " + underId);
+ }
+ }, "AccentBaseHeight, UnderbarVerticalGap");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 3000 * emToPx;
+ assert_approx_equals(getBox("ref003").bottom - getBox("over0031").bottom,
+ shortBaseHeight, epsilon,
+ "mover: nonaccent over short base");
+ assert_approx_equals(getBox("ref003").bottom - getBox("over0032").bottom,
+ tallBaseHeight, epsilon,
+ "mover: accent over tall base");
+ assert_approx_equals(getBox("ref003").bottom - getBox("over0033").bottom,
+ axisBaseHeight, epsilon,
+ "mover: accent over short base");
+ assert_approx_equals(getBox("ref003").bottom - getBox("over0034").bottom,
+ shortBaseHeight, epsilon,
+ "munderover: nonaccent over short base");
+ assert_approx_equals(getBox("ref003").bottom - getBox("over0035").bottom,
+ tallBaseHeight, epsilon,
+ "munderover: accent over tall base");
+ assert_approx_equals(getBox("ref003").bottom - getBox("over0036").bottom,
+ axisBaseHeight, epsilon,
+ "munderover: accent over short base");
+ for (var j = 1; j <= 6; j++) {
+ var elId = "el003" + j;
+ var baseId = "base003" + j;
+ if (j >= 4) {
+ var underId = "under003" + j;
+ assert_approx_equals(getBox(underId).top - getBox(baseId).bottom,
+ 0, epsilon,
+ "gap between " + baseId + " and " + underId);
+ }
+ var overId = "over003" + j;
+ assert_approx_equals(getBox(overId).top - getBox(elId).top,
+ v, epsilon,
+ "extra ascender below " + overId);
+ }
+ }, "AccentBaseHeight, OverbarExtraAscender");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ v = 11000 * emToPx;
+ assert_approx_equals(getBox("ref004").bottom - getBox("over0041").bottom,
+ shortBaseHeight + v, epsilon,
+ "mover: nonaccent over short base");
+ assert_approx_equals(getBox("ref004").bottom - getBox("over0042").bottom,
+ tallBaseHeight, epsilon,
+ "mover: accent over tall base");
+ assert_approx_equals(getBox("ref004").bottom - getBox("over0043").bottom,
+ axisBaseHeight, epsilon,
+ "mover: accent over short base");
+ assert_approx_equals(getBox("ref004").bottom - getBox("over0044").bottom,
+ shortBaseHeight + v, epsilon,
+ "munderover: nonaccent over short base");
+ assert_approx_equals(getBox("ref004").bottom - getBox("over0045").bottom,
+ tallBaseHeight, epsilon,
+ "munderover: accent over tall base");
+ assert_approx_equals(getBox("ref004").bottom - getBox("over0046").bottom,
+ axisBaseHeight, epsilon,
+ "munderover: accent over short base");
+ for (var j = 4; j <= 6; j++) {
+ var baseId = "base004" + j;
+ var underId = "under004" + j;
+ assert_approx_equals(getBox(underId).top - getBox(baseId).bottom,
+ 0, epsilon,
+ "gap between " + baseId + " and " + underId);
+ }
+ }, "AccentBaseHeight, OverbarVerticalGap");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math style="font-family: accentbaseheight4000underbarextradescender5000;">
+ <mspace id="ref001" height="1em" width="3em" style="background: green"/>
+ <munder style="background: cyan" id="el0011">
+ <mspace id="base0011" height="3em" width="1em" style="background: black"/>
+ <mo id="under0011" style="color: blue">&#xB0;</mo>
+ </munder>
+ <munder style="background: cyan" id="el0012">
+ <mspace id="base0012" height="5em" width="1em" style="background: black"/>
+ <mo id="under0012" style="color: blue">&#x2D8;</mo>
+ </munder>
+ <munder style="background: cyan" id="el0013">
+ <mspace id="base0013" height="3em" width="1em" style="background: black"/>
+ <mo id="under0013" style="color: blue">&#x2D8;</mo>
+ </munder>
+ <munderover style="background: cyan" id="el0014">
+ <mspace id="base0014" height="3em" width="1em" style="background: black"/>
+ <mo id="under0014" style="color: blue">&#xB0;</mo>
+ <mo id="over0014" style="color: red">&#xB0;</mo>
+ </munderover>
+ <munderover style="background: cyan" id="el0015" accent="true">
+ <mspace id="base0015" height="5em" width="1em" style="background: black"/>
+ <mo id="under0015" style="color: blue">&#x2D8;</mo>
+ <mo id="over0015" style="color: red">&#x2D8;</mo>
+ </munderover>
+ <munderover style="background: cyan" id="el0016" accent="true">
+ <mspace id="base0016" height="3em" width="1em" style="background: black"/>
+ <mo id="under0016" style="color: blue">&#x2D8;</mo>
+ <mo id="over0016" style="color: red">&#x2D8;</mo>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: accentbaseheight4000underbarverticalgap7000;">
+ <mspace id="ref002" height="1em" width="3em" style="background: green"/>
+ <munder style="background: cyan" id="el0021" accentunder="false">
+ <mspace id="base0021" height="3em" width="1em" style="background: black"/>
+ <mo id="under0021" style="color: blue">&#x2D8;</mo>
+ </munder>
+ <munder style="background: cyan" id="el0022">
+ <mspace id="base0022" height="5em" width="1em" style="background: black"/>
+ <mo id="under0022" style="color: blue" accent="true">&#x2D8;</mo>
+ </munder>
+ <munder style="background: cyan" id="el0023">
+ <mspace id="base0023" height="3em" width="1em" style="background: black"/>
+ <mo id="under0023" style="color: blue" accent="true">&#xB0;</mo>
+ </munder>
+ <munderover style="background: cyan" id="el0024">
+ <mspace id="base0024" height="3em" width="1em" style="background: black"/>
+ <mo id="under0024" style="color: blue" accent="false">&#x2D8;</mo>
+ <mo id="over0024" style="color: red" accent="false">&#x2D8;</mo>
+ </munderover>
+ <munderover style="background: cyan" id="el0025">
+ <mspace id="base0025" height="5em" width="1em" style="background: black"/>
+ <mo id="under0025" style="color: blue" accent="false">&#x2D8;</mo>
+ <mo id="over0025" style="color: red">&#x2D8;</mo>
+ </munderover>
+ <munderover style="background: cyan" id="el0026">
+ <mspace id="base0026" height="3em" width="1em" style="background: black"/>
+ <mo id="under0026" style="color: blue" accent="false">&#x2D8;</mo>
+ <mo id="over0026" style="color: red">&#x2D8;</mo>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: accentbaseheight4000overbarextraascender3000;">
+ <mspace id="ref003" height="1em" width="3em" style="background: green"/>
+ <mover style="background: cyan" id="el0031">
+ <mspace id="base0031" height="3em" width="1em" style="background: black"/>
+ <mo id="over0031" style="color: red">&#xB0;</mo>
+ </mover>
+ <mover style="background: cyan" id="el0032" accent="true">
+ <mspace id="base0032" height="5em" width="1em" style="background: black"/>
+ <mo id="over0032" style="color: red">&#xB0;</mo>
+ </mover>
+ <mover style="background: cyan" id="el0033">
+ <mspace id="base0033" height="3em" width="1em" style="background: black"/>
+ <mo id="over0033" style="color: red">&#x2D8;</mo>
+ </mover>
+ <munderover style="background: cyan" id="el0034">
+ <mspace id="base0034" height="3em" width="1em" style="background: black"/>
+ <mo id="under0034" style="color: blue">&#xB0;</mo>
+ <mo id="over0034" style="color: red" accent="false">&#x2D8;</mo>
+ </munderover>
+ <munderover style="background: cyan" id="el0035" accent="true">
+ <mspace id="base0035" height="5em" width="1em" style="background: black"/>
+ <mo id="under0035" style="color: blue">&#x2D8;</mo>
+ <mo id="over0035" style="color: red">&#x2D8;</mo>
+ </munderover>
+ <munderover style="background: cyan" id="el0036" accent="true">
+ <mspace id="base0036" height="3em" width="1em" style="background: black"/>
+ <mo id="under0036" style="color: blue">&#x2D8;</mo>
+ <mo id="over0036" style="color: red">&#x2D8;</mo>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: accentbaseheight4000overbarverticalgap11000;">
+ <mspace id="ref004" height="1em" width="3em" style="background: green"/>
+ <mover style="background: cyan" id="el0041">
+ <mspace id="base0041" height="3em" width="1em" style="background: black"/>
+ <mo id="over0041" style="color: red">&#xB0;</mo>
+ </mover>
+ <mover style="background: cyan" id="el0042" accent="true">
+ <mspace id="base0042" height="5em" width="1em" style="background: black"/>
+ <mo id="over0042" style="color: red">&#xB0;</mo>
+ </mover>
+ <mover style="background: cyan" id="el0043">
+ <mspace id="base0043" height="3em" width="1em" style="background: black"/>
+ <mo id="over0043" style="color: red">&#x2D8;</mo>
+ </mover>
+ <munderover style="background: cyan" id="el0044">
+ <mspace id="base0044" height="3em" width="1em" style="background: black"/>
+ <mo id="under0044" style="color: blue">&#xB0;</mo>
+ <mo id="over0044" style="color: red" accent="false">&#x2D8;</mo>
+ </munderover>
+ <munderover style="background: cyan" id="el0045" accent="true">
+ <mspace id="base0045" height="5em" width="1em" style="background: black"/>
+ <mo id="under0045" style="color: blue">&#x2D8;</mo>
+ <mo id="over0045" style="color: red">&#x2D8;</mo>
+ </munderover>
+ <munderover style="background: cyan" id="el0046" accent="true">
+ <mspace id="base0046" height="3em" width="1em" style="background: black"/>
+ <mo id="under0046" style="color: blue">&#x2D8;</mo>
+ <mo id="over0046" style="color: red">&#x2D8;</mo>
+ </munderover>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-and-embellished-operator-1.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-and-embellished-operator-1.html
new file mode 100644
index 0000000000..1c236eabed
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-and-embellished-operator-1.html
@@ -0,0 +1,151 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Underscripts and Overscripts parameters (embellished operators)</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+<meta name="assert" content="Elements munder, mover, munderover (with an embelished operator base) correctly use the limit parameters from the MATH table.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math, mspace, mo {
+ font-size: 10px;
+ }
+ @font-face {
+ font-family: lowerlimitbaselinedropmin3000;
+ src: url("/fonts/math/limits-lowerlimitbaselinedropmin3000.woff");
+ }
+ @font-face {
+ font-family: lowerlimitgapmin11000;
+ src: url("/fonts/math/limits-lowerlimitgapmin11000.woff");
+ }
+ @font-face {
+ font-family: upperlimitbaselinerisemin5000;
+ src: url("/fonts/math/limits-upperlimitbaselinerisemin5000.woff");
+ }
+ @font-face {
+ font-family: upperlimitgapmin7000;
+ src: url("/fonts/math/limits-upperlimitgapmin7000.woff");
+ }
+</style>
+<script>
+ var emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+ var epsilon = 1;
+
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 3000 * emToPx;
+ assert_approx_equals(getBox("under00011").top - getBox("ref0001").bottom,
+ v, epsilon, "munder: under shift");
+ assert_approx_equals(getBox("under00012").top - getBox("ref0001").bottom,
+ v, epsilon, "munderover: under shift");
+ }, "LowerLimitBaselineDropMin");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 11000 * emToPx;
+ assert_approx_equals(getBox("under00021").top - getBox("ref0002").bottom,
+ v, epsilon, "munder: under gap");
+ assert_approx_equals(getBox("under00022").top - getBox("ref0002").bottom,
+ v, epsilon, "munderover: under gap");
+ }, "LowerLimitGapMin");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 5000 * emToPx;
+ assert_approx_equals(getBox("ref0003").top - getBox("over00031").bottom,
+ v, epsilon, "mover: over shift");
+ assert_approx_equals(getBox("ref0003").top - getBox("over00032").bottom,
+ v, epsilon, "munderover: over shift");
+ }, "UpperLimitBaselineRiseMin");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 7000 * emToPx;
+ assert_approx_equals(getBox("ref0004").top - getBox("over00041").bottom,
+ v, epsilon, "mover: over shift");
+ assert_approx_equals(getBox("ref0004").top - getBox("over00042").bottom,
+ v, epsilon, "munderover: over shift");
+ }, "UpperLimitGapMin");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math style="font-family: lowerlimitbaselinedropmin3000;">
+ <mspace id="ref0001" height="1em" width="3em" style="background: green"/>
+ <munder>
+ <mrow><mrow><mo movablelimits="false">&#x2211;</mo></mrow></mrow>
+ <mspace id="under00011" depth="1em" width="3em" style="background: blue"/>
+ </munder>
+ <munderover>
+ <mrow><mrow><mo movablelimits="false">&#x2211;</mo></mrow></mrow>
+ <mspace id="under00012" depth="1em" width="3em" style="background: blue"/>
+ <mspace height="1em" width="3em" style="background: black"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: lowerlimitgapmin11000;">
+ <mspace id="ref0002" height="1em" width="3em" style="background: green"/>
+ <munder>
+ <mrow><mrow><mo movablelimits="false">&#x2211;</mo></mrow></mrow>
+ <mspace id="under00021" depth="1em" width="3em" style="background: blue"/>
+ </munder>
+ <munderover>
+ <mrow><mrow><mo movablelimits="false">&#x2211;</mo></mrow></mrow>
+ <mspace id="under00022" depth="1em" width="3em" style="background: blue"/>
+ <mspace height="1em" width="3em" style="background: black"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: upperlimitbaselinerisemin5000;">
+ <mspace id="ref0003" height="1em" width="3em" style="background: green"/>
+ <mover>
+ <mrow><mrow><mo movablelimits="false">&#x2211;</mo></mrow></mrow>
+ <mspace id="over00031" height="1em" width="3em" style="background: blue"/>
+ </mover>
+ <munderover>
+ <mrow><mrow><mo movablelimits="false">&#x2211;</mo></mrow></mrow>
+ <mspace height="1em" width="3em" style="background: black"/>
+ <mspace id="over00032" height="1em" width="3em" style="background: blue"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: upperlimitgapmin7000;">
+ <mspace id="ref0004" height="1em" width="3em" style="background: green"/>
+ <mover>
+ <mrow><mrow><mo movablelimits="false">&#x2211;</mo></mrow></mrow>
+ <mspace id="over00041" depth="1em" width="3em" style="background: blue"/>
+ </mover>
+ <munderover>
+ <mrow><mrow><mo movablelimits="false">&#x2211;</mo></mrow></mrow>
+ <mspace height="1em" width="3em" style="background: black"/>
+ <mspace id="over00042" depth="1em" width="3em" style="background: blue"/>
+ </munderover>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-and-embellished-operator-2.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-and-embellished-operator-2.html
new file mode 100644
index 0000000000..04a97786c4
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-parameters-and-embellished-operator-2.html
@@ -0,0 +1,151 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Underscripts and Overscripts parameters (embellished operators)</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+<meta name="assert" content="Elements munder, mover, munderover (with an embelished operator base) correctly use the stretch stack parameters from the MATH table.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math, mspace, mo {
+ font-size: 10px;
+ }
+ @font-face {
+ font-family: bottomshiftdown3000;
+ src: url("/fonts/math/stretchstack-bottomshiftdown3000.woff");
+ }
+ @font-face {
+ font-family: gapbelowmin11000;
+ src: url("/fonts/math/stretchstack-gapbelowmin11000.woff");
+ }
+ @font-face {
+ font-family: topshiftup5000;
+ src: url("/fonts/math/stretchstack-topshiftup5000.woff");
+ }
+ @font-face {
+ font-family: gapabovemin7000;
+ src: url("/fonts/math/stretchstack-gapabovemin7000.woff");
+ }
+</style>
+<script>
+ var emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+ var epsilon = 1;
+
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 3000 * emToPx;
+ assert_approx_equals(getBox("under00011").top - getBox("ref0001").bottom,
+ v, epsilon, "munder: under shift");
+ assert_approx_equals(getBox("under00012").top - getBox("ref0001").bottom,
+ v, epsilon, "munderover: under shift");
+ }, "StretchStackBottomShiftDown");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 11000 * emToPx;
+ assert_approx_equals(getBox("under00021").top - getBox("ref0002").bottom,
+ v, epsilon, "munder: under gap");
+ assert_approx_equals(getBox("under00022").top - getBox("ref0002").bottom,
+ v, epsilon, "munderover: under gap");
+ }, "StretchStackGapBelowMin");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 5000 * emToPx;
+ assert_approx_equals(getBox("ref0003").top - getBox("over00031").bottom,
+ v, epsilon, "mover: over shift");
+ assert_approx_equals(getBox("ref0003").top - getBox("over00032").bottom,
+ v, epsilon, "munderover: over shift");
+ }, "StretchStackTopShiftUp");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v = 7000 * emToPx;
+ assert_approx_equals(getBox("ref0004").top - getBox("over00041").bottom,
+ v, epsilon, "mover: over shift");
+ assert_approx_equals(getBox("ref0004").top - getBox("over00042").bottom,
+ v, epsilon, "munderover: over shift");
+ }, "StretchStackGapAboveMin");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math style="font-family: bottomshiftdown3000;">
+ <mspace id="ref0001" height="1em" width="3em" style="background: green"/>
+ <munder>
+ <mrow><mrow><mo>&#x2192;</mo></mrow></mrow>
+ <mspace id="under00011" depth="1em" width="3em" style="background: blue"/>
+ </munder>
+ <munderover>
+ <mrow><mrow><mo>&#x2192;</mo></mrow></mrow>
+ <mspace id="under00012" depth="1em" width="3em" style="background: blue"/>
+ <mspace height="1em" width="3em" style="background: black"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: gapbelowmin11000;">
+ <mspace id="ref0002" height="1em" width="3em" style="background: green"/>
+ <munder>
+ <mrow><mrow><mo>&#x2192;</mo></mrow></mrow>
+ <mspace id="under00021" depth="1em" width="3em" style="background: blue"/>
+ </munder>
+ <munderover>
+ <mrow><mrow><mo>&#x2192;</mo></mrow></mrow>
+ <mspace id="under00022" depth="1em" width="3em" style="background: blue"/>
+ <mspace height="1em" width="3em" style="background: black"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: topshiftup5000;">
+ <mspace id="ref0003" height="1em" width="3em" style="background: green"/>
+ <mover>
+ <mrow><mrow><mo>&#x2192;</mo></mrow></mrow>
+ <mspace id="over00031" height="1em" width="3em" style="background: blue"/>
+ </mover>
+ <munderover>
+ <mrow><mrow><mo>&#x2192;</mo></mrow></mrow>
+ <mspace height="1em" width="3em" style="background: black"/>
+ <mspace id="over00032" height="1em" width="3em" style="background: blue"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math style="font-family: gapabovemin7000;">
+ <mspace id="ref0004" height="1em" width="3em" style="background: green"/>
+ <mover>
+ <mrow><mrow><mo>&#x2192;</mo></mrow></mrow>
+ <mspace id="over00041" depth="1em" width="3em" style="background: blue"/>
+ </mover>
+ <munderover>
+ <mrow><mrow><mo>&#x2192;</mo></mrow></mrow>
+ <mspace height="1em" width="3em" style="background: black"/>
+ <mspace id="over00042" depth="1em" width="3em" style="background: blue"/>
+ </munderover>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-001-ref.html
new file mode 100644
index 0000000000..89ac9c6324
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-001-ref.html
@@ -0,0 +1,167 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Horizontal stretchy operator (reference)</title>
+<style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/stretchy.woff");
+ }
+ math, mo {
+ font-family: TestFont;
+ font-size: 50px;
+ }
+</style>
+<body>
+ <p>This test passes if you see green rectangles and no red.</p>
+
+ <div style="position: absolute; left: 3em; top; 3em;
+ width: 1000px; height: 500px; background: lightgreen;">
+
+ <div style="position: absolute; top: 1px; left: 1px;">
+ <!-- stretchy base in munder -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ </munder>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 251px;">
+ <!-- stretchy script in munder -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munder>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 101px; left: 1px;">
+ <!-- stretchy base in mover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ </mover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 101px; left: 251px;">
+ <!-- stretchy script in mover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </mover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 201px; left: 1px;">
+ <!-- stretchy base in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 201px; left: 251px;">
+ <!-- stretchy underscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 301px; left: 1px;">
+ <!-- stretchy overscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 501px;">
+ <!-- stretchy base and underscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 151px; left: 501px;">
+ <!-- stretchy base and overscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 301px; left: 501px;">
+ <!-- stretchy scripts in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 751px;">
+ <!-- Only stretchy operators in munderover. The widest unstretched size
+ is used as the target size. -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="font-size: 1em; color: green;">⥚</mo>
+ <mo lspace="0" rspace="0" style="font-size: 4em; color: green;">⥚</mo>
+ <mo lspace="0" rspace="0" style="font-size: 2em; color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+ </div>
+ <script>
+ MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");
+ MathMLFeatureDetection.ensure_for_match_reftest("has_munderover");
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-001.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-001.html
new file mode 100644
index 0000000000..6b0f99ec11
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-001.html
@@ -0,0 +1,270 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Horizontal stretchy operator</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dfn-algorithm-for-stretching-operators-along-the-inline-axis">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-operators">
+<link rel="match" href="underover-stretchy-001-ref.html"/>
+<meta name="assert" content="Verify visual rendering of padding/border/margin on an operator, stretchy along the inline axis.">
+<script src="/mathml/support/feature-detection.js"></script>
+<style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/stretchy.woff");
+ }
+ math, mo {
+ font-family: TestFont;
+ font-size: 50px;
+ }
+</style>
+<body>
+ <p>This test passes if you see green rectangles and no red.</p>
+ <!-- The red mspace elements below are expected to be covered by the green
+ stretchy mo elements. -->
+
+ <div style="position: absolute; left: 3em; top; 3em;
+ width: 1000px; height: 500px; background: lightgreen;">
+
+ <div style="position: absolute; top: 1px; left: 1px;">
+ <!-- stretchy base in munder -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ </munder>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ </munder>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 251px;">
+ <!-- stretchy script in munder -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </munder>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munder>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 101px; left: 1px;">
+ <!-- stretchy base in mover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ </mover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ </mover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 101px; left: 251px;">
+ <!-- stretchy script in mover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </mover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </mover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 201px; left: 1px;">
+ <!-- stretchy base in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 201px; left: 251px;">
+ <!-- stretchy underscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 301px; left: 1px;">
+ <!-- stretchy overscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 501px;">
+ <!-- stretchy base and underscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 151px; left: 501px;">
+ <!-- stretchy base and overscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 301px; left: 501px;">
+ <!-- stretchy scripts in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 751px;">
+ <!-- Only stretchy operators in munderover. The widest unstretched size
+ is used as the target size. -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="198px" height="198px" style="background: red; margin: 1px;"/>
+ <mspace width="198px" height="98px" style="background: red; margin: 1px;"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="font-size: 1em; color: green;">⥚</mo>
+ <mo lspace="0" rspace="0" style="font-size: 4em; color: green;">⥚</mo>
+ <mo lspace="0" rspace="0" style="font-size: 2em; color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+ </div>
+ <script>
+ MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");
+ MathMLFeatureDetection.ensure_for_match_reftest("has_munderover");
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-002-ref.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-002-ref.html
new file mode 100644
index 0000000000..c12c74d654
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-002-ref.html
@@ -0,0 +1,167 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Horizontal stretchy operator, embellished with two nested mrows (reference)</title>
+<style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/stretchy.woff");
+ }
+ math, mo {
+ font-family: TestFont;
+ font-size: 50px;
+ }
+</style>
+<body>
+ <p>This test passes if you see green rectangles and no red.</p>
+
+ <div style="position: absolute; left: 3em; top; 3em;
+ width: 1000px; height: 500px; background: lightgreen;">
+
+ <div style="position: absolute; top: 1px; left: 1px;">
+ <!-- stretchy base in munder -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ </munder>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 251px;">
+ <!-- stretchy script in munder -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munder>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 101px; left: 1px;">
+ <!-- stretchy base in mover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ </mover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 101px; left: 251px;">
+ <!-- stretchy script in mover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </mover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 201px; left: 1px;">
+ <!-- stretchy base in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 201px; left: 251px;">
+ <!-- stretchy underscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 301px; left: 1px;">
+ <!-- stretchy overscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 501px;">
+ <!-- stretchy base and underscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 151px; left: 501px;">
+ <!-- stretchy base and overscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 301px; left: 501px;">
+ <!-- stretchy scripts in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 751px;">
+ <!-- Only stretchy operators in munderover. The widest unstretched size
+ is used as the target size. -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="font-size: 1em; color: green;">⥚</mo>
+ <mo lspace="0" rspace="0" style="font-size: 4em; color: green;">⥚</mo>
+ <mo lspace="0" rspace="0" style="font-size: 2em; color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+ </div>
+ <script>
+ MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");
+ MathMLFeatureDetection.ensure_for_match_reftest("has_munderover");
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-002.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-002.html
new file mode 100644
index 0000000000..a1cfa20bb4
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-002.html
@@ -0,0 +1,272 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Horizontal stretchy operator, embellished with two nested mrows</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dfn-algorithm-for-stretching-operators-along-the-inline-axis">
+<link rel="help" href="https://w3c.github.io/mathml-core/#algorithm-for-stretching-operators-along-the-block-axis">
+<link rel="help" href="https://w3c.github.io/mathml-core/#embellished-operators">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-operators">
+<link rel="match" href="underover-stretchy-002-ref.html"/>
+<meta name="assert" content="Verify visual rendering of padding/border/margin on an embellished operator, stretchy along the inline axis.">
+<script src="/mathml/support/feature-detection.js"></script>
+<style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/stretchy.woff");
+ }
+ math, mo {
+ font-family: TestFont;
+ font-size: 50px;
+ }
+</style>
+<body>
+ <p>This test passes if you see green rectangles and no red.</p>
+ <!-- The red mspace elements below are expected to be covered by the green
+ stretchy mo elements. -->
+
+ <div style="position: absolute; left: 3em; top; 3em;
+ width: 1000px; height: 500px; background: lightgreen;">
+
+ <div style="position: absolute; top: 1px; left: 1px;">
+ <!-- stretchy base in munder -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ </munder>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <mrow><mrow><mo lspace="0" rspace="0" style="color: green;">⥚</mo></mrow></mrow>
+ <mspace width="200px" height="0px"/>
+ </munder>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 251px;">
+ <!-- stretchy script in munder -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </munder>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <mspace width="200px" height="0px"/>
+ <mrow><mrow><mo lspace="0" rspace="0" style="color: green;">⥚</mo></mrow></mrow>
+ </munder>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 101px; left: 1px;">
+ <!-- stretchy base in mover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ </mover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <mrow><mrow><mo lspace="0" rspace="0" style="color: green;">⥚</mo></mrow></mrow>
+ <mspace width="200px" height="0px"/>
+ </mover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 101px; left: 251px;">
+ <!-- stretchy script in mover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </mover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <mspace width="200px" height="0px"/>
+ <mrow><mrow><mo lspace="0" rspace="0" style="color: green;">⥚</mo></mrow></mrow>
+ </mover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 201px; left: 1px;">
+ <!-- stretchy base in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mrow><mrow><mo lspace="0" rspace="0" style="color: green;">⥚</mo></mrow></mrow>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 201px; left: 251px;">
+ <!-- stretchy underscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mrow><mrow><mo lspace="0" rspace="0" style="color: green;">⥚</mo></mrow></mrow>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 301px; left: 1px;">
+ <!-- stretchy overscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ <mrow><mrow><mo lspace="0" rspace="0" style="color: green;">⥚</mo></mrow></mrow>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 501px;">
+ <!-- stretchy base and underscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mrow><mrow><mo lspace="0" rspace="0" style="color: green;">⥚</mo></mrow></mrow>
+ <mspace width="200px" height="0px"/>
+ <mrow><mrow><mo lspace="0" rspace="0" style="color: green;">⥚</mo></mrow></mrow>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 151px; left: 501px;">
+ <!-- stretchy base and overscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mrow><mrow><mo lspace="0" rspace="0" style="color: green;">⥚</mo></mrow></mrow>
+ <mspace width="200px" height="0px"/>
+ <mrow><mrow><mo lspace="0" rspace="0" style="color: green;">⥚</mo></mrow></mrow>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 301px; left: 501px;">
+ <!-- stretchy scripts in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mrow><mrow><mo lspace="0" rspace="0" style="color: green;">⥚</mo></mrow></mrow>
+ <mrow><mrow><mo lspace="0" rspace="0" style="color: green;">⥚</mo></mrow></mrow>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 751px;">
+ <!-- Only stretchy operators in munderover. The widest unstretched size
+ is used as the target size. -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="198px" height="198px" style="background: red; margin: 1px;"/>
+ <mspace width="198px" height="98px" style="background: red; margin: 1px;"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="font-size: 1em; color: green;">⥚</mo>
+ <mo lspace="0" rspace="0" style="font-size: 4em; color: green;">⥚</mo>
+ <mo lspace="0" rspace="0" style="font-size: 2em; color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+ </div>
+ <script>
+ MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");
+ MathMLFeatureDetection.ensure_for_match_reftest("has_munderover");
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-003-ref.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-003-ref.html
new file mode 100644
index 0000000000..02c7ce2efb
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-003-ref.html
@@ -0,0 +1,167 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Horizontal stretchy operator, embellished with an munderover (reference)</title>
+<style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/stretchy.woff");
+ }
+ math, mo {
+ font-family: TestFont;
+ font-size: 50px;
+ }
+</style>
+<body>
+ <p>This test passes if you see green rectangles and no red.</p>
+
+ <div style="position: absolute; left: 3em; top; 3em;
+ width: 1000px; height: 500px; background: lightgreen;">
+
+ <div style="position: absolute; top: 1px; left: 1px;">
+ <!-- stretchy base in munder -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ </munder>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 251px;">
+ <!-- stretchy script in munder -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munder>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 101px; left: 1px;">
+ <!-- stretchy base in mover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ </mover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 101px; left: 251px;">
+ <!-- stretchy script in mover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </mover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 201px; left: 1px;">
+ <!-- stretchy base in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 201px; left: 251px;">
+ <!-- stretchy underscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 301px; left: 1px;">
+ <!-- stretchy overscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 501px;">
+ <!-- stretchy base and underscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 151px; left: 501px;">
+ <!-- stretchy base and overscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 301px; left: 501px;">
+ <!-- stretchy scripts in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ <mo lspace="0" rspace="0" style="color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 751px;">
+ <!-- Only stretchy operators in munderover. The widest unstretched size
+ is used as the target size. -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="font-size: 1em; color: green;">⥚</mo>
+ <mo lspace="0" rspace="0" style="font-size: 4em; color: green;">⥚</mo>
+ <mo lspace="0" rspace="0" style="font-size: 2em; color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+ </div>
+ <script>
+ MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");
+ MathMLFeatureDetection.ensure_for_match_reftest("has_munderover");
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-003.html b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-003.html
new file mode 100644
index 0000000000..735fcab63e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/scripts/underover-stretchy-003.html
@@ -0,0 +1,272 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Horizontal stretchy operator, embellished with an munderover</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dfn-algorithm-for-stretching-operators-along-the-inline-axis">
+<link rel="help" href="https://w3c.github.io/mathml-core/#algorithm-for-stretching-operators-along-the-block-axis">
+<link rel="help" href="https://w3c.github.io/mathml-core/#embellished-operators">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-operators">
+<link rel="match" href="underover-stretchy-003-ref.html"/>
+<meta name="assert" content="Verify visual rendering of padding/border/margin on an embellished operator, stretchy along the inline axis.">
+<script src="/mathml/support/feature-detection.js"></script>
+<style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/stretchy.woff");
+ }
+ math, mo {
+ font-family: TestFont;
+ font-size: 50px;
+ }
+</style>
+<body>
+ <p>This test passes if you see green rectangles and no red.</p>
+ <!-- The red mspace elements below are expected to be covered by the green
+ stretchy mo elements. -->
+
+ <div style="position: absolute; left: 3em; top; 3em;
+ width: 1000px; height: 500px; background: lightgreen;">
+
+ <div style="position: absolute; top: 1px; left: 1px;">
+ <!-- stretchy base in munder -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ </munder>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <munderover><mo lspace="0" rspace="0" style="color: green;">⥚</mo><mspace/><mspace/></munderover>
+ <mspace width="200px" height="0px"/>
+ </munder>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 251px;">
+ <!-- stretchy script in munder -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </munder>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munder>
+ <mspace width="200px" height="0px"/>
+ <munderover><mo lspace="0" rspace="0" style="color: green;">⥚</mo><mspace/><mspace/></munderover>
+ </munder>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 101px; left: 1px;">
+ <!-- stretchy base in mover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ </mover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <munderover><mo lspace="0" rspace="0" style="color: green;">⥚</mo><mspace/><mspace/></munderover>
+ <mspace width="200px" height="0px"/>
+ </mover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 101px; left: 251px;">
+ <!-- stretchy script in mover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </mover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <mover>
+ <mspace width="200px" height="0px"/>
+ <munderover><mo lspace="0" rspace="0" style="color: green;">⥚</mo><mspace/><mspace/></munderover>
+ </mover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 201px; left: 1px;">
+ <!-- stretchy base in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <munderover><mo lspace="0" rspace="0" style="color: green;">⥚</mo><mspace/><mspace/></munderover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 201px; left: 251px;">
+ <!-- stretchy underscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <munderover><mo lspace="0" rspace="0" style="color: green;">⥚</mo><mspace/><mspace/></munderover>
+ <mspace width="200px" height="0px"/>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 301px; left: 1px;">
+ <!-- stretchy overscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="200px" height="0px"/>
+ <munderover><mo lspace="0" rspace="0" style="color: green;">⥚</mo><mspace/><mspace/></munderover>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 501px;">
+ <!-- stretchy base and underscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <munderover><mo lspace="0" rspace="0" style="color: green;">⥚</mo><mspace/><mspace/></munderover>
+ <mspace width="200px" height="0px"/>
+ <munderover><mo lspace="0" rspace="0" style="color: green;">⥚</mo><mspace/><mspace/></munderover>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 151px; left: 501px;">
+ <!-- stretchy base and overscript in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <munderover><mo lspace="0" rspace="0" style="color: green;">⥚</mo><mspace/><mspace/></munderover>
+ <mspace width="200px" height="0px"/>
+ <munderover><mo lspace="0" rspace="0" style="color: green;">⥚</mo><mspace/><mspace/></munderover>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 301px; left: 501px;">
+ <!-- stretchy scripts in munderover -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="200px" height="0px"/>
+ <munderover><mo lspace="0" rspace="0" style="color: green;">⥚</mo><mspace/><mspace/></munderover>
+ <munderover><mo lspace="0" rspace="0" style="color: green;">⥚</mo><mspace/><mspace/></munderover>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div style="position: absolute; top: 1px; left: 751px;">
+ <!-- Only stretchy operators in munderover. The widest unstretched size
+ is used as the target size. -->
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mspace width="198px" height="48px" style="background: red; margin: 1px;"/>
+ <mspace width="198px" height="198px" style="background: red; margin: 1px;"/>
+ <mspace width="198px" height="98px" style="background: red; margin: 1px;"/>
+ </munderover>
+ </math>
+ </div>
+ <div style="position: absolute; left: 0; top: 0;">
+ <math>
+ <munderover>
+ <mo lspace="0" rspace="0" style="font-size: 1em; color: green;">⥚</mo>
+ <mo lspace="0" rspace="0" style="font-size: 4em; color: green;">⥚</mo>
+ <mo lspace="0" rspace="0" style="font-size: 2em; color: green;">⥚</mo>
+ </munderover>
+ </math>
+ </div>
+ </div>
+ </div>
+ <script>
+ MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");
+ MathMLFeatureDetection.ensure_for_match_reftest("has_munderover");
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-children-ref.html b/testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-children-ref.html
new file mode 100644
index 0000000000..ae74024c2f
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-children-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>space (reference)</title>
+</head>
+<body>
+ <p>Test passes if you see a green square and no text.</p>
+ <math><mspace width="200px" height="200px" style="background: green"></mspace></math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-children.html b/testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-children.html
new file mode 100644
index 0000000000..8520f83d24
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-children.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+<title>space</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#space-mspace">
+<link rel="match" href="mspace-children-ref.html"/>
+<meta name="assert" content="Verify mspace visual rendering of its children">
+</head>
+<body>
+ <p>Test passes if you see a green square and no text.</p>
+ <math><mspace width="200px" height="200px" style="background: green">Text Node <mtext>x</mtext></mspace></math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-percentage-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-percentage-001-ref.html
new file mode 100644
index 0000000000..da4f1dd397
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-percentage-001-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>mspace percentages (reference)</title>
+ <style>
+ .red {
+ background: red;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if there is a green square with no red.</p>
+ <math display="block"
+ style="width: 200px; height: 200px; background: green">
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-percentage-001.html b/testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-percentage-001.html
new file mode 100644
index 0000000000..758429e1db
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-percentage-001.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>mspace percentages</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#space-mspace">
+ <meta name="assert" content="Verify that percentage values for mspace do not use refer to the containing block">
+ <link rel="match" href="mspace-percentage-001-ref.html">
+ <style>
+ .red {
+ background: red;
+ }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if there is a green square with no red.</p>
+ <math display="block"
+ style="width: 200px; height: 200px; background: green">
+ <mspace width="5%" height="10px" class="red"></mspace>
+ <mspace width=" 5%" height="10px" class="red"></mspace>
+ <mspace width="5% " height="10px" class="red"></mspace>
+ <mspace width="10px" height="5%" class="red"></mspace>
+ <mspace width="10px" height=" 5%" class="red"></mspace>
+ <mspace width="10px" height="5% " class="red"></mspace>
+ <mspace width="10px" depth="5%" class="red"></mspace>
+ <mspace width="10px" depth=" 5%" class="red"></mspace>
+ <mspace width="10px" depth="5% " class="red"></mspace>
+ <mspace width="10px" height="5%" depth="5%" class="red"></mspace>
+ <mspace width="10px" height=" 5%" depth=" 5%" class="red"></mspace>
+ <mspace width="10px" height="5% " depth="5% " class="red"></mspace>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-width-height-001.html b/testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-width-height-001.html
new file mode 100644
index 0000000000..52b3eaa190
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/spaces/mspace-width-height-001.html
@@ -0,0 +1,113 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Space</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#space-mspace">
+<meta name="assert" content="Verify mspace metrics for different values of height, depth and width">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ var epsilon = 1;
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function getMetrics(aId) {
+ let baseline = document.getElementById("baseline").getBoundingClientRect();
+ let mspace = document.getElementById(aId).getBoundingClientRect();
+ return {
+ width: mspace.width,
+ height: mspace.height,
+ line_ascent: (baseline.top + baseline.bottom)/2 - mspace.top
+ };
+ }
+
+ function runTests() {
+ test(function() {
+ let metrics = getMetrics("widthAttributePlusWidthProperty");
+ assert_approx_equals(metrics.width, 200, epsilon,
+ "mspace width overridden by inline style");
+ assert_approx_equals(metrics.height, 200, epsilon,
+ "mspace height as specified by height attribute");
+ assert_approx_equals(metrics.line_ascent, 200, epsilon,
+ "mspace line-ascent as specified by height attribute");
+ }, "width attribute + width property");
+
+ test(function() {
+ let metrics = getMetrics("heightAndDepthAttributesPlusHeightProperty");
+ assert_approx_equals(metrics.width, 200, epsilon,
+ "mspace width as specified by attribute");
+ assert_approx_equals(metrics.height, 200, epsilon,
+ "mspace height overridden by inline style");
+ assert_approx_equals(metrics.line_ascent, 100, epsilon,
+ "mspace line-ascent as specified by height attribute");
+ }, "height/depth attributes + height property");
+
+ test(function() {
+ let metrics = getMetrics("heightAttributePlusHeightProperty");
+ assert_approx_equals(metrics.width, 200, epsilon,
+ "mspace width as specified by attribute");
+ assert_approx_equals(metrics.height, 200, epsilon,
+ "mspace height overridden by inline style");
+ assert_approx_equals(metrics.line_ascent, 300, epsilon,
+ "mspace line-ascent as specified by height attribute");
+ }, "height attribute + height property");
+
+ test(function() {
+ let metrics = getMetrics("depthAttributePlusHeightProperty");
+ assert_approx_equals(metrics.width, 200, epsilon,
+ "mspace width as specified by attribute");
+ assert_approx_equals(metrics.height, 200, epsilon,
+ "mspace height overridden by inline style");
+ assert_approx_equals(metrics.line_ascent, 0, epsilon,
+ "mspace line-ascent defaults to 0");
+ }, "depth attribute + height property");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+
+ <math>
+ <!-- Reference baseline -->
+ <mspace id="baseline" style="background: black"
+ width="10px" height="100px" depth="100px"/>
+
+ <!-- width="500px" is a presentational hint
+ setting the element's width property to the corresponding value,
+ overridden by the inline style width: 200px.
+ height="200px" sets the height/line-ascent to 200px. -->
+ <mspace id="widthAttributePlusWidthProperty"
+ width="500px" height="200px"
+ style="width: 200px; background: green"/>
+
+ <!-- height="100px" + depth="200px" are used as a presentational hint
+ setting the element's height property to calc(100px + 200px),
+ overridden by inline style height: 200px.
+ height="100px" sets the line-ascent to 100px. -->
+ <mspace id="heightAndDepthAttributesPlusHeightProperty"
+ width="200px" height="100px" depth="200px"
+ style="height: 200px; background: blue"/>
+
+ <!-- height="300px" is used as a presentational hint
+ setting the element's height property to the corresponding value,
+ overridden by inline style height: 200px.
+ height="300px" sets the line-ascent to 300px. -->
+ <mspace id="heightAttributePlusHeightProperty"
+ width="200px" height="300px"
+ style="height: 200px; background: magenta"/>
+
+ <!-- depth="300px" is used as a presentational hint
+ setting the element's height property to the corresponding value,
+ overridden by inline style height: 200px.
+ The line-ascent defaults to 0. -->
+ <mspace id="depthAttributePlusHeightProperty"
+ width="200px" depth="300px"
+ style="height: 200px; background: yellow"/>
+ </math>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/spaces/space-1.html b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-1.html
new file mode 100644
index 0000000000..4cb2a58a3c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-1.html
@@ -0,0 +1,150 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Space</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#space-mspace">
+<meta name="assert" content="Verify mspace metrics for different values of height, depth and width">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ var epsilon = 1;
+ function getBox(aId) {
+ var box = document.getElementById(aId).getBoundingClientRect();
+ box.middle = (box.bottom + box.top) / 2;
+ box.center = (box.left + box.right) / 2;
+ return box;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+ test(function() {
+ var empty = getBox("empty");
+ assert_equals(empty.width, 0, "zero width");
+ assert_approx_equals(getBox("baseline").bottom - empty.top, 0, epsilon, "zero depth");
+ assert_approx_equals(empty.bottom - getBox("baseline").bottom, 0, epsilon, "zero depth");
+ }, "Empty mspace");
+
+ test(function() {
+ for (var i = 0; i <= 2; i++) {
+ var space = getBox("width" + i);
+ assert_approx_equals(space.width, 25*(i+1), epsilon, "width " + i);
+ assert_approx_equals(getBox("baseline").bottom - space.top, 0, epsilon, "height" + i);
+ assert_approx_equals(space.bottom - getBox("baseline").bottom, 0, epsilon, "depth" + i);
+ }
+ }, "Different widths");
+
+ test(function() {
+ for (var i = 0; i <= 2; i++) {
+ var space = getBox("height" + i);
+ assert_equals(space.width, 0, "width" + i);
+ assert_approx_equals(getBox("baseline").bottom - space.top, 25*(i+1), epsilon, "height" + i);
+ assert_approx_equals(space.bottom - getBox("baseline").bottom, 0, epsilon, "depth" + i);
+ }
+ }, "Different heights");
+
+ test(function() {
+ for (var i = 0; i <= 2; i++) {
+ var space = getBox("depth" + i);
+ assert_equals(space.width, 0, "width" + i);
+ assert_approx_equals(getBox("baseline").bottom - space.top, 0, epsilon, "height" + i);
+ assert_approx_equals(space.bottom - getBox("baseline").bottom, 25*(i+1), epsilon, "depth" + i);
+ }
+ }, "Different depths");
+
+ test(function() {
+ for (var i = 0; i <= 2; i++) {
+ var space = getBox("mspace" + i);
+ assert_approx_equals(space.width, 25*(1+i%3), epsilon, "width" + i);
+ assert_approx_equals(getBox("baseline").bottom - space.top, 25*(1+(i+1)%3), epsilon, "height" + i);
+ assert_approx_equals(space.bottom - getBox("baseline").bottom, 25*(1+(i+2)%3), epsilon, "depth" + i);
+ }
+ }, "Various combinations of height, depth and width.");
+
+ test(function() {
+ var container = document.getElementById("containerForPreferredWidth");
+ var mspace = container.getElementsByTagName("mspace")[0];
+ var containerWidth = container.getBoundingClientRect().width;
+ var mspaceWidth = mspace.getBoundingClientRect().width;
+ assert_approx_equals(containerWidth, mspaceWidth, epsilon);
+ }, "Preferred width");
+
+ // Dynamically set attributes.
+ ["width", "height", "depth"].forEach(function (name, index) {
+ document.getElementById("dynamic-remove").removeAttribute(name);
+ let length = `${50 + index * 10}px`;
+ document.getElementById("dynamic-attach").setAttribute(name, length);
+ document.getElementById("dynamic-modify").setAttribute(name, length);
+ });
+ let baseline = getBox("baseline2").bottom;
+
+ test(function() {
+ let remove = getBox("dynamic-remove");
+ assert_approx_equals(remove.width, 0, epsilon);
+ assert_approx_equals(remove.height, 0, epsilon);
+ assert_approx_equals(remove.top, baseline, epsilon);
+ }, "dynamic attributes (remove)");
+
+ test(function() {
+ let attach = getBox("dynamic-attach");
+ assert_approx_equals(attach.width, 50, epsilon);
+ assert_approx_equals(attach.height, 60 + 70, epsilon);
+ assert_approx_equals(baseline - attach.top, 60, epsilon);
+ }, "dynamic attributes (attach)");
+
+ test(function() {
+ let modify = getBox("dynamic-modify");
+ assert_approx_equals(modify.width, 50, epsilon);
+ assert_approx_equals(modify.height, 60 + 70, epsilon);
+ assert_approx_equals(baseline - modify.top, 60, epsilon);
+ }, "dynamic attributes (modify)");
+
+ done();
+ }
+</script>
+<style>
+div.shrink-wrap {
+ background: yellow;
+ display: inline-block;
+ margin-top: 5px;
+ padding-top: 5px;
+}
+</style>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <span id="baseline" style="display: inline-block; width: 30px; height: 5px; background: blue"></span>
+ <math>
+ <mspace id="empty"/>
+ <mspace id="width0" width="25px"/>
+ <mspace id="width1" width="50px"/>
+ <mspace id="width2" width="75px"/>
+ <mspace id="height0" height="25px"/>
+ <mspace id="height1" height="50px"/>
+ <mspace id="height2" height="75px"/>
+ <mspace id="depth0" depth="25px"/>
+ <mspace id="depth1" depth="50px"/>
+ <mspace id="depth2" depth="75px"/>
+ <mspace id="mspace0" width="25px" height="50px" depth="75px" style="background: green"/>
+ <mspace id="mspace1" width="50px" height="75px" depth="25px" style="background: blue"/>
+ <mspace id="mspace2" width="75px" height="25px" depth="50px" style="background: green"/>
+ </math>
+ </p>
+ <div>
+ <div id="containerForPreferredWidth" class="shrink-wrap">
+ <math><mspace width="75px" height="25px" depth="50px" style="background: green"/></math>
+ </div>
+ </div>
+ <p>
+ <span id="baseline2" style="display: inline-block; width: 30px; height: 5px; background: blue"></span>
+ <math>
+ <mspace id="dynamic-attach" style="background: lightgreen"/>
+ <mspace id="dynamic-remove" width="10px" height="20px" depth="30px" style="background: lightyellow"/>
+ <mspace id="dynamic-modify" width="100px" height="200px" depth="300px" style="background: pink"/>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/spaces/space-2-ref.html b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-2-ref.html
new file mode 100644
index 0000000000..5a8b39e189
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-2-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>space (reference)</title>
+</head>
+<body>
+ <p>Test passes if you see a green square and no red.</p>
+ <div style="position: relative;">
+ <div style="position: absolute; top: 0px; left: 0px;
+ background: green; width: 200px; height: 200px;">
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/spaces/space-2.html b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-2.html
new file mode 100644
index 0000000000..640afb204f
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-2.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>space</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#space-mspace">
+<link rel="match" href="space-2-ref.html"/>
+<meta name="assert" content="Verify mspace visual rendering for different values of height, depth and width">
+</head>
+<body>
+ <p>Test passes if you see a green square and no red.</p>
+ <div style="position: relative;">
+ <!-- Some green and red mspaces to draw a square -->
+ <div style="position: absolute; top: 0px; left: 0px;
+ width: 200px; height: 200px;">
+ <math style="position: absolute; top: 0px; left: 0px">
+ <mspace width="50px" height="100px" depth="100px" style="background: green"/>
+ <mspace width="50px" height="100px" depth="100px" style="background: green"/>
+ <mspace width="25px" depth="100px" style="background: green"/>
+ <mspace width="25px" depth="100px" style="background: green"/>
+ <mspace width="25px" height="100px" style="background: green"/>
+ <mspace width="25px" height="100px" style="background: green"/>
+ </math>
+ <math style="position: absolute; top: 0px; left: 0px">
+ <mspace width="100px" height="20px" depth="20px" style="background: red"/>
+ <mspace width="50px" height="100px" style="background: red"/>
+ <mspace width="50px" depth="100px" style="background: red"/>
+ </math>
+ </div>
+ <!-- These green divs should cover the red mspace elements -->
+ <div style="position: absolute; top: 0px; left: 0px;
+ width: 200px; height: 200px;">
+ <div style="position: absolute; top: 80px; left: 0px;
+ width: 100px; height: 40px; background: green"></div>
+ <div style="position: absolute; top: 0px; left: 100px;
+ width: 50px; height: 100px; background: green"></div>
+ <div style="position: absolute; top: 100px; left: 150px;
+ width: 50px; height: 100px; background: green"></div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/spaces/space-like-001.html b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-like-001.html
new file mode 100644
index 0000000000..60e81095ad
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-like-001.html
@@ -0,0 +1,340 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Space-like elements</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#definition-of-space-like-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-mrow">
+<meta name="assert" content="Verify definition of space-like elements">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<style>
+ /* Default spacing of operator 'X' is 0.2777777777777778em so quite different
+ from the measured/specified 0em and 1em. */
+ math, math * {
+ font: 25px/1 Ahem;
+ }
+ mn {
+ color: black;
+ }
+ mo {
+ color: yellow;
+ }
+ .testedElement, .testedElement * {
+ color: blue !important;
+ background: blue !important;
+ }
+</style>
+<script>
+ function spaceBefore(id) {
+ var element = document.getElementById(id);
+ var mnBeforeParent = element.parentNode.previousElementSibling;
+ return element.getBoundingClientRect().left - mnBeforeParent.getBoundingClientRect().right;
+ }
+
+ function spaceAfter(id) {
+ var element = document.getElementById(id);
+ var mnAfterParent = element.parentNode.nextElementSibling;
+ return mnAfterParent.getBoundingClientRect().left - element.getBoundingClientRect().right;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+ var epsilon = 1;
+ var emToPx = 25;
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("mtext"), emToPx, epsilon);
+ assert_approx_equals(spaceAfter("mtext"), emToPx, epsilon);
+ }, "mtext is space-like");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("mspace"), emToPx, epsilon);
+ assert_approx_equals(spaceAfter("mspace"), emToPx, epsilon);
+ }, "mspace is space-like");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("mrow1"), emToPx, epsilon);
+ assert_approx_equals(spaceAfter("mrow1"), emToPx, epsilon);
+ }, "space-like mrow");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("mrow2"), 0, epsilon);
+ assert_approx_equals(spaceAfter("mrow2"), 2 * emToPx, epsilon);
+ }, "non-space-like mrow");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("mstyle1"), emToPx, epsilon);
+ assert_approx_equals(spaceAfter("mstyle1"), emToPx, epsilon);
+ }, "space-like mstyle");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("mstyle2"), 0, epsilon);
+ assert_approx_equals(spaceAfter("mstyle2"), 2 * emToPx, epsilon);
+ }, "non-space-like mstyle");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("mphantom1"), emToPx, epsilon);
+ assert_approx_equals(spaceAfter("mphantom1"), emToPx, epsilon);
+ }, "space-like mphantom");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("mphantom2"), 0, epsilon);
+ assert_approx_equals(spaceAfter("mphantom2"), 2 * emToPx, epsilon);
+ }, "non-space-like mphantom");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("mpadded1"), emToPx, epsilon);
+ assert_approx_equals(spaceAfter("mpadded1"), emToPx, epsilon);
+ }, "space-like mpadded");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("mpadded2"), 0, epsilon);
+ assert_approx_equals(spaceAfter("mpadded2"), 2 * emToPx, epsilon);
+ }, "non-space-like mpadded");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("merror1"), emToPx, epsilon);
+ assert_approx_equals(spaceAfter("merror1"), emToPx, epsilon);
+ }, "space-like merror");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("merror2"), 0, epsilon);
+ assert_approx_equals(spaceAfter("merror2"), 2 * emToPx, epsilon);
+ }, "non-space-like merror");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("menclose1"), emToPx, epsilon);
+ assert_approx_equals(spaceAfter("menclose1"), emToPx, epsilon);
+ }, "space-like menclose");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("menclose2"), 0, epsilon);
+ assert_approx_equals(spaceAfter("menclose2"), 2 * emToPx, epsilon);
+ }, "non-space-like menclose");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- mtext is space-like. -->
+ <mtext class="testedElement" id="mtext">X</mtext>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- mspace is space-like. -->
+ <mspace class="testedElement" id="mspace" width="25px" height="10px"></mspace>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- mrow is space-like when it contains only space-like elements. -->
+ <mrow id="mrow1" class="testedElement">
+ <mtext>X</mtext>
+ <mspace width="25px" height="10px"></mspace>
+ </mrow>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- mrow is not space-like when it contains a non space-like element
+ such as "mn". -->
+ <mrow id="mrow2" class="testedElement">
+ <mn>X</mn>
+ <mspace width="25px" height="10px"></mspace>
+ </mrow>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- mstyle is space-like when it contains only space-like elements. -->
+ <mstyle id="mstyle1" class="testedElement">
+ <mtext>X</mtext>
+ <mspace width="25px" height="10px"></mspace>
+ </mstyle>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- mstyle is not space-like when it contains a non space-like element
+ such as "mn". -->
+ <mstyle id="mstyle2" class="testedElement">
+ <mn>X</mn>
+ <mspace width="25px" height="10px"></mspace>
+ </mstyle>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- mphantom is space-like when it contains only space-like elements.
+ -->
+ <mphantom id="mphantom1" class="testedElement">
+ <mtext>X</mtext>
+ <mspace width="25px" height="10px"></mspace>
+ </mphantom>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- mphantom is not space-like when it contains a non space-like
+ element such as "mn". -->
+ <mphantom id="mphantom2" class="testedElement">
+ <mn>X</mn>
+ <mspace width="25px" height="10px"></mspace>
+ </mphantom>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- mpadded is space-like when it contains only space-like elements. -->
+ <mpadded id="mpadded1" class="testedElement">
+ <mtext>X</mtext>
+ <mspace width="25px" height="10px"></mspace>
+ </mpadded>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- mpadded is not space-like when it contains a non space-like element
+ such as "mn". -->
+ <mpadded id="mpadded2" class="testedElement">
+ <mn>X</mn>
+ <mspace width="25px" height="10px"></mspace>
+ </mpadded>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- merror is space-like when it contains only space-like elements. -->
+ <merror id="merror1" class="testedElement">
+ <mtext>X</mtext>
+ <mspace width="25px" height="10px"></mspace>
+ </merror>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- merror is not space-like when it contains a non space-like element
+ such as "mn". -->
+ <merror id="merror2" class="testedElement">
+ <mn>X</mn>
+ <mspace width="25px" height="10px"></mspace>
+ </merror>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- menclose is space-like when it contains only space-like
+ elements. -->
+ <menclose id="menclose1" class="testedElement">
+ <mtext>X</mtext>
+ <mspace width="25px" height="10px"></mspace>
+ </menclose>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- menclose is not space-like when it contains a non space-like
+ element such as "mn". -->
+ <menclose id="menclose2" class="testedElement">
+ <mn>X</mn>
+ <mspace width="25px" height="10px"></mspace>
+ </menclose>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/spaces/space-like-002.html b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-like-002.html
new file mode 100644
index 0000000000..fba92adf23
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-like-002.html
@@ -0,0 +1,174 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Space-like elements</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#definition-of-space-like-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-mrow">
+<meta name="assert" content="Verify definition of space-like elements">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<style>
+ /* Default spacing of operator 'X' is 0.2777777777777778em so quite different
+ from the measured/specified 0em and 1em. */
+ math, math * {
+ font: 25px/1 Ahem;
+ }
+ mn {
+ color: black;
+ }
+ mo {
+ color: yellow;
+ }
+ .testedElement, .testedElement * {
+ color: blue !important;
+ background: blue !important;
+ }
+</style>
+<script>
+ function spaceBefore(id) {
+ var element = document.getElementById(id);
+ var mnBeforeParent = element.parentNode.previousElementSibling;
+ return element.getBoundingClientRect().left - mnBeforeParent.getBoundingClientRect().right;
+ }
+
+ function spaceAfter(id) {
+ var element = document.getElementById(id);
+ var mnAfterParent = element.parentNode.nextElementSibling;
+ return mnAfterParent.getBoundingClientRect().left - element.getBoundingClientRect().right;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+ var epsilon = 1;
+ var emToPx = 25;
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("maction1"), emToPx, epsilon);
+ assert_approx_equals(spaceAfter("maction1"), emToPx, epsilon);
+ }, "space-like maction");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("maction2"), emToPx, epsilon);
+ assert_approx_equals(spaceAfter("maction2"), emToPx, epsilon);
+ }, "space-like maction (no first child)");
+
+ test(function() {
+ assert_approx_equals(spaceBefore("maction3"), 0, epsilon);
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceAfter("maction3"), 2 * emToPx, epsilon);
+ }, "non-space like maction (first child not space-like)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("semantics1"), emToPx, epsilon);
+ assert_approx_equals(spaceAfter("semantics1"), emToPx, epsilon);
+ }, "space-like semantics");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("semantics2"), emToPx, epsilon);
+ assert_approx_equals(spaceAfter("semantics2"), emToPx, epsilon);
+ }, "space-like semantics (no first child)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("semantics3"), 0, epsilon);
+ assert_approx_equals(spaceAfter("semantics3"), 2 * emToPx, epsilon);
+ }, "non-space like semantics (first child not space-like)");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- maction is space-like when its first child exists and is space-like -->
+ <maction id="maction1" class="testedElement" actiontype="statusline">
+ <mtext>X</mtext>
+ <mtext>STATUS MESSAGE</mtext>
+ </maction>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- maction is not space-like when its first does not exist-like -->
+ <maction id="maction2" class="testedElement" actiontype="statusline">
+ </maction>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- maction is not space-like when its first is not space-like -->
+ <maction id="maction3" class="testedElement" actiontype="statusline">
+ <mn>1</mn>
+ <mtext>STATUS MESSAGE</mtext>
+ </maction>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- semantics is space-like when its first child exists and is space-like -->
+ <semantics id="semantics1" class="testedElement" actiontype="statusline">
+ <mtext>X</mtext>
+ <annotation>TEXT ANNOTATION</annotation>
+ </semantics>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- semantics is not space-like when its first does not exist-like -->
+ <semantics id="semantics2" class="testedElement" actiontype="statusline">
+ </semantics>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- semantics is not space-like when its first is not space-like -->
+ <semantics id="semantics3" class="testedElement" actiontype="statusline">
+ <mn>1</mn>
+ <annotation>TEXT ANNOTATION</annotation>
+ </semantics>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/spaces/space-like-003.html b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-like-003.html
new file mode 100644
index 0000000000..5b693fb3c9
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-like-003.html
@@ -0,0 +1,252 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Non space-like elements</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#definition-of-space-like-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-mrow">
+<meta name="assert" content="Verify definition of space-like elements">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<style>
+ /* Default spacing of operator 'X' is 0.2777777777777778em so quite different
+ from the measured/specified 0em and 1em. */
+ math, math * {
+ font: 25px/1 Ahem;
+ }
+ mn {
+ color: black;
+ }
+ mo {
+ color: yellow;
+ }
+ .testedElement, .testedElement * {
+ color: blue !important;
+ background: blue !important;
+ }
+</style>
+<script>
+ function spaceBefore(element) {
+ var mnBeforeParent = element.parentNode.previousElementSibling;
+ return element.getBoundingClientRect().left - mnBeforeParent.getBoundingClientRect().right;
+ }
+
+ function spaceAfter(element) {
+ var mnAfterParent = element.parentNode.nextElementSibling;
+ return mnAfterParent.getBoundingClientRect().left - element.getBoundingClientRect().right;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+ var epsilon = 1;
+ var emToPx = 25;
+
+ Array.from(document.querySelectorAll(".testedElement")).forEach(el => {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore(el), 0, epsilon);
+ assert_approx_equals(spaceAfter(el), 2 * emToPx, epsilon);
+ }, `${el.tagName} is not space-like`);
+ });
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <mroot class="testedElement">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mroot>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <mfrac class="testedElement">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mfrac>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <mi class="testedElement">X</mi>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <mmultiscripts class="testedElement">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mmultiscripts>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <mn class="testedElement">X</mn>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <mo class="testedElement" lspace="0" rspace="0">X</mo>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <mover class="testedElement">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mover>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <munder class="testedElement">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </munder>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <ms class="testedElement">X</ms>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <munderover class="testedElement">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </munderover>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <msup class="testedElement">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </msup>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <msub class="testedElement">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </msub>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <msubsup class="testedElement">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </msubsup>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <msqrt class="testedElement">
+ <mtext>X</mtext>
+ </msqrt>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <mtable class="testedElement">
+ <mtr>
+ <mtd>
+ <mtext>X</mtext>
+ </mtd>
+ </mtr>
+ </mtable>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/spaces/space-like-004.html b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-like-004.html
new file mode 100644
index 0000000000..1e8cfaaaca
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-like-004.html
@@ -0,0 +1,446 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Space-like elements</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#definition-of-space-like-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-mrow">
+<meta name="assert" content="Verify definition of space-like elements">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/box-navigation.js"></script>
+<style>
+ /* Default spacing of operator 'X' is 0.2777777777777778em so quite different
+ from the measured/specified 0em and 1em. */
+ math, math * {
+ font: 25px/1 Ahem;
+ }
+ mn {
+ color: black;
+ }
+ mo {
+ color: yellow;
+ }
+ .testedElement, .testedElement * {
+ color: blue !important;
+ background: blue !important;
+ }
+ .oof1 {
+ position: absolute;
+ }
+ .oof2 {
+ position: fixed;
+ }
+ .nobox {
+ display: none;
+ }
+</style>
+<script>
+ function spaceBefore(id) {
+ var element = document.getElementById(id);
+ var mnBeforeParent = previousInFlowSibling(element.parentNode);
+ return element.getBoundingClientRect().left - mnBeforeParent.getBoundingClientRect().right;
+ }
+
+ function spaceAfter(id) {
+ var element = document.getElementById(id);
+ var mnAfterParent = nextInFlowSibling(element.parentNode);
+ return mnAfterParent.getBoundingClientRect().left - element.getBoundingClientRect().right;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+ var epsilon = 1;
+ var emToPx = 25;
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("complex1"), emToPx, epsilon);
+ assert_approx_equals(spaceAfter("complex1"), emToPx, epsilon);
+ }, "complex space-like subtree");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("complex1-bis"), emToPx, epsilon);
+ assert_approx_equals(spaceAfter("complex1-bis"), emToPx, epsilon);
+ }, "complex space-like subtree, from in-flow children");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("complex2"), 0, epsilon);
+ assert_approx_equals(spaceAfter("complex2"), 2 * emToPx, epsilon);
+ }, "complex non-space-like subtree");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_operator_spacing());
+ assert_approx_equals(spaceBefore("complex2-bis"), 0, epsilon);
+ assert_approx_equals(spaceAfter("complex2-bis"), 2 * emToPx, epsilon);
+ }, "complex non-space-like subtree, from in-flow children");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- This element is space-like because it is made of nested
+ mrow, mstyle, mpadded, mphantom, mtext, mspace
+ -->
+ <mrow class="testedElement" id="complex1">
+ <mtext>X</mtext>
+ <mstyle>
+ <mstyle>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mstyle>
+ <mtext>X</mtext>
+ <mspace width="25px"></mspace>
+ <mpadded>
+ <mtext>X</mtext>
+ <mrow></mrow>
+ <mtext>X</mtext>
+ <mspace width="25px"></mspace>
+ <mphantom>
+ <mtext>X</mtext>
+ <mspace width="25px"></mspace>
+ </mphantom>
+ <mrow>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mrow>
+ <mspace width="25px"></mspace>
+ </mpadded>
+ <mspace width="25px"></mspace>
+ <mtext>X</mtext>
+ <mspace width="25px"></mspace>
+ <mpadded>
+ <mphantom>
+ <mtext>X</mtext>
+ <mspace width="25px"></mspace>
+ </mphantom>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mspace width="25px"></mspace>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mspace width="25px"></mspace>
+ <mphantom>
+ <mtext>X</mtext>
+ <mspace width="25px"></mspace>
+ </mphantom>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mspace width="25px"></mspace>
+ </mpadded>
+ </mstyle>
+ <mspace width="25px"></mspace>
+ </mrow>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mrow>
+ <!-- This element is space-like because it is made of nested
+ mrow, mstyle, mpadded, mphantom, mtext, mspace
+ -->
+ <mrow class="testedElement" id="complex1-bis">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mstyle>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mstyle>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mstyle>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mpadded>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mrow></mrow>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mphantom>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mphantom>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mrow>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mrow>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mpadded>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mpadded>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mphantom>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mphantom>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mphantom>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mphantom>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mpadded>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mstyle>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mrow>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="1em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mrow>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn>X</mn>
+ <mrow>
+ <!-- This element is not space-like. It is made of nested
+ mrow, mstyle, mpadded, mphantom, mtext, mspace but contains
+ one non-space like descendant (an mn element).
+ -->
+ <mrow class="testedElement" id="complex2">
+ <mtext>X</mtext>
+ <mstyle>
+ <mstyle>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mstyle>
+ <mtext>X</mtext>
+ <mspace width="25px"></mspace>
+ <mpadded>
+ <mtext>X</mtext>
+ <mrow></mrow>
+ <mtext>X</mtext>
+ <mspace width="25px"></mspace>
+ <mphantom>
+ <mtext>X</mtext>
+ <mspace width="25px"></mspace>
+ </mphantom>
+ <mrow>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mrow>
+ <mspace width="25px"></mspace>
+ </mpadded>
+ <mspace width="25px"></mspace>
+ <mtext>X</mtext>
+ <mspace width="25px"></mspace>
+ <mpadded>
+ <mphantom>
+ <mn>X</mn> <!-- mn is not space-like -->
+ <mspace width="25px"></mspace>
+ </mphantom>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mspace width="25px"></mspace>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mspace width="25px"></mspace>
+ <mphantom>
+ <mtext>X</mtext>
+ <mspace width="25px"></mspace>
+ </mphantom>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mspace width="25px"></mspace>
+ </mpadded>
+ </mstyle>
+ <mspace width="25px"></mspace>
+ </mrow>
+ <mo lspace="1em" rspace="0em">X</mo>
+ </mrow>
+ <mn>X</mn>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mrow>
+ <!-- This element is not space-like. It is made of nested
+ mrow, mstyle, mpadded, mphantom, mtext, mspace but contains
+ one non-space like descendant (an mn element).
+ -->
+ <mrow class="testedElement" id="complex2-bis">
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mstyle>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mstyle>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mstyle>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mpadded>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mrow></mrow>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mphantom>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mphantom>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mrow>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mrow>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mpadded>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mpadded>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mphantom>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn> <!-- mn is not space-like -->
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mphantom>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mphantom>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mphantom>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mtext>X</mtext>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mpadded>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mstyle>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mspace width="25px"></mspace>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mrow>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mo lspace="1em" rspace="0em">X</mo>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </mrow>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ <mn>X</mn>
+ <mn class="oof1">0</mn><mn class="oof2">1</mn><mn class="nobox">2</mn>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/spaces/space-vertical-align.tentative-ref.html b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-vertical-align.tentative-ref.html
new file mode 100644
index 0000000000..ed30edde96
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-vertical-align.tentative-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>space and vertical-align (reference)</title>
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="position: relative;">
+ <div style="position: absolute; top: 0px; left: 0px;
+ background: green; width: 100px; height: 100px;">
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/spaces/space-vertical-align.tentative.html b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-vertical-align.tentative.html
new file mode 100644
index 0000000000..359b12aa34
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/spaces/space-vertical-align.tentative.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>space and vertical-align</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#space-mspace">
+<link rel="match" href="space-vertical-align.tentative-ref.html"/>
+<meta name="assert" content="Verify that vertical-align property has no effect on mspace">
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="position: relative;">
+ <div style="position: absolute; top: 0px; left: 0px;
+ width: 200px; height: 200px;">
+ <math style="position: absolute; top: 0px; left: 0px">
+ <mspace width="50px" height="100px" style="background: green;vertical-align:50px"/>
+ <mspace width="50px" height="100px" style="background: green;vertical-align:50%"/>
+ </math>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/tables/dynamic-table-001.html b/testing/web-platform/tests/mathml/presentation-markup/tables/dynamic-table-001.html
new file mode 100644
index 0000000000..a07ef94d27
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/tables/dynamic-table-001.html
@@ -0,0 +1,301 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Dynamic tabular elements</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/mathml/support/mathml-fragments.js"></script>
+<link rel="help" href="https://w3c.github.io/mathml-core/#table-or-matrix-mtable">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript">
+<meta name="assert" content="Dynamically modify DOM tree of mtables">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/layout-comparison.js"></script>
+<script>
+ function forceCells(mtable, rows, cols) {
+ while (mtable.children.length > rows)
+ mtable.removeChild(mtable.lastElementChild);
+ while (mtable.children.length < rows)
+ mtable.appendChild(FragmentHelper.createElement("mtr"));
+ for (let i = 0; i < rows; i++) {
+ let mtr = mtable.children[i];
+ while (mtr.children.length > cols)
+ mtr.removeChild(mtr.lastElementChild);
+ while (mtr.children.length < cols)
+ mtr.appendChild(FragmentHelper.createElement("mtd"));
+
+ for (let j = 0; j < cols; j++) {
+ let mtd = mtr.children[j];
+ while (mtd.children.length > 0)
+ mtd.removeChild(mtd.lastElementChild);
+ let mspace = FragmentHelper.createElement("mspace");
+ mspace.setAttribute("height", `${10*(i+1)}px`);
+ mspace.setAttribute("width", `${10*(j+1)}px`);
+ mspace.setAttribute("style", `background: black;`);
+ mtd.appendChild(mspace);
+ }
+ }
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", function() {
+ // force initial layout so we're sure what we're testing against
+ document.documentElement.getBoundingClientRect();
+
+ let reference = document.getElementById("reference");
+
+ Array.from(document.querySelectorAll("[data-title]")).forEach(mtable => {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ forceCells(mtable, 4, 3);
+ const epsilon = 1;
+ compareLayout(mtable, reference, epsilon);
+ }, `${mtable.getAttribute("data-title")}`);
+ });
+ done();
+ });
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mtable id="reference">
+ <mtr>
+ <mtd><mspace height="10px" width="10px" style="background: blue;"/></mtd>
+ <mtd><mspace height="10px" width="20px" style="background: blue;"/></mtd>
+ <mtd><mspace height="10px" width="30px" style="background: blue;"/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="20px" width="10px" style="background: blue;"/></mtd>
+ <mtd><mspace height="20px" width="20px" style="background: blue;"/></mtd>
+ <mtd><mspace height="20px" width="30px" style="background: blue;"/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="30px" width="10px" style="background: blue;"/></mtd>
+ <mtd><mspace height="30px" width="20px" style="background: blue;"/></mtd>
+ <mtd><mspace height="30px" width="30px" style="background: blue;"/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="40px" width="10px" style="background: blue;"/></mtd>
+ <mtd><mspace height="40px" width="20px" style="background: blue;"/></mtd>
+ <mtd><mspace height="40px" width="30px" style="background: blue;"/></mtd>
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtable data-title="Filling an empty mtable element"></mtable>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtable data-title="Filling empty mtr elements">
+ <mtr></mtr>
+ <mtr></mtr>
+ <mtr></mtr>
+ <mtr></mtr>
+ </mtable>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtable data-title="Filling empty mtd elements">
+ <mtr>
+ <mtd></mtd>
+ <mtd></mtd>
+ <mtd></mtd>
+ </mtr>
+ <mtr>
+ <mtd></mtd>
+ <mtd></mtd>
+ <mtd></mtd>
+ </mtr>
+ <mtr>
+ <mtd></mtd>
+ <mtd></mtd>
+ <mtd></mtd>
+ </mtr>
+ <mtr>
+ <mtd></mtd>
+ <mtd></mtd>
+ <mtd></mtd>
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtable data-title="Filling an empty mtr element">
+ <mtr>
+ <mtd><mspace height="10px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="10px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="10px" width="30px" style="background: black;"/></mtd>
+ </mtr>
+ <mtr>
+ <!-- Empty mtr -->
+ </mtr>
+ <mtr>
+ <mtd><mspace height="30px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="30px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="30px" width="30px" style="background: black;"/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="40px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="40px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="40px" width="30px" style="background: black;"/></mtd>
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtable data-title="Filling an empty mtd element">
+ <mtr>
+ <mtd><mspace height="10px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="10px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="10px" width="30px" style="background: black;"/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="20px" width="10px" style="background: black;"/></mtd>
+ <mtd><!-- Empty --></mtd>
+ <mtd><mspace height="20px" width="30px" style="background: black;"/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="30px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="30px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="30px" width="30px" style="background: black;"/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="40px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="40px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="40px" width="30px" style="background: black;"/></mtd>
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtable data-title="Adding missing elements">
+ <mtr>
+ <mtd><mspace height="10px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="10px" width="20px" style="background: black;"/></mtd>
+ <!-- Cell missing -->
+ </mtr>
+ <mtr>
+ <mtd><mspace height="20px" width="10px" style="background: black;"/></mtd>
+ <mtd><!-- Empty --></mtd>
+ <mtd><mspace height="20px" width="30px" style="background: black;"/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="30px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="30px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="30px" width="30px" style="background: black;"/></mtd>
+ </mtr>
+ <!-- Row missing -->
+ </mtable>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtable data-title="Removing a row">
+ <mtr>
+ <mtd><mspace height="10px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="10px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="10px" width="30px" style="background: black;"/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="20px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="20px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="20px" width="30px" style="background: black;"/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="30px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="30px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="30px" width="30px" style="background: black;"/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="40px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="40px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="40px" width="30px" style="background: black;"/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="50px" width="10px" style="background: red;"/></mtd>
+ <mtd><mspace height="50px" width="20px" style="background: red;"/></mtd>
+ <mtd><mspace height="50px" width="30px" style="background: red;"/></mtd>
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtable data-title="Removing a column">
+ <mtr>
+ <mtd><mspace height="10px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="10px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="10px" width="30px" style="background: black;"/></mtd>
+ <mtd><mspace height="10px" width="40px" style="background: red;"/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="20px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="20px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="20px" width="30px" style="background: black;"/></mtd>
+ <mtd><mspace height="20px" width="40px" style="background: red;"/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="30px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="30px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="30px" width="30px" style="background: black;"/></mtd>
+ <mtd><mspace height="30px" width="40px" style="background: red;"/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="40px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="40px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="40px" width="30px" style="background: black;"/></mtd>
+ <mtd><mspace height="40px" width="40px" style="background: red;"/></mtd>
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtable data-title="Removing extra elements">
+ <mtr>
+ <mtd><mspace height="10px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="10px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="10px" width="30px" style="background: black;"/></mtd>
+ <mtd><mspace height="10px" width="40px" style="background: black;"/></mtd>
+ <mtd><mspace height="10px" width="50px" style="background: red;"/></mtd><!-- extra mtd -->
+ </mtr>
+ <mtr>
+ <mtd><mspace height="20px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="20px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="20px" width="30px" style="background: black;"/></mtd>
+ <mtd><mspace height="20px" width="40px" style="background: black;"/><mspace height="20px" width="40px" style="background: red;"/><!-- extra child--></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="30px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="30px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="30px" width="30px" style="background: black;"/></mtd>
+ <mtd><mspace height="30px" width="40px" style="background: black;"/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="40px" width="10px" style="background: black;"/></mtd>
+ <mtd><mspace height="40px" width="20px" style="background: black;"/></mtd>
+ <mtd><mspace height="40px" width="30px" style="background: black;"/></mtd>
+ <mtd><mspace height="40px" width="40px" style="background: black;"/></mtd>
+ </mtr>
+ <mtr>
+ <mtd><mspace height="50px" width="10px" style="background: red;"/></mtd>
+ <mtd><mspace height="50px" width="20px" style="background: red;"/></mtd>
+ <mtd><mspace height="50px" width="30px" style="background: red;"/></mtd>
+ <mtd><mspace height="50px" width="40px" style="background: red;"/></mtd>
+ </mtr> <!-- extra row -->
+ </mtable>
+ </math>
+ </p>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/tables/table-001.html b/testing/web-platform/tests/mathml/presentation-markup/tables/table-001.html
new file mode 100644
index 0000000000..91e99184df
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/tables/table-001.html
@@ -0,0 +1,286 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Basic table layout</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#table-or-matrix-mtable">
+<meta name="assert" content="Verify position of cells in basic 2x2, 4x3 and 3x4 math tables.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+ function runTests() {
+ Array.from(document.getElementsByTagName("mtable")).forEach(table => {
+ const id = table.getAttribute("id");
+ const rtl = window.getComputedStyle(table).direction === "rtl";
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ const rows = Array.from(table.getElementsByTagName("mtr"));
+ for (var j = 0; j < rows.length; j++) {
+ var cells = Array.from(rows[j].getElementsByTagName("mtd"));
+ for (var i = 0; i < cells.length - 1; i++) {
+ var space1 = cells[i].firstElementChild.getBoundingClientRect();
+ var space2 = cells[i + 1].firstElementChild.getBoundingClientRect();
+ assert_equals(space1.top, space2.top,
+ `Cells (${i},${j}) and (${i + 1},${j}) should have same vertical position`);
+ if (rtl) {
+ assert_greater_than(space1.left, space2.right,
+ `Cell (${i},${j}) should be on the right of (${i + 1},${j})`);
+ } else {
+ assert_less_than(space1.right, space2.left,
+ `Cell (${i},${j}) should be on the left of (${i + 1},${j})`);
+ }
+ }
+ }
+
+ for (var j = 0; j < rows.length - 1; j++) {
+ var cells1 = Array.from(rows[j].getElementsByTagName("mtd"));
+ var cells2 = Array.from(rows[j + 1].getElementsByTagName("mtd"));
+ for (var i = 0; i < cells1.length; i++) {
+ var space1 = cells1[i].firstElementChild.getBoundingClientRect();
+ var space2 = cells2[i].firstElementChild.getBoundingClientRect();
+ assert_equals(space1.left, space2.left,
+ `Cells (${i},${j}) and (${i},${j + 1}) should have same horizontal position`);
+ assert_less_than(space1.bottom, space2.top,
+ `Cell (${i},${j}) should be above (${i},${j + 1})`);
+ }
+ }
+ }, `Layout of ${id}`);
+
+ });
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mtable id="table-001">
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: lightblue;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: lightgreen;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: blue;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: green;"></mspace>
+ </mtd>
+ </mtr>
+ </mtable>
+ <mtable id="table-002">
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: lightblue;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: lightgreen;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: cyan;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: purple;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: blue;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: green;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: yellow;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: orange;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: black;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: red;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: gray;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: maroon;"></mspace>
+ </mtd>
+ </mtr>
+ </mtable>
+ <mtable id="table-003">
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: lightblue;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: lightgreen;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: cyan;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: blue;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: green;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: orange;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: black;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: maroon;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: gray;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: red;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: purple;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: yellow;"></mspace>
+ </mtd>
+
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+ <p>
+ <math dir="rtl">
+ <mtable id="table-011">
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: lightblue;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: lightgreen;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: blue;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: green;"></mspace>
+ </mtd>
+ </mtr>
+ </mtable>
+ <mtable id="table-012">
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: lightblue;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: lightgreen;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: cyan;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: purple;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: blue;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: green;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: yellow;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: orange;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: black;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: red;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: gray;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: maroon;"></mspace>
+ </mtd>
+ </mtr>
+ </mtable>
+ <mtable id="table-013">
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: lightblue;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: lightgreen;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: cyan;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: blue;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: green;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: orange;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: black;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: maroon;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: gray;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: red;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: purple;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: yellow;"></mspace>
+ </mtd>
+
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/tables/table-002.html b/testing/web-platform/tests/mathml/presentation-markup/tables/table-002.html
new file mode 100644
index 0000000000..b1d75db0c0
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/tables/table-002.html
@@ -0,0 +1,146 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Basic table alignment</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#table-or-matrix-mtable">
+<meta name="assert" content="Verify alignment of cells with inline elements in basic 2x2, 4x3 and 3x4 math tables.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+ function runTests() {
+ var epsilon = 1;
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ const ascents = [40, 0, 20, 30, 10, 80, 0, 40, 70, 30];
+ const row = document.getElementById("vertical").firstElementChild;
+ const cells = Array.from(row.getElementsByTagName("mtd"));
+ for (var i = 0; i < cells.length - 1; i++) {
+ var space1 = cells[i].firstElementChild.getBoundingClientRect();
+ var space2 = cells[i + 1].firstElementChild.getBoundingClientRect();
+ assert_approx_equals(space1.top + ascents[i],
+ space2.top + ascents[i + 1],
+ epsilon,
+ `Baselines of cells ${i} and ${i + 1} should be aligned.`);
+ }
+ }, `Vertical alignment of cells`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ const table = document.getElementById("horizontal");
+ const rows = Array.from(table.getElementsByTagName("mtr"));
+ for (var j = 0; j < rows.length - 1; j++) {
+ var space1 = rows[j].firstElementChild.firstElementChild.getBoundingClientRect();
+ var space2 = rows[j + 1].firstElementChild.firstElementChild.getBoundingClientRect();
+ assert_approx_equals((space1.left + space1.right) / 2,
+ (space2.left + space2.right) / 2,
+ epsilon,
+ `Baselines of cells ${j} and ${j + 1} should be aligned.`);
+ }
+ }, `Horizontal alignment of cells`);
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mtable id="vertical">
+ <mtr>
+ <mtd>
+ <mspace width="10px" height="40px" depth="0px" style="background: lightblue;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="10px" height="0px" depth="40px" style="background: lightgreen;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="10px" height="20px" depth="20px" style="background: cyan;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="10px" height="30px" depth="10px" style="background: purple;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="10px" height="10px" depth="30px" style="background: orange;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="10px" height="80px" depth="0px" style="background: blue;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="10px" height="0px" depth="80px" style="background: green;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="10px" height="40px" depth="40px" style="background: yellow;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="10px" height="70px" depth="30px" style="background: red;"></mspace>
+ </mtd>
+ <mtd>
+ <mspace width="10px" height="30px" depth="70px" style="background: black;"></mspace>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtable id="horizontal">
+ <mtr>
+ <mtd>
+ <mspace width="10px" height="10px" style="background: lightblue;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="40px" height="10px" style="background: lightgreen;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="30px" height="10px" style="background: cyan;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="20px" height="10px" style="background: purple;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="50px" height="10px" style="background: orange;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="100px" height="10px" style="background: blue;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="90px" height="10px" style="background: green;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="70px" height="10px" style="background: yellow;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="80px" height="10px" style="background: red;"></mspace>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mspace width="40px" height="10px" style="background: black;"></mspace>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/tables/table-003.html b/testing/web-platform/tests/mathml/presentation-markup/tables/table-003.html
new file mode 100644
index 0000000000..323cb03c8a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/tables/table-003.html
@@ -0,0 +1,146 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Basic table alignment</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#table-or-matrix-mtable">
+<meta name="assert" content="Verify alignment of cells with block elements in basic 2x2, 4x3 and 3x4 math tables.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+ function runTests() {
+ var epsilon = 1;
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ const ascents = [40, 0, 20, 30, 10, 80, 0, 40, 70, 30];
+ const row = document.getElementById("vertical").firstElementChild;
+ const cells = Array.from(row.getElementsByTagName("mtd"));
+ for (var i = 0; i < cells.length - 1; i++) {
+ var space1 = cells[i].firstElementChild.firstElementChild.getBoundingClientRect();
+ var space2 = cells[i + 1].firstElementChild.firstElementChild.getBoundingClientRect();
+ assert_approx_equals(space1.top + ascents[i],
+ space2.top + ascents[i + 1],
+ epsilon,
+ `Baselines of cells ${i} and ${i + 1} should be aligned.`);
+ }
+ }, `Vertical alignment of cells`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ const table = document.getElementById("horizontal");
+ const rows = Array.from(table.getElementsByTagName("mtr"));
+ for (var j = 0; j < rows.length - 1; j++) {
+ var space1 = rows[j].firstElementChild.firstElementChild.firstElementChild.getBoundingClientRect();
+ var space2 = rows[j + 1].firstElementChild.firstElementChild.firstElementChild.getBoundingClientRect();
+ assert_approx_equals((space1.left + space1.right) / 2,
+ (space2.left + space2.right) / 2,
+ epsilon,
+ `Baselines of cells ${j} and ${j + 1} should be aligned.`);
+ }
+ }, `Horizontal alignment of cells`);
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mtable id="vertical">
+ <mtr>
+ <mtd>
+ <mrow><mspace width="10px" height="40px" depth="0px" style="background: lightblue;"></mspace></mrow>
+ </mtd>
+ <mtd>
+ <mrow><mspace width="10px" height="0px" depth="40px" style="background: lightgreen;"></mspace></mrow>
+ </mtd>
+ <mtd>
+ <mrow><mspace width="10px" height="20px" depth="20px" style="background: cyan;"></mspace></mrow>
+ </mtd>
+ <mtd>
+ <mrow><mspace width="10px" height="30px" depth="10px" style="background: purple;"></mspace></mrow>
+ </mtd>
+ <mtd>
+ <mrow><mspace width="10px" height="10px" depth="30px" style="background: orange;"></mspace></mrow>
+ </mtd>
+ <mtd>
+ <mrow><mspace width="10px" height="80px" depth="0px" style="background: blue;"></mspace></mrow>
+ </mtd>
+ <mtd>
+ <mrow><mspace width="10px" height="0px" depth="80px" style="background: green;"></mspace></mrow>
+ </mtd>
+ <mtd>
+ <mrow><mspace width="10px" height="40px" depth="40px" style="background: yellow;"></mspace></mrow>
+ </mtd>
+ <mtd>
+ <mrow><mspace width="10px" height="70px" depth="30px" style="background: red;"></mspace></mrow>
+ </mtd>
+ <mtd>
+ <mrow><mspace width="10px" height="30px" depth="70px" style="background: black;"></mspace></mrow>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtable id="horizontal">
+ <mtr>
+ <mtd>
+ <mrow><mspace width="10px" height="10px" style="background: lightblue;"></mspace></mrow>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mrow><mspace width="40px" height="10px" style="background: lightgreen;"></mspace></mrow>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mrow><mspace width="30px" height="10px" style="background: cyan;"></mspace></mrow>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mrow><mspace width="20px" height="10px" style="background: purple;"></mspace></mrow>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mrow><mspace width="50px" height="10px" style="background: orange;"></mspace></mrow>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mrow><mspace width="100px" height="10px" style="background: blue;"></mspace></mrow>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mrow><mspace width="90px" height="10px" style="background: green;"></mspace></mrow>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mrow><mspace width="70px" height="10px" style="background: yellow;"></mspace></mrow>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mrow><mspace width="80px" height="10px" style="background: red;"></mspace></mrow>
+ </mtd>
+ </mtr>
+ <mtr>
+ <mtd>
+ <mrow><mspace width="40px" height="10px" style="background: black;"></mspace></mrow>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/tables/table-axis-height.html b/testing/web-platform/tests/mathml/presentation-markup/tables/table-axis-height.html
new file mode 100644
index 0000000000..58f9d64c21
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/tables/table-axis-height.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>table axis height</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#table-or-matrix-mtable">
+<meta name="assert" content="Element mtable correctly uses the axis height parameter from the MATH table.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ math, mspace {
+ font-size: 10px;
+ }
+ @font-face {
+ font-family: axisheight5000-verticalarrow14000;
+ src: url("/fonts/math/axisheight5000-verticalarrow14000.woff");
+ }
+</style>
+<script>
+ var emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+ var epsilon = 1;
+
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+
+ var v1 = 5000 * emToPx;
+ var tableMiddle = (getBox("table").bottom + getBox("table").top) / 2;
+ assert_approx_equals(getBox("baseline").bottom - tableMiddle,
+ v1, epsilon, "mtable: axis height");
+ }, "AxisHeight");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math style="font-family: axisheight5000-verticalarrow14000">
+ <mspace id="baseline" style="background: green" width="50px" height="1px"/>
+ <mtable id="table" style="background: blue"><mtr><mtd><mspace width="100px" height="1px"/></mtd></mtr></mtable>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/tables/table-cell-mrow-layout.html b/testing/web-platform/tests/mathml/presentation-markup/tables/table-cell-mrow-layout.html
new file mode 100644
index 0000000000..1e76e3949a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/tables/table-cell-mrow-layout.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Table cell mrow layout</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#table-or-matrix-mtable">
+<meta name="assert" content="Table cell relies on the mrow layout for their children.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/layout-comparison.js"></script>
+<style>
+ /* Remove default padding, since there is none on reference mrow element. */
+ mtd { padding: 0; }
+</style>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mtable id="mtable">
+ <mtr>
+ <mtd id="mtd">
+ <mspace width="10px" depth="20px" height="20px" style="background: blue"/>
+ <mspace width="10px" depth="10px" height="30px" style="background: lightblue"/>
+ <mspace width="10px" depth="30px" height="10px" style="background: black"/>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow id="mtd-reference">
+ <mspace width="10px" depth="20px" height="20px" style="background: blue"/>
+ <mspace width="10px" depth="10px" height="30px" style="background: lightblue"/>
+ <mspace width="10px" depth="30px" height="10px" style="background: black"/>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtable id="mtable-reference">
+ <mtr>
+ <mtd>
+ <mrow>
+ <mspace width="10px" depth="20px" height="20px" style="background: blue"/>
+ <mspace width="10px" depth="10px" height="30px" style="background: lightblue"/>
+ <mspace width="10px" depth="30px" height="10px" style="background: black"/>
+ </mrow>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+ </p>
+ <script>
+ const epsilon = 1;
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ let mtd = document.getElementById("mtd");
+ let reference = document.getElementById("mtd-reference");
+ compareLayout(mtd, reference, epsilon);
+ }, "<mtd> relies on mrow algorithm to layout its children");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ let mtable = document.getElementById("mtable");
+ let reference = document.getElementById("mtable-reference");
+ compareLayout(mtable, reference, epsilon);
+ }, "<mtable> layout does not change if children of <mtd> elements are wrapped in an explicit <mrow>");
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/tables/table-default-styles-001.html b/testing/web-platform/tests/mathml/presentation-markup/tables/table-default-styles-001.html
new file mode 100644
index 0000000000..495cdc000a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/tables/table-default-styles-001.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Tabular math elements default styles</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://w3c.github.io/mathml-core/#tabular-math">
+<link rel="help" href="https://w3c.github.io/mathml-core/#user-agent-stylesheet">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<meta name="assert" content="Check default styles for mtable, mtr and mtd.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ math {
+ font: 25px/1 Ahem;
+ }
+</style>
+<div id="log"></div>
+<div>
+ <math>
+ <mrow id="reference"><mspace width="20px" height="10px" style="background: lightblue;"></mrow>
+ <mtable id="mtable"><mtr id="mtr"><mtd id="mtd"><mspace width="20px" height="10px" style="background: lightblue;"></mtd></mtr></mtable>
+ </math>
+</div>
+<script>
+ test(() => assert_equals(window.getComputedStyle(mtable).mathStyle, "compact"),
+ "Default math-style value on mtable");
+ test(() => assert_equals(window.getComputedStyle(mtable).display, "inline-table"),
+ "Default display value on mtable");
+ test(() => assert_equals(window.getComputedStyle(mtr).display, "table-row"),
+ "Default display value on mtr");
+ test(() => assert_equals(window.getComputedStyle(mtd).display, "table-cell"),
+ "Default display value on mtd");
+ test(() => assert_equals(window.getComputedStyle(mtd).textAlign, "center"),
+ "Default text-align value on mtd");
+ test(() => assert_equals(window.getComputedStyle(mtd).paddingLeft, "10px"),
+ "Default padding-left value on mtd");
+ test(() => assert_equals(window.getComputedStyle(mtd).paddingRight, "10px"),
+ "Default padding-right value on mtd");
+ test(() => assert_equals(window.getComputedStyle(mtd).paddingTop, "10px"),
+ "Default padding-top value on mtd");
+ test(() => assert_equals(window.getComputedStyle(mtd).paddingBottom, "10px"),
+ "Default padding-bottom value on mtd");
+
+ test(function () {
+ var mtableBox = document.getElementById("mtable").getBoundingClientRect();
+ var referenceBox = document.getElementById("reference").getBoundingClientRect();
+ assert_equals(mtableBox.width, referenceBox.width + 20);
+ assert_equals(mtableBox.height, referenceBox.height + 20);
+ }, "Bounding box is the same as mrow + mtd default padding");
+</script>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/tokens/dynamic-mtext-like-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/tokens/dynamic-mtext-like-001-ref.html
new file mode 100644
index 0000000000..a145a8eb51
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/tokens/dynamic-mtext-like-001-ref.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Dynamic mtext-like elements (reference)</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ math {
+ font: 25px/1 Ahem;
+ background: lightblue;
+ }
+ li {
+ padding: 2px;
+ }
+</style>
+</head>
+<body>
+ <ol>
+ <li><math><mtext class="testedElement">É</mtext></math></li>
+ <li><math><mtext class="testedElement">pX</mtext></math></li>
+ <li><math><mtext class="testedElement"><span>Xp</span></mtext></math></li>
+ <li><math><mi class="testedElement">É</mi></math></li>
+ <li><math><mi class="testedElement">pX</mi></math></li>
+ <li><math><mi class="testedElement"><span>Xp</span></mi></math></li>
+ <li><math><mn class="testedElement">É</mn></math></li>
+ <li><math><mn class="testedElement">pX</mn></math></li>
+ <li><math><mn class="testedElement"><span>Xp</span></mn></math></li>
+ <li><math><mo class="testedElement">É</mo></math></li>
+ <li><math><mo class="testedElement">pX</mo></math></li>
+ <li><math><mo class="testedElement"><span>Xp</span></mo></math></li>
+ <li><math><mo class="testedElement">É</mo></math></li>
+ <li><math><mo class="testedElement">pX</mo></math></li>
+ <li><math><mo class="testedElement"><span>Xp</span></mo></math></li>
+ <li><math><ms class="testedElement">É</ms></math></li>
+ <li><math><ms class="testedElement">pX</ms></math></li>
+ <li><math><ms class="testedElement"><span>Xp</span></ms></math></li>
+ <li><math><annotation class="testedElement">É</annotation></math></li>
+ <li><math><annotation class="testedElement">pX</annotation></math></li>
+ <li><math><annotation-xml class="testedElement">É</annotation-xml></math></li>
+ <li><math><annotation-xml class="testedElement">pX</annotation-xml></math></li>
+ </ol>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/tokens/dynamic-mtext-like-001.html b/testing/web-platform/tests/mathml/presentation-markup/tokens/dynamic-mtext-like-001.html
new file mode 100644
index 0000000000..8e42f7fa17
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/tokens/dynamic-mtext-like-001.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>Dynamic mtext-like elements</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<script src="/mathml/support/mathml-fragments.js"></script>
+<meta name="assert" content="Dynamically set children of mtext-like elements.">
+<style>
+ math {
+ font: 25px/1 Ahem;
+ background: lightblue;
+ }
+ li {
+ padding: 2px;
+ }
+</style>
+<link rel="match" href="dynamic-mtext-like-001-ref.html">
+<script>
+ window.addEventListener("load", function() {
+
+ // force initial layout so we're sure what we're testing against
+ document.documentElement.getBoundingClientRect();
+
+ Array.from(document.getElementsByClassName("testedElement")).forEach(e => {
+ if (e.textContent === "")
+ e.textContent = "É";
+ else if (e.textContent === "X")
+ e.textContent = "pX";
+ else if (e.textContent === "p") {
+ while (e.firstChild)
+ e.removeChild(e.firstChild);
+ e.insertAdjacentHTML("beforeend", "<span>Xp</span>")
+ }
+ });
+
+ document.documentElement.classList.remove('reftest-wait');
+ });
+</script>
+</head>
+<body>
+ <ol>
+ <li><math><mtext class="testedElement"></mtext></math></li>
+ <li><math><mtext class="testedElement">X</mtext></math></li>
+ <li><math><mtext class="testedElement">p</mtext></math></li>
+ <li><math><mi class="testedElement"></mi></math></li>
+ <li><math><mi class="testedElement">X</mi></math></li>
+ <li><math><mi class="testedElement">p</mi></math></li>
+ <li><math><mn class="testedElement"></mn></math></li>
+ <li><math><mn class="testedElement">X</mn></math></li>
+ <li><math><mn class="testedElement">p</mn></math></li>
+ <li><math><mo class="testedElement"></mo></math></li>
+ <li><math><mo class="testedElement">X</mo></math></li>
+ <li><math><mo class="testedElement">p</mo></math></li>
+ <li><math><mo class="testedElement"></mo></math></li>
+ <li><math><mo class="testedElement">X</mo></math></li>
+ <li><math><mo class="testedElement">p</mo></math></li>
+ <li><math><ms class="testedElement"></ms></math></li>
+ <li><math><ms class="testedElement">X</ms></math></li>
+ <li><math><ms class="testedElement">p</ms></math></li>
+ <!-- HTML parser does not accept span as a child of annotation or
+ annotation-xml, so we can't test dynamic VS static. -->
+ <li><math><annotation class="testedElement"></annotation></math></li>
+ <li><math><annotation class="testedElement">X</annotation></math></li>
+ <li><math><annotation-xml class="testedElement"></annotation-xml></math></li>
+ <li><math><annotation-xml class="testedElement">X</annotation-xml></math></li>
+ </ol>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/tokens/ms-001-ref.html b/testing/web-platform/tests/mathml/presentation-markup/tokens/ms-001-ref.html
new file mode 100644
index 0000000000..bbd42a93ee
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/tokens/ms-001-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>ms legacy lquote and rquote attributes (reference)</title>
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math {
+ font: 25px/1 Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <p>
+ <math>
+ <ms>X</ms>
+ </math>
+ </p>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/presentation-markup/tokens/ms-001.html b/testing/web-platform/tests/mathml/presentation-markup/tokens/ms-001.html
new file mode 100644
index 0000000000..abac0c8b2e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/presentation-markup/tokens/ms-001.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>ms legacy lquote and rquote attributes</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#string-literal-ms">
+ <meta name="assert" content="Verify that legacy lquote and rquote attributes are ignored on the ms element.">
+ <link rel="match" href="ms-001-ref.html">
+ <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+ <style>
+ math {
+ font: 25px/1 Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <p>
+ <math>
+ <ms lquote="É" rquote="p">X</ms>
+ </math>
+ </p>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_ms");</script>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/attribute-mapping-001.html b/testing/web-platform/tests/mathml/relations/css-styling/attribute-mapping-001.html
new file mode 100644
index 0000000000..e423b16fd7
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/attribute-mapping-001.html
@@ -0,0 +1,111 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Attribute mapping</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+<meta name="assert" content="Verify that dir, mathcolor, mathbackground and mathsize are mapped to CSS but that deprecated MathML3 attributes are not.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<style>
+ #container {
+ color: blue;
+ font-size: 50px;
+ }
+</style>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+ function runTests() {
+ var container = document.getElementById("container");
+ for (tag in MathMLFragments) {
+ container.insertAdjacentHTML("beforeend", `<math>${MathMLFragments[tag]}</math>`);
+ }
+ Array.from(document.getElementsByClassName("element")).forEach(element => {
+ var tag = element.tagName;
+ var style = window.getComputedStyle(element);
+
+ test(function() {
+ assert_equals(style.getPropertyValue("direction"), "ltr", "no attribute");
+ element.setAttribute("dir", "rtl");
+ assert_equals(style.getPropertyValue("direction"), "rtl", "attribute specified");
+ element.setAttribute("dir", "RtL");
+ assert_equals(style.getPropertyValue("direction"), "rtl", "case insensitive");
+ element.setAttribute("dir", "auto");
+ assert_equals(style.getPropertyValue("direction"), "ltr", "auto");
+ element.setAttribute("dir", "foo");
+ assert_equals(style.getPropertyValue("direction"), "ltr", "random value");
+ }, `dir on the ${tag} element is mapped to CSS direction`)
+
+ test(function() {
+ assert_equals(style.getPropertyValue("color"),
+ "rgb(0, 0, 255)",
+ "no attribute");
+ element.setAttribute("mathcolor", "black");
+ assert_equals(style.getPropertyValue("color"), "rgb(0, 0, 0)", "attribute specified");
+ // The color names are case-insensitive.
+ // See https://www.w3.org/TR/css-color-3/#html4
+ element.setAttribute("mathcolor", "GrEeN");
+ assert_equals(style.getPropertyValue("color"), "rgb(0, 128, 0)", "case insensitive");
+ }, `mathcolor on the ${tag} element is mapped to CSS color`);
+
+ test(function() {
+ assert_equals(style.getPropertyValue("background-color"),
+ tag === "merror" ?
+ "rgb(255, 255, 224)" : "rgba(0, 0, 0, 0)",
+ "no attribute");
+ element.setAttribute("mathbackground", "lightblue");
+ assert_equals(style.getPropertyValue("background-color"), "rgb(173, 216, 230)", "attribute specified");
+ // The color names are case-insensitive.
+ // See https://www.w3.org/TR/css-color-3/#html4
+ element.setAttribute("mathbackground", "YeLlOw");
+ assert_equals(style.getPropertyValue("background-color"), "rgb(255, 255, 0)", "case insensitive");
+ }, `mathbackground on the ${tag} element is mapped to CSS background-color`);
+
+ test(function() {
+ // "none" and "mprescripts" can only be used as non-first children of mmultiscripts so font-size
+ // is incremented and the resulting fraction string is hard to test accurately, skip for now.
+ if (tag === "none" || tag === "mprescripts")
+ return;
+ assert_equals(style.getPropertyValue("font-size"), "50px", "no attribute");
+ element.setAttribute("mathsize", "20px");
+ assert_equals(style.getPropertyValue("font-size"), "20px", "attribute specified");
+ // unit identifiers are ASCII case-insensitive.
+ // https://www.w3.org/TR/css-values-3/#typedef-dimension
+ element.setAttribute("mathsize", "30Px");
+ assert_equals(style.getPropertyValue("font-size"), "30px", "case insensitive");
+ }, `mathsize on the ${tag} element is mapped to CSS font-size`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mathsize(), "Superseding attributes are supported");
+ var properties = ["background-color", "color", "fontfamily", "font-size", "font-style", "font-weight"];
+ var oldStyle = {};
+ properties.forEach(property => {
+ oldStyle[property] = style.getPropertyValue(property);
+ });
+ element.setAttribute("background", "red");
+ element.setAttribute("color", "blue");
+ element.setAttribute("fontfamily", "monospace");
+ element.setAttribute("fontsize", "50px");
+ element.setAttribute("fontstyle", "italic");
+ element.setAttribute("fontweight", "bold");
+ properties.forEach(property => {
+ assert_equals(style.getPropertyValue(property), oldStyle[property], `${property}`);
+ });
+ }, `deprecated MathML3 attributes on the ${tag} element are not mapped to CSS`);
+ });
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <div id="container">
+ <math class="element"></math>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/attribute-mapping-002.html b/testing/web-platform/tests/mathml/relations/css-styling/attribute-mapping-002.html
new file mode 100644
index 0000000000..baf136f358
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/attribute-mapping-002.html
@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Attribute mapping</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-mathvariant-attribute">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-displaystyle-and-scriptlevel-attributes">
+<meta name="assert" content="Verify that mathvariant, scriptlevel, displaystyle are mapped to CSS">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+ #container {
+ /* Ahem font does not have a MATH table so the font-size scale factor
+ is always 0.71^{computed - inherited math script level} */
+ font: 100px/1 Ahem;
+ }
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+ function fontSize(style) {
+ return parseFloat((/(.+)px/).exec(style.getPropertyValue("font-size"))[1]);
+ }
+ function runTests() {
+ var container = document.getElementById("container");
+ for (tag in MathMLFragments) {
+ container.insertAdjacentHTML("beforeend", `<math><mrow>${MathMLFragments[tag]}</mrow></math>`);
+ }
+ Array.from(document.getElementsByClassName("element")).forEach(element => {
+ var tag = element.tagName;
+ var style = window.getComputedStyle(element);
+
+ test(function() {
+ assert_equals(style.getPropertyValue("text-transform"),
+ tag === "mi" ? "math-auto" : "none",
+ "no attribute");
+ element.parentNode.setAttribute("style", "text-transform: uppercase");
+ assert_equals(style.getPropertyValue("text-transform"),
+ tag === "mi" ? "math-auto" : "uppercase",
+ "text-transform on parent");
+ element.setAttribute("mathvariant", "normal");
+ assert_equals(style.getPropertyValue("text-transform"),
+ tag === "mi" ? "none" : "uppercase", "attribute specified");
+ element.setAttribute("mathvariant", "NoRmAl");
+ assert_equals(style.getPropertyValue("text-transform"),
+ tag === "mi" ? "none" : "uppercase", "case insensitive");
+ }, `mathvariant on the ${tag} element is ${tag === "mi" ? "" : "not"} mapped to CSS text-transform`)
+
+ test(function() {
+ // none and mprescripts appear as scripts
+ assert_equals(style.getPropertyValue("math-depth"), tag === "none" || tag === "mprescripts" ? "1" : "0", "no attribute");
+
+ var absoluteScriptlevel = 2;
+ element.setAttribute("scriptlevel", absoluteScriptlevel);
+ assert_equals(style.getPropertyValue("math-depth"), "" + absoluteScriptlevel, "attribute specified <U>");
+
+ var positiveScriptlevelDelta = 1;
+ element.setAttribute("scriptlevel", `+${positiveScriptlevelDelta}`);
+ assert_equals(style.getPropertyValue("math-depth"), "" + positiveScriptlevelDelta, "attribute specified +<U>");
+
+ var negativeScriptlevelDelta = -3;
+ element.setAttribute("scriptlevel", `${negativeScriptlevelDelta}`);
+ assert_equals(style.getPropertyValue("math-depth"), "" + negativeScriptlevelDelta, "attribute specified -<U>");
+
+ element.setAttribute("scriptlevel", absoluteScriptlevel);
+ element.setAttribute("mathsize", "42px");
+ assert_approx_equals(fontSize(style), 42, 1, "mathsize wins over scriptlevel");
+
+ }, `scriptlevel on the ${tag} element is mapped to math-depth(...)`);
+
+ test(function() {
+ // none and mprescripts appear as scripts
+ let expected = 0;
+ element.setAttribute("scriptlevel", "" + expected);
+ assert_equals(style.getPropertyValue("math-depth"), "" + expected, "no attribute");
+
+ element.setAttribute("scriptlevel", " +1");
+ assert_equals(style.getPropertyValue("math-depth"), "" + expected, "invalid scriptlevel value");
+
+ element.setAttribute("scriptlevel", " + 1");
+ assert_equals(style.getPropertyValue("math-depth"), "" + expected, "invalid scriptlevel value");
+
+ element.setAttribute("scriptlevel", "2.0");
+ assert_equals(style.getPropertyValue("math-depth"), "" + expected, "invalid scriptlevel value");
+
+ element.setAttribute("scriptlevel", "-3\"");
+ assert_equals(style.getPropertyValue("math-depth"), "" + expected, "invalid scriptlevel value");
+
+ element.setAttribute("scriptlevel", "200px");
+ assert_equals(style.getPropertyValue("math-depth"), "" + expected, "invalid scriptlevel value");
+
+ element.setAttribute("scriptlevel", "add(2)");
+ assert_equals(style.getPropertyValue("math-depth"), "" + expected, "invalid scriptlevel value");
+
+ }, `invalid scriptlevel values on the ${tag} element are not mapped to math-depth(...)`);
+
+ test(function() {
+ assert_equals(style.getPropertyValue("math-style"), "compact", "no attribute");
+ element.setAttribute("displaystyle", "true");
+ assert_equals(style.getPropertyValue("math-style"), "normal", "attribute specified");
+ element.setAttribute("displaystyle", "TrUe");
+ assert_equals(style.getPropertyValue("math-style"), "normal", "case insensitive");
+ }, `displaystyle on the ${tag} element is mapped to CSS math-style`);
+ });
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <div id="container">
+ <div><math class="element"></math></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/blur-filter-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/blur-filter-ref.html
new file mode 100644
index 0000000000..21fc165b7d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/blur-filter-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Blur filter (reference)</title>
+</head>
+<body>
+ <p>Rectangles should be blurred.</p>
+ <div style="background: green; filter: blur(5px); width: 200px; height: 200px;"></div>
+ <div style="background: green; filter: blur(5px); width: 200px; height: 200px; position: absolute; top: 300px"></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/blur-filter.html b/testing/web-platform/tests/mathml/relations/css-styling/blur-filter.html
new file mode 100644
index 0000000000..92a894bf34
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/blur-filter.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Blur filter</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="match" href="blur-filter-ref.html"/>
+<meta name="assert" content="Verify that 'filter: blur' works on MathML elements.">
+</head>
+<body>
+ <p>Rectangles should be blurred.</p>
+ <div>
+ <math><mspace width="200px" height="200px" style="background: green; filter: blur(5px)"/></math>
+ </div>
+ <div style="position: absolute; top: 300px">
+ <math style="filter: blur(5px)"><mspace width="200px" height="200px" style="background: green"/></math>
+ </div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/clip-path-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/clip-path-ref.html
new file mode 100644
index 0000000000..57935564bf
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/clip-path-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Clip property (reference)</title>
+</head>
+<body>
+ <p>Rectangles should be clipped to a polygon.</p>
+ <div style="background: green; width: 200px; height: 200px; clip-path: polygon(10% 10%, 90% 10%, 90% 90%, 10% 90%)"></div>
+ <div style="background: green; width: 200px; height: 200px; position: absolute; top: 300px; clip-path: polygon(10% 10%, 90% 10%, 90% 90%, 10% 90%)"></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/clip-path.html b/testing/web-platform/tests/mathml/relations/css-styling/clip-path.html
new file mode 100644
index 0000000000..abe58e2261
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/clip-path.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Clip property</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="match" href="clip-path-ref.html"/>
+<meta name="assert" content="Verify that the clip property works on MathML elements.">
+</head>
+<body>
+ <p>Rectangles should be clipped to a polygon.</p>
+ <div>
+ <math><mspace width="200px" height="200px" style="background: green; clip-path: polygon(10% 10%, 90% 10%, 90% 90%, 10% 90%)"/></math>
+ </div>
+ <div style="position: absolute; top: 300px; width: 200px; height: 200px">
+ <math style="position: absolute; clip-path: polygon(10% 10%, 90% 10%, 90% 90%, 10% 90%)"><mspace width="200px" height="200px" style="background: green"/></math>
+ </div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/clip-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/clip-ref.html
new file mode 100644
index 0000000000..7882ac8c31
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/clip-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Clip property (reference)</title>
+</head>
+<body>
+ <p>Rectangles should be clipped.</p>
+ <div style="background: green; width: 200px; height: 200px; position: absolute; top: 100px; clip: rect(0px 100px 100px 0px)"></div>
+ <div style="background: green; width: 200px; height: 200px; position: absolute; top: 300px; clip: rect(0px 100px 100px 0px)"></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/clip.html b/testing/web-platform/tests/mathml/relations/css-styling/clip.html
new file mode 100644
index 0000000000..48b7753fd8
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/clip.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Clip property</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="match" href="clip-ref.html"/>
+<meta name="assert" content="Verify that the clip property works on MathML elements.">
+</head>
+<body>
+ <p>Rectangles should be clipped.</p>
+ <div>
+ <math><mspace width="200px" height="200px" style="position:absolute; top:100px; background: green; clip: rect(0px 100px 100px 0px)"/></math>
+ </div>
+ <div style="position: absolute; top: 300px; width: 200px; height: 200px">
+ <math style="position: absolute; clip: rect(0px 100px 100px 0px)"><mspace width="200px" height="200px" style="background: green"/></math>
+ </div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/color-001-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/color-001-ref.html
new file mode 100644
index 0000000000..0efca480ee
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/color-001-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>color (reference)</title>
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; width: 200px; height: 200px; padding: 1px;">
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/color-001.html b/testing/web-platform/tests/mathml/relations/css-styling/color-001.html
new file mode 100644
index 0000000000..76d65f579c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/color-001.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>color</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="match" href="color-001-ref.html"/>
+<meta name="assert" content="Verify that the color is used for the text of token elements.">
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; color: red; width: 200px; height: 200px; padding: 1px;">
+ <math><mi style="color: green">1</mi></math>
+ <math><mn style="color: green">2</mn></math>
+ <math><mo style="color: green">3</mo></math>
+ <math><mtext style="color: green">4</mtext></math>
+ <math><ms style="color: green">5</ms></math>
+ <div id="dynamic">
+ <math><mi>1</mi></math>
+ <math><mn>2</mn></math>
+ <math><mo>3</mo></math>
+ <math><mtext>4</mtext></math>
+ <math><ms>5</ms></math>
+ </div>
+ </div>
+ <script>
+ window.addEventListener("load", () => {
+ document.getElementById("dynamic").style.color = "green";
+ document.documentElement.classList.remove("reftest-wait");
+ });
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/color-002-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/color-002-ref.html
new file mode 100644
index 0000000000..0efca480ee
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/color-002-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>color (reference)</title>
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; width: 200px; height: 200px; padding: 1px;">
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/color-002.html b/testing/web-platform/tests/mathml/relations/css-styling/color-002.html
new file mode 100644
index 0000000000..bce24f54c8
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/color-002.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>color</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="help" href="https://w3c.github.io/mathml-core/#fraction-with-nonzero-line-thickness">
+<link rel="match" href="color-002-ref.html"/>
+<meta name="assert" content="Verify that the color is used for text and fraction bar of the mfrac element.">
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; color: red; width: 200px; height: 200px; padding: 1px;">
+ <math><mfrac style="color: green"><mn>1</mn><mn>2</mn></mfrac></math>
+ <div id="dynamic">
+ <math><mfrac><mn>1</mn><mn>2</mn></mfrac></math>
+ </div>
+ </div>
+ <script>
+ window.addEventListener("load", () => {
+ document.getElementById("dynamic").style.color = "green";
+ document.documentElement.classList.remove("reftest-wait");
+ });
+ </script>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/color-003-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/color-003-ref.html
new file mode 100644
index 0000000000..0efca480ee
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/color-003-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>color (reference)</title>
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; width: 200px; height: 200px; padding: 1px;">
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/color-003.html b/testing/web-platform/tests/mathml/relations/css-styling/color-003.html
new file mode 100644
index 0000000000..dd04b61054
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/color-003.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>color</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="help" href="https://w3c.github.io/mathml-core/#radical-symbol">
+<link rel="match" href="color-003-ref.html"/>
+<meta name="assert" content="Verify that the color is used for text and radical symbol of the msqrt and mroot elements.">
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; color: red; width: 200px; height: 200px; padding: 1px;">
+ <math><msqrt style="color: green"><mn>1</mn></msqrt></math>
+ <math><mroot style="color: green"><mn>2</mn><mn>2</mn></mroot></math>
+ <div id="dynamic">
+ <math><msqrt><mn>1</mn></msqrt></math>
+ <math><mroot><mn>2</mn><mn>2</mn></mroot></math>
+ </div>
+ </div>
+ <script>
+ window.addEventListener("load", () => {
+ document.getElementById("dynamic").style.color = "green";
+ document.documentElement.classList.remove("reftest-wait");
+ });
+ </script>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_msqrt");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/color-004.tentative-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/color-004.tentative-ref.html
new file mode 100644
index 0000000000..0efca480ee
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/color-004.tentative-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>color (reference)</title>
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; width: 200px; height: 200px; padding: 1px;">
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/color-004.tentative.html b/testing/web-platform/tests/mathml/relations/css-styling/color-004.tentative.html
new file mode 100644
index 0000000000..4bd15e62a0
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/color-004.tentative.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>color</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="help" href="https://github.com/mathml-refresh/mathml-core/pull/24">
+<link rel="match" href="color-004.tentative-ref.html"/>
+<meta name="assert" content="Verify that the color is used for text and graphical elements of the menclose element.">
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; color: red; width: 200px; height: 200px; padding: 1px;">
+ <math><menclose notation="left" style="color: green"><mn>1</mn></menclose></math>
+ <math><menclose notation="right" style="color: green"><mn>2</mn></menclose></math>
+ <math><menclose notation="top" style="color: green"><mn>3</mn></menclose></math>
+ <math><menclose notation="bottom" style="color: green"><mn>4</mn></menclose></math>
+ <math><menclose notation="box" style="color: green"><mn>5</mn></menclose></math>
+ <math><menclose notation="roundedbox" style="color: green"><mn>6</mn></menclose></math>
+ <math><menclose notation="actuarial" style="color: green"><mn>7</mn></menclose></math>
+ <math><menclose notation="madruwb" style="color: green"><mn>8</mn></menclose></math>
+ <math><menclose notation="horizontalstrike" style="color: green"><mn>9</mn></menclose></math>
+ <math><menclose notation="verticalstrike" style="color: green"><mn>10</mn></menclose></math>
+ <math><menclose notation="updiagonalstrike" style="color: green"><mn>11</mn></menclose></math>
+ <math><menclose notation="downdiagonalstrike" style="color: green"><mn>12</mn></menclose></math>
+ <math><menclose notation="longdiv" style="color: green"><mn>13</mn></menclose></math>
+ <math><menclose notation="circle" style="color: green"><mn>14</mn></menclose></math>
+ <div id="dynamic">
+ <math><menclose notation="left"><mn>1</mn></menclose></math>
+ <math><menclose notation="right"><mn>2</mn></menclose></math>
+ <math><menclose notation="top"><mn>3</mn></menclose></math>
+ <math><menclose notation="bottom"><mn>4</mn></menclose></math>
+ <math><menclose notation="box"><mn>5</mn></menclose></math>
+ <math><menclose notation="roundedbox"><mn>6</mn></menclose></math>
+ <math><menclose notation="actuarial"><mn>7</mn></menclose></math>
+ <math><menclose notation="madruwb"><mn>8</mn></menclose></math>
+ <math><menclose notation="horizontalstrike"><mn>9</mn></menclose></math>
+ <math><menclose notation="verticalstrike"><mn>10</mn></menclose></math>
+ <math><menclose notation="updiagonalstrike"><mn>11</mn></menclose></math>
+ <math><menclose notation="downdiagonalstrike"><mn>12</mn></menclose></math>
+ <math><menclose notation="longdiv"><mn>13</mn></menclose></math>
+ <math><menclose notation="circle"><mn>14</mn></menclose></math>
+ </div>
+ </div>
+ <script>
+ window.addEventListener("load", () => {
+ document.getElementById("dynamic").style.color = "green";
+ document.documentElement.classList.remove("reftest-wait");
+ });
+ </script>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_menclose");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/color-005-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/color-005-ref.html
new file mode 100644
index 0000000000..0efca480ee
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/color-005-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>color (reference)</title>
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; width: 200px; height: 200px; padding: 1px;">
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/color-005.html b/testing/web-platform/tests/mathml/relations/css-styling/color-005.html
new file mode 100644
index 0000000000..f2660c9e62
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/color-005.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>color</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="match" href="color-005-ref.html"/>
+<meta name="assert" content="Verify that the color is used for normal, stretchy and large operators.">
+<style>
+ math {
+ font: 20px/1 Ahem;
+ }
+ @font-face {
+ font-family: operators;
+ src: url("/fonts/math/operators.woff");
+ }
+ mo {
+ font-family: operators;
+ }
+</style>
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div id="square" style="background: green; color: red; width: 200px; height: 200px; padding: 1px;">
+ <math>
+ <!-- unstretched operators -->
+ <mo style="color: green">⥯</mo>
+ <mo style="color: green">+</mo>
+ <mo style="color: green">-</mo>
+ </math>
+ <math displaystyle="true">
+ <!-- large operator -->
+ <mo largeop="true" style="color: green">⥯</mo>
+ </math>
+ <math>
+ <mrow>
+ <!-- stretchy, small size -->
+ <mspace height="2em"/>
+ <mo style="color: green">⥯</mo>
+ </mrow>
+ </math>
+ <math>
+ <mrow>
+ <!-- stretchy, large size -->
+ <mspace height="4em"/>
+ <mo style="color: green">⥯</mo>
+ </mrow>
+ </math>
+ <div id="dynamic">
+ <math>
+ <!-- unstretched operators -->
+ <mo stretchy="false">⥯</mo>
+ <mo>+</mo>
+ <mo>-</mo>
+ </math>
+ <math displaystyle="true">
+ <!-- large operator -->
+ <mo largeop="true">⥯</mo>
+ </math>
+ <math>
+ <mrow>
+ <!-- stretchy, small size -->
+ <mspace height="2em"/>
+ <mo>⥯</mo>
+ </mrow>
+ </math>
+ <math>
+ <mrow>
+ <!-- stretchy, large size -->
+ <mspace height="4em"/>
+ <mo>⥯</mo>
+ </mrow>
+ </math>
+ </div>
+ </div>
+ <script src="/mathml/support/fonts.js"></script>
+ <script>
+ window.addEventListener("load", () => loadAllFonts().then(() => {
+ document.getElementById("dynamic").style.color = "green";
+ document.documentElement.classList.remove("reftest-wait");
+ }));
+ </script>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_operator_spacing");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/default-font-family.html b/testing/web-platform/tests/mathml/relations/css-styling/default-font-family.html
new file mode 100644
index 0000000000..c471b0fc9d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/default-font-family.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Default font-family on the &lt;math&gt; root</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-top-level-math-element">
+<link rel="help" href="https://w3c.github.io/mathml-core/#user-agent-stylesheet">
+<meta name="assert" content="Verify that the default font-family is 'math'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <div id="log"></div>
+ <div style="font-family: BB2F7F3E9FEE11EA96DF67A737751C2F;">
+ <div id="inherited-reference"></div>
+ <math id="math-not-inherited"></math>
+ </div>
+ <math id="math-default"></math>
+
+ <script>
+ function getFontFamily(id) {
+ return window.getComputedStyle(document.getElementById(id)).fontFamily;
+ }
+
+ test(function () {
+ assert_equals(getFontFamily("inherited-reference"), "BB2F7F3E9FEE11EA96DF67A737751C2F");
+ assert_not_equals(getFontFamily("math-not-inherited"), getFontFamily("inherited-reference"));
+ }, "Default font-family on <math> is not inherited");
+
+ test(function () {
+ assert_equals(getFontFamily("math-not-inherited"), "math");
+ assert_equals(getFontFamily("math-default"), "math");
+ }, "Default font-family on <math> is 'math'");
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/default-properties-on-semantics-and-maction.html b/testing/web-platform/tests/mathml/relations/css-styling/default-properties-on-semantics-and-maction.html
new file mode 100644
index 0000000000..23f8b62dfa
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/default-properties-on-semantics-and-maction.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Default properties on &lt;semantics&gt; and &lt;maction&gt;</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#semantics-and-presentation">
+<link rel="help" href="https://w3c.github.io/mathml-core/#enlivening-expressions">
+<link rel="help" href="https://w3c.github.io/mathml-core/#user-agent-stylesheet">
+<meta name="assert" content="Test that only the first children of semantics/maction are displayed.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <div id="log"></div>
+ <div>
+ <math>
+ <semantics>
+ <mn>1</mn>
+ <mn>2</mn>
+ <mn>3</mn>
+ <mn>4</mn>
+ <mn>5</mn>
+ </semantics>
+ <maction>
+ <mn>1</mn>
+ <mn>2</mn>
+ <mn>3</mn>
+ <mn>4</mn>
+ <mn>5</mn>
+ </maction>
+ </math>
+ </div>
+
+ <script>
+ ["semantics", "maction"].forEach(name => {
+ let element = document.getElementsByTagName(name)[0];
+ test(() => {
+ let child = element.firstElementChild;
+ assert_not_equals(window.getComputedStyle(child).display, "none", `Child ${child.innerText} does not have display: none`);
+ for (child = child.nextElementSibling; child; child = child.nextElementSibling) {
+ assert_equals(window.getComputedStyle(child).display, "none", `Child ${child.innerText} has display: none`);
+ }
+ }, `Display value of children of the <${name}> element`);
+ });
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/default-properties-on-the-math-root.html b/testing/web-platform/tests/mathml/relations/css-styling/default-properties-on-the-math-root.html
new file mode 100644
index 0000000000..c329935f2e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/default-properties-on-the-math-root.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Default properties on the &lt;math&gt; root</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-top-level-math-element">
+<link rel="help" href="https://w3c.github.io/mathml-core/#user-agent-stylesheet">
+<meta name="assert" content="Test properties on the math root set by the UA stylesheet.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ math {
+ font-size: 100px;
+ }
+ .styled {
+ direction: rtl;
+ writing-mode: vertical-lr;
+ text-indent: .5em;
+ letter-spacing: .5em;
+ line-height: .5em;
+ word-spacing: .5em;
+ font-style: italic;
+ font-weight: bold;
+ }
+</style>
+
+</head>
+<body>
+ <div id="log"></div>
+ <div class="styled">
+ <math id="ua"></math>
+ <math id="author" class="styled"></math>
+ </div>
+
+ <script>
+ function getProperty(id, property) {
+ return window.getComputedStyle(document.getElementById(id))[property];
+ }
+ [
+ // Property name, value when specified from the UA, from the author.
+ ["direction", "ltr", "rtl"],
+ ["writing-mode", "horizontal-tb", "horizontal-tb"], // MathML Core level 1 only supports horizontal mode.
+ ["text-indent", "0px", "50px"],
+ ["letter-spacing", "normal", "50px"],
+ ["line-height", "normal", "50px"],
+ ["word-spacing", "0px", "50px"],
+ ["font-style", "normal", "italic"],
+ ["font-weight", "400", "700"]
+ ].forEach(([name, ua_value, author_value]) => {
+ test(function () {
+ assert_equals(getProperty("ua", name), ua_value, "when specified from the UA sheet");
+ assert_equals(getProperty("author", name), author_value, "when specified by the author");
+ }, `Value of ${name} on the <math> root`);
+ });
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/display-1-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/display-1-ref.html
new file mode 100644
index 0000000000..ce65aba18c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/display-1-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>display (reference)</title>
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; width: 200px; height: 200px;">
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/display-1.html b/testing/web-platform/tests/mathml/relations/css-styling/display-1.html
new file mode 100644
index 0000000000..5a9e4db687
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/display-1.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>display</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="match" href="display-1-ref.html"/>
+<meta name="assert" content="Verify that the 'display: none' property works on MathML elements.">
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; color: red; width: 200px; height: 200px;">
+ <math style="display: none;"><mspace width="200px" height="200px" style="background: red"/></math>
+ </div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/display-2.html b/testing/web-platform/tests/mathml/relations/css-styling/display-2.html
new file mode 100644
index 0000000000..36a02952eb
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/display-2.html
@@ -0,0 +1,139 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Verify that one can override the layout of MathML elements with the CSS display property</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<meta name="assert" content="Verify that one can override the display of a MathML element.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/layout-comparison.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ math {
+ font-family: inherit;
+ }
+ mfrac {
+ padding: 0;
+ }
+</style>
+<script>
+ const Xsize = 25;
+ const templates = {
+ "block display": `<math style="display: block;">XXX</math>`,
+ "block display with contrained width": `<math style="display: block; width: ${2*Xsize}px;">XXX</math>`,
+ "list display inside display block": `<math style="display: block">\
+ <mmultiscripts style="display: list-item;">X</mmultiscripts>\
+ <maction style="display: list-item;">X</maction>\
+ <mpadded style="display: list-item;">X</mpadded>\
+</math>`,
+ "inline display": `<math style="display: inline;">XXX</math>`,
+ "inline-block display": `<math style="display: inline-block">XXX</math>`,
+ "table display (math)": `<math style="display: table">\
+ <mfrac style='display: table-row'>\
+ <msub style='display: table-cell'>X</msub>\
+ <msup style='display: table-cell'>X</msup>\
+ <msubsup style='display: table-cell'>X</msubsup>\
+ </mfrac>\
+ <mtable style='display: table-row'>\
+ <munder style='display: table-cell'>X</munder>\
+ <mover style='display: table-cell'>X</mover>\
+ <munderover style='display: table-cell'>X</munderover>\
+ </mtable>\
+</math>`,
+ "table display (mrow)": `<math display="block">\
+<mrow style="display: table">\
+ <mfrac style='display: table-row'>\
+ <msub style='display: table-cell'>X</msub>\
+ <msup style='display: table-cell'>X</msup>\
+ <msubsup style='display: table-cell'>X</msubsup>\
+ </mfrac>\
+ <mtable style='display: table-row'>\
+ <munder style='display: table-cell'>X</munder>\
+ <mover style='display: table-cell'>X</mover>\
+ <munderover style='display: table-cell'>X</munderover>\
+ </mtable>\
+</mrow></math>`,
+ "inline-table display (math)": `<math style="display: inline-table">\
+ <mfrac style='display: table-row'>\
+ <msub style='display: table-cell'>X</msub>\
+ <msup style='display: table-cell'>X</msup>\
+ <msubsup style='display: table-cell'>X</msubsup>\
+ </mfrac>\
+ <mtable style='display: table-row'>\
+ <munder style='display: table-cell'>X</munder>\
+ <mover style='display: table-cell'>X</mover>\
+ <munderover style='display: table-cell'>X</munderover>\
+ </mtable>\
+</math>`,
+ "inline-table display (mrow)": `<math display="block">\
+<mrow style="display: inline-table">\
+ <mfrac style='display: table-row'>\
+ <msub style='display: table-cell'>X</msub>\
+ <msup style='display: table-cell'>X</msup>\
+ <msubsup style='display: table-cell'>X</msubsup>\
+ </mfrac>\
+ <mtable style='display: table-row'>\
+ <munder style='display: table-cell'>X</munder>\
+ <mover style='display: table-cell'>X</mover>\
+ <munderover style='display: table-cell'>X</munderover>\
+ </mtable>\
+</mrow></math>`,
+ "flexbox display (math)": `<math style="display: flex; flex-direction: column;">XXX</math>`,
+ "flexbox display (mrow)": `<math display="block"><mrow style="display: flex; flex-direction: column;">XXX</mrow></math>`,
+ "grid display (math)": `<math style="display: grid; grid-gap: 2px; grid-template-columns: ${Xsize}px ${Xsize}px ${Xsize}px;>">XXXXXXXXX</math>`,
+ "grid display (mrow)": `<math display="block"><mrow style="display: grid; grid-gap: 2px; grid-template-columns: ${Xsize}px ${Xsize}px ${Xsize}px;>">XXXXXXXXX</mrow></math>`,
+ "ruby display (math)": `<math style="display: ruby;">\
+<mrow style="display: ruby-base;">X</mrow>\
+<mrow style="display: ruby-text">XX</mrow>\
+</math>`,
+ "ruby display (mrow)": `<math display="block"><mrow style="display: ruby;">\
+<mrow style="display: ruby-base;">X</mrow>\
+<mrow style="display: ruby-text">XX</mrow>\
+</mrow></math>`,
+ "block display with column width (math)": `<math style="display: block; column-width: ${2*Xsize}px">\
+ <mrow>XXXX</mrow><mrow>XXXX</mrow><mrow>XXXX</mrow>\
+</math>`,
+ "block display with column width (mrow)": `<math style="display: block"><mrow style="display: block; column-width: ${2*Xsize}px">\
+ <mrow>XXXX</mrow><mrow>XXXX</mrow><mrow>XXXX</mrow>\
+</mrow></math>`,
+ };
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+
+ for (let key in templates) {
+ if (!templates.hasOwnProperty(key))
+ continue;
+ let mathtest = templates[key].
+ replace(/X/g, `<mspace style="display: inline-block; width: ${Xsize}px; height: ${Xsize}px; background: black"></mspace>`);
+ let reference = mathtest.
+ replace(/maction|math|mfrac|mmultiscripts|mover|mover|mpadded|mrow|mspace|msubsup|msub|msup|mtable|munderover|munder/g, "div");
+ document.body.insertAdjacentHTML("beforeend", `<div style="font: 20px/1 Ahem; position: absolute;">\
+<div><span>${key}:</span>${mathtest}</div>\
+<div><span>${key}:</span>${reference}</div>\
+</div>`);
+ let div = document.body.lastElementChild;
+ let elementDiv = div.firstElementChild;
+ let referenceDiv = div.lastElementChild;
+
+ test(function() {
+ const epsilon = 1;
+ compareLayout(elementDiv, referenceDiv, epsilon);
+ }, `${key}`);
+
+ div.style = "display: none;"; // Hide the div after measurement.
+ }
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/display-contents.html b/testing/web-platform/tests/mathml/relations/css-styling/display-contents.html
new file mode 100644
index 0000000000..b18fdd6c8b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/display-contents.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>display: contents</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<meta name="assert" content="Verify that display: contents computes to display: none">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+ function runTests() {
+ var container = document.getElementById("container");
+ for (tag in MathMLFragments) {
+ container.insertAdjacentHTML("beforeend", `<math>${MathMLFragments[tag]}</math>`);
+ }
+ test(function() {
+ Array.from(document.getElementsByClassName("element")).forEach(element => {
+ var style = window.getComputedStyle(element);
+ element.setAttribute("style", "display: contents");
+ assert_equals(style.getPropertyValue("display"), "none", `${tag}`);
+ });
+ }, "display: contents computes to display: none");
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <div id="container">
+ <math class="element"></math>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/display-with-overflow-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/display-with-overflow-ref.html
new file mode 100644
index 0000000000..b359414dc2
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/display-with-overflow-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<style>
+div {
+ width: 20px;
+ padding: 5px;
+ font-size: 40px;
+ overflow-x: scroll;
+ overflow-y: hidden;
+}
+</style>
+<div>
+ <math display="block" style="width: min-content;">
+ <mn>text</mn>
+ </math>
+</div>
+<div style="direction: rtl;">
+ <math display="block" style="width: min-content;">
+ <mn>text</mn>
+ </math>
+</div>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/display-with-overflow.html b/testing/web-platform/tests/mathml/relations/css-styling/display-with-overflow.html
new file mode 100644
index 0000000000..33df26c3ee
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/display-with-overflow.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1416539">
+<link rel="match" href="display-with-overflow-ref.html">
+<meta name="assert" content="Use safe centering (so that content is reachable with scroll) for display=block centering.">
+<style>
+math {
+ width: 20px;
+ padding: 5px;
+ font-size: 40px;
+ overflow-x: scroll;
+ overflow-y: hidden;
+}
+</style>
+<math display="block">
+ <mn>text</mn>
+</math>
+<math display="block" style="direction: rtl;">
+ <mn>text</mn>
+</math>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-011-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-011-ref.html
new file mode 100644
index 0000000000..400c46a245
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-011-ref.html
@@ -0,0 +1,155 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>displaystyle</title>
+ <meta charset="utf-8">
+ <link rel="stylesheet" href="/fonts/ahem.css">
+ <style>
+ math {
+ font: 25px Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <!-- Test displaystyle on mstyle -->
+ <math>
+ <mstyle displaystyle="true">
+ <munder><mo>O</mo><mo>O</mo></munder>
+ </mstyle>
+ <mstyle displaystyle="false">
+ <msub><mo>O</mo><mo>O</mo></munder>
+ </mstyle>
+ </math>
+
+ <!-- The mfrac element sets displaystyle to "false", or if it was already
+ false increments scriptlevel by 1, within numerator and denominator.
+ -->
+ <math>
+ <mstyle displaystyle="true">
+ <mfrac>
+ <msub><mo>O</mo><mo>O</mo></msub>
+ <msub><mo>O</mo><mo>O</mo></msub>
+ </mfrac>
+ </mstyle>
+ </math>
+
+ <!-- The mroot element increments scriptlevel by 2, and sets
+ displaystyle to "false", within index, but leaves both attributes
+ unchanged within base.
+ The msqrt element leaves both attributes unchanged within its
+ argument. -->
+ <math>
+ <mstyle displaystyle="true">
+ <mroot>
+ <munder><mo>O</mo><mo>O</mo></munder>
+ <msub><mo>O</mo><mo>O</mo></msub>
+ </mroot>
+ <msqrt>
+ <munder><mo>O</mo><mo>O</mo></munder>
+ </msqrt>
+ </mstyle>
+ </math>
+
+<!--
+ The msub element [...] increments scriptlevel by 1, and sets displaystyle to
+ "false", within subscript, but leaves both attributes unchanged within base.
+
+ The msup element [...] increments scriptlevel by 1, and sets displaystyle to
+ "false", within superscript, but leaves both attributes unchanged within
+ base.
+
+ The msubsup element [...] increments scriptlevel by 1, and sets displaystyle
+ to "false", within subscript and superscript, but leaves both attributes
+ unchanged within base.
+
+ The mmultiscripts element increments scriptlevel by 1, and sets displaystyle
+ to "false", within each of its arguments except base, but leaves both
+ attributes unchanged within base.
+ -->
+ <math>
+ <mstyle displaystyle="true">
+ <msub>
+ <munder><mo>O</mo><mo>O</mo></munder>
+ <msub><mo>O</mo><mo>O</mo></msub>
+ </msub>
+ <msup>
+ <munder><mo>O</mo><mo>O</mo></munder>
+ <msub><mo>O</mo><mo>O</mo></msub>
+ </msup>
+ <msubsup>
+ <munder><mo>O</mo><mo>O</mo></munder>
+ <msub><mo>O</mo><mo>O</mo></msub>
+ <msub><mo>O</mo><mo>O</mo></msub>
+ </msubsup>
+ <mmultiscripts>
+ <munder><mo>O</mo><mo>O</mo></munder>
+ <msub><mo>O</mo><mo>O</mo></msub>
+ <msub><mo>O</mo><mo>O</mo></msub>
+ <mprescripts/>
+ <msub><mo>O</mo><mo>O</mo></msub>
+ <msub><mo>O</mo><mo>O</mo></msub>
+ </mmultiscripts>
+ </mstyle>
+ </math>
+
+<!--
+ The munder element [...] always sets displaystyle to "false" within the
+ underscript, but increments scriptlevel by 1 only when accentunder is
+ "false". Within base, it always leaves both attributes unchanged.
+
+ The mover element [...] always sets displaystyle to "false" within
+ overscript, but increments scriptlevel by 1 only when accent is "false".
+ Within base, it always leaves both attributes unchanged.
+
+ The munderover [..] always sets displaystyle to "false" within underscript
+ and overscript, but increments scriptlevel by 1 only when accentunder or
+ accent, respectively, are "false". Within base, it always leaves both
+ attributes unchanged.
+-->
+ <math>
+ <mstyle displaystyle="true">
+ <munder>
+ <munder><mo>O</mo><mo>O</mo></munder>
+ <msub><mo>O</mo><mo>O</mo></msub>
+ </munder>
+ <mover>
+ <munder><mo>O</mo><mo>O</mo></munder>
+ <msub><mo>O</mo><mo>O</mo></msub>
+ </mover>
+ <munderover>
+ <munder><mo>O</mo><mo>O</mo></munder>
+ <msub><mo>O</mo><mo>O</mo></msub>
+ <msub><mo>O</mo><mo>O</mo></msub>
+ </munderover>
+ </mstyle>
+ </math>
+
+<!--
+ The displaystyle attribute is allowed on the mtable element to set the
+ inherited value of the attribute. If the attribute is not present, the
+ mtable element sets displaystyle to "false" within the table elements.
+-->
+ <math>
+ <mstyle displaystyle="false">
+ <mtable displaystyle="true">
+ <mtr>
+ <mtd>
+ <munder><mo>O</mo><mo>O</mo></munder>
+ </mtd>
+ </mtr>
+ </mtable>
+ </mstyle>
+ <mstyle displaystyle="true">
+ <mtable>
+ <mtr>
+ <mtd>
+ <msub><mo>O</mo><mo>O</mo></msub>
+ </mtd>
+ </mtr>
+ </mtable>
+ </mstyle>
+ </math>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-011.html b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-011.html
new file mode 100644
index 0000000000..a0bfc29ae5
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-011.html
@@ -0,0 +1,168 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>displaystyle</title>
+ <meta charset="utf-8">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#the-displaystyle-and-scriptlevel-attributes">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#style-change-mstyle">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#radicals-msqrt-mroot">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#prescripts-and-tensor-indices-mmultiscripts">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#table-or-matrix-mtable">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <link rel="match" href="displaystyle-011-ref.html"/>
+ <meta name="assert" content="Test the effect on displaystyle and movablelimits">
+ <link rel="stylesheet" href="/fonts/ahem.css">
+ <style>
+ math {
+ font: 25px Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <!-- Test displaystyle on mstyle -->
+ <math>
+ <mstyle displaystyle="true">
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ </mstyle>
+ <mstyle displaystyle="false">
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ </mstyle>
+ </math>
+
+ <!-- The mfrac element sets displaystyle to "false", or if it was already
+ false increments scriptlevel by 1, within numerator and denominator.
+ -->
+ <math>
+ <mstyle displaystyle="true">
+ <mfrac>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ </mfrac>
+ </mstyle>
+ </math>
+
+ <!-- The mroot element increments scriptlevel by 2, and sets
+ displaystyle to "false", within index, but leaves both attributes
+ unchanged within base.
+ The msqrt element leaves both attributes unchanged within its
+ argument. -->
+ <math>
+ <mstyle displaystyle="true">
+ <mroot>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ </mroot>
+ <msqrt>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ </msqrt>
+ </mstyle>
+ </math>
+
+<!--
+ The msub element [...] increments scriptlevel by 1, and sets displaystyle to
+ "false", within subscript, but leaves both attributes unchanged within base.
+
+ The msup element [...] increments scriptlevel by 1, and sets displaystyle to
+ "false", within superscript, but leaves both attributes unchanged within
+ base.
+
+ The msubsup element [...] increments scriptlevel by 1, and sets displaystyle
+ to "false", within subscript and superscript, but leaves both attributes
+ unchanged within base.
+
+ The mmultiscripts element increments scriptlevel by 1, and sets displaystyle
+ to "false", within each of its arguments except base, but leaves both
+ attributes unchanged within base.
+ -->
+ <math>
+ <mstyle displaystyle="true">
+ <msub>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ </msub>
+ <msup>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ </msup>
+ <msubsup>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ </msubsup>
+ <mmultiscripts>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <mprescripts/>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ </mmultiscripts>
+ </mstyle>
+ </math>
+
+<!--
+ The munder element [...] always sets displaystyle to "false" within the
+ underscript, but increments scriptlevel by 1 only when accentunder is
+ "false". Within base, it always leaves both attributes unchanged.
+
+ The mover element [...] always sets displaystyle to "false" within
+ overscript, but increments scriptlevel by 1 only when accent is "false".
+ Within base, it always leaves both attributes unchanged.
+
+ The munderover [..] always sets displaystyle to "false" within underscript
+ and overscript, but increments scriptlevel by 1 only when accentunder or
+ accent, respectively, are "false". Within base, it always leaves both
+ attributes unchanged.
+-->
+ <math>
+ <mstyle displaystyle="true">
+ <munder>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ </munder>
+ <mover>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ </mover>
+ <munderover>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ </munderover>
+ </mstyle>
+ </math>
+
+<!--
+ The displaystyle attribute is allowed on the mtable element to set the
+ inherited value of the attribute. If the attribute is not present, the
+ mtable element sets displaystyle to "false" within the table elements.
+-->
+ <math>
+ <mstyle displaystyle="false">
+ <mtable displaystyle="true">
+ <mtr>
+ <mtd>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ </mtd>
+ </mtr>
+ </mtable>
+ </mstyle>
+ <mstyle displaystyle="true">
+ <mtable>
+ <mtr>
+ <mtd>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ </mtd>
+ </mtr>
+ </mtable>
+ </mstyle>
+ </math>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_movablelimits");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-012-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-012-ref.html
new file mode 100644
index 0000000000..96042b696f
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-012-ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>displaystyle</title>
+ <meta charset="utf-8">
+ <link rel="stylesheet" href="/fonts/ahem.css">
+ <style>
+ math {
+ font: 25px Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <!-- Test the effect of displaystyle on munder, mover and munderover -->
+ <math>
+ <mstyle displaystyle="true">
+ <munder><mo>O</mo><mo>O</mo></munder>
+ <mover><mo>O</mo><mo>O</mo></mover>
+ <munderover><mo>O</mo><mo>O</mo><mo>O</mo></munderover>
+ </mstyle>
+ <mstyle displaystyle="false">
+ <msub><mo>O</mo><mo>O</mo></msub>
+ <msup><mo>O</mo><mo>O</mo></msup>
+ <msubsup><mo>O</mo><mo>O</mo><mo>O</mo></msubsup>
+ </mstyle>
+ </math>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-012.html b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-012.html
new file mode 100644
index 0000000000..9fd4c784dd
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-012.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>displaystyle</title>
+ <meta charset="utf-8">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#the-displaystyle-and-scriptlevel-attributes">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#style-change-mstyle">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <link rel="match" href="displaystyle-012-ref.html"/>
+ <meta name="assert" content="Test the effect on displaystyle on munder, mover and munderover">
+ <link rel="stylesheet" href="/fonts/ahem.css">
+ <style>
+ math {
+ font: 25px Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <math>
+ <mstyle displaystyle="true">
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <mover><mo movablelimits="true">O</mo><mo>O</mo></mover>
+ <munderover><mo movablelimits="true">O</mo><mo>O</mo><mo>O</mo></munderover>
+ </mstyle>
+ <mstyle displaystyle="false">
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <mover><mo movablelimits="true">O</mo><mo>O</mo></mover>
+ <munderover><mo movablelimits="true">O</mo><mo>O</mo><mo>O</mo></munderover>
+ </mstyle>
+ </math>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_movablelimits");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-013-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-013-ref.html
new file mode 100644
index 0000000000..9a580350de
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-013-ref.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>displaystyle</title>
+ <meta charset="utf-8">
+ <link rel="stylesheet" href="/fonts/ahem.css">
+ <style>
+ math {
+ font: 25px Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <!-- Test dynamic change of displaystyle -->
+ <math id="m1" displaystyle="true">
+ <munder><mo>O</mo><mo>O</mo></munder>
+ <mfrac><mn>1</mn><mn>2</mn></mfrac>
+ </math>
+ <math>
+ <mstyle id="m2" displaystyle="true">
+ <munder><mo>O</mo><mo>O</mo></munder>
+ <mfrac><mn>1</mn><mn>2</mn></mfrac>
+ </mstyle>
+ </math>
+ <math>
+ <mtable id="m3" displaystyle="true">
+ <mtr>
+ <mtd>
+ <munder><mo>O</mo><mo>O</mo></munder>
+ <mfrac><mn>1</mn><mn>2</mn></mfrac>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+ <math id="m4" displaystyle="false">
+ <msub><mo>O</mo><mo>O</mo></msub>
+ <mfrac><mn>1</mn><mn>2</mn></mfrac>
+ </math>
+ <math>
+ <mstyle id="m5" displaystyle="false">
+ <msub><mo>O</mo><mo>O</mo></msub>
+ <mfrac><mn>1</mn><mn>2</mn></mfrac>
+ </mstyle>
+ </math>
+ <math>
+ <mtable id="m6" displaystyle="false">
+ <mtr>
+ <mtd>
+ <msub><mo>O</mo><mo>O</mo></msub>
+ <mfrac><mn>1</mn><mn>2</mn></mfrac>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-013.html b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-013.html
new file mode 100644
index 0000000000..3ce9fff062
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-013.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <title>displaystyle</title>
+ <meta charset="utf-8">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#the-displaystyle-and-scriptlevel-attributes">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#style-change-mstyle">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#table-or-matrix-mtable">
+ <link rel="match" href="displaystyle-013-ref.html"/>
+ <meta name="assert" content="Test dynamic change of displaystyle">
+ <script src="/mathml/support/fonts.js"></script>
+ <script type="text/javascript">
+ function doTest() {
+ document.body.offsetTop; // Update layout
+ document.getElementById("m1").setAttribute("displaystyle", "true");
+ document.getElementById("m2").setAttribute("displaystyle", "true");
+ document.getElementById("m3").setAttribute("displaystyle", "true");
+ document.getElementById("m4").removeAttribute("displaystyle");
+ document.getElementById("m5").removeAttribute("displaystyle");
+ document.getElementById("m6").removeAttribute("displaystyle");
+ document.documentElement.removeAttribute("class");
+ }
+ window.addEventListener("load", () => { loadAllFonts().then(doTest); });
+ </script>
+ <link rel="stylesheet" href="/fonts/ahem.css">
+ <style>
+ math {
+ font: 25px Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <math id="m1">
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <mfrac><mn>1</mn><mn>2</mn></mfrac>
+ </math>
+ <math>
+ <mstyle id="m2">
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <mfrac><mn>1</mn><mn>2</mn></mfrac>
+ </mstyle>
+ </math>
+ <math>
+ <mtable id="m3">
+ <mtr>
+ <mtd>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <mfrac><mn>1</mn><mn>2</mn></mfrac>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+ <math id="m4" displaystyle="true">
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <mfrac><mn>1</mn><mn>2</mn></mfrac>
+ </math>
+ <math>
+ <mstyle id="m5" displaystyle="true">
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <mfrac><mn>1</mn><mn>2</mn></mfrac>
+ </mstyle>
+ </math>
+ <math>
+ <mtable id="m6" displaystyle="true">
+ <mtr>
+ <mtd>
+ <munder><mo movablelimits="true">O</mo><mo>O</mo></munder>
+ <mfrac><mn>1</mn><mn>2</mn></mfrac>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_movablelimits");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-014-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-014-ref.html
new file mode 100644
index 0000000000..085e2c429d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-014-ref.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>displaystyle</title>
+ <meta charset="utf-8">
+ <link rel="stylesheet" href="/fonts/ahem.css">
+ <style>
+ math {
+ font: 25px Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <!-- See https://bugzilla.mozilla.org/show_bug.cgi?id=832800 -->
+ <math>
+ <mstyle displaystyle="true">
+ <mfrac>
+ <mrow>
+ <mn>X</mn>
+ <mo id="mathOperator" mathbackground="red">+</mo>
+ <mfrac>
+ <mrow><mn>X</mn></mrow>
+ <mrow><mn>X</mn></mrow>
+ </mfrac>
+ </mrow>
+ <mrow>
+ <mn>X</mn>
+ </mrow>
+ </mfrac>
+ </mstyle>
+ </math>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-014.html b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-014.html
new file mode 100644
index 0000000000..a4f1208e35
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-014.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <title>displaystyle</title>
+ <meta charset="utf-8">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#the-displaystyle-and-scriptlevel-attributes">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#style-change-mstyle">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+ <link rel="match" href="displaystyle-014-ref.html"/>
+ <meta name="assert" content="Test dynamic change of mathbackground on an operator does not interfer with its displaystyle">
+ <script src="/mathml/support/fonts.js"></script>
+ <script type="text/javascript">
+ function doTest() {
+ document.body.offsetTop; // Update layout
+ document.getElementById('mathOperator').
+ setAttribute('mathbackground', 'red');
+ document.documentElement.removeAttribute("class");
+ }
+ window.addEventListener("load", () => { loadAllFonts().then(doTest); });
+ </script>
+ <link rel="stylesheet" href="/fonts/ahem.css">
+ <style>
+ math {
+ font: 25px Ahem;
+ }
+ </style>
+ </head>
+ <body>
+
+ <!-- See https://bugzilla.mozilla.org/show_bug.cgi?id=832800 -->
+ <math>
+ <mstyle displaystyle="true">
+ <mfrac>
+ <mrow>
+ <mn>X</mn>
+ <mo id="mathOperator">+</mo>
+ <mfrac>
+ <mrow><mn>X</mn></mrow>
+ <mrow><mn>X</mn></mrow>
+ </mfrac>
+ </mrow>
+ <mrow>
+ <mn>X</mn>
+ </mrow>
+ </mfrac>
+ </mstyle>
+ </math>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-015-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-015-ref.html
new file mode 100644
index 0000000000..2e375c6886
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-015-ref.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>displaystyle and display</title>
+ </head>
+ <body>
+ <math>
+ <munderover>
+ <mo>∑</mo>
+ <mi>b</mi>
+ <mi>c</mi>
+ </munderover>
+ </math>
+ <math displaystyle="true">
+ <munderover>
+ <mo>∑</mo>
+ <mi>b</mi>
+ <mi>c</mi>
+ </munderover>
+ </math>
+ <math display="inline" displaystyle="true">
+ <munderover>
+ <mo>∑</mo>
+ <mi>b</mi>
+ <mi>c</mi>
+ </munderover>
+ </math>
+ <math display="block" displaystyle="true">
+ <munderover>
+ <mo>∑</mo>
+ <mi>b</mi>
+ <mi>c</mi>
+ </munderover>
+ </math>
+ <math displaystyle="false">
+ <munderover>
+ <mo>∑</mo>
+ <mi>b</mi>
+ <mi>c</mi>
+ </munderover>
+ </math>
+ <math display="inline" displaystyle="false">
+ <munderover>
+ <mo>∑</mo>
+ <mi>b</mi>
+ <mi>c</mi>
+ </munderover>
+ </math>
+ <math display="block" displaystyle="false">
+ <munderover>
+ <mo>∑</mo>
+ <mi>b</mi>
+ <mi>c</mi>
+ </munderover>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-015.html b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-015.html
new file mode 100644
index 0000000000..e4a747fb20
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-015.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>displaystyle and display</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#the-displaystyle-and-scriptlevel-attributes">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#style-change-mstyle">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#the-top-level-math-element">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#operator-dictionary">
+ <link rel="match" href="displaystyle-015-ref.html"/>
+ <meta name="assert" content="Test interaction of math@display and displaystyle on an operator with movablelimits">
+ </head>
+ <body>
+ <math>
+ <mstyle displaystyle="false">
+ <munderover>
+ <mo>∑</mo>
+ <mi>b</mi>
+ <mi>c</mi>
+ </munderover>
+ </mstyle>
+ </math>
+ <math>
+ <mstyle displaystyle="true">
+ <munderover>
+ <mo>∑</mo>
+ <mi>b</mi>
+ <mi>c</mi>
+ </munderover>
+ </mstyle>
+ </math>
+ <math display="inline">
+ <mstyle displaystyle="true">
+ <munderover>
+ <mo>∑</mo>
+ <mi>b</mi>
+ <mi>c</mi>
+ </munderover>
+ </mstyle>
+ </math>
+ <math display="block">
+ <mstyle displaystyle="true">
+ <munderover>
+ <mo>∑</mo>
+ <mi>b</mi>
+ <mi>c</mi>
+ </munderover>
+ </mstyle>
+ </math>
+ <math>
+ <mstyle displaystyle="false">
+ <munderover>
+ <mo>∑</mo>
+ <mi>b</mi>
+ <mi>c</mi>
+ </munderover>
+ </mstyle>
+ </math>
+ <math display="inline">
+ <mstyle displaystyle="false">
+ <munderover>
+ <mo>∑</mo>
+ <mi>b</mi>
+ <mi>c</mi>
+ </munderover>
+ </mstyle>
+ </math>
+ <math display="block">
+ <mstyle displaystyle="false">
+ <munderover>
+ <mo>∑</mo>
+ <mi>b</mi>
+ <mi>c</mi>
+ </munderover>
+ </mstyle>
+ </math>
+
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_movablelimits");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-1.html b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-1.html
new file mode 100644
index 0000000000..26aed81d03
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-1.html
@@ -0,0 +1,136 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>displaystyle</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-displaystyle-and-scriptlevel-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-math-style-property">
+<meta name="assert" content="Verify that the correct inheritance of the displaystyle value by measuring the size of large operators.">
+<style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/largeop-displayoperatorminheight5000.woff");
+ }
+ math {
+ font-family: TestFont;
+ font-size: 10px;
+ }
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/attribute-values.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script>
+ setup({ explicit_done: true });
+ var emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+ var epsilon = 5;
+ function verify_displaystyle(elementId, displaystyle, description) {
+ var expectedSize = (displaystyle ? 5000 : 1000) * emToPx;
+ var elementSize = document.getElementById(elementId).
+ getBoundingClientRect().height;
+ assert_approx_equals(elementSize, expectedSize, epsilon, description);
+ }
+
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ for (transform in AttributeValueTransforms) {
+ TransformAttributeValues(transform, ["display", "displaystyle"]);
+ test(function() {
+ verify_displaystyle("math_default", false, "default");
+ verify_displaystyle("math_false", false, "explicit displaystyle false");
+ verify_displaystyle("math_true", true, "explicit displaystyle true");
+ }, `math element (${transform})`);
+ test(function() {
+ verify_displaystyle("math_inline", false, "explicit display inline");
+ verify_displaystyle("math_block", true, "explicit display block");
+ verify_displaystyle("math_block_false", false, "explicit display block and displaystyle false");
+ verify_displaystyle("math_block_true", true, "explicit display block and displaystyle true");
+ verify_displaystyle("math_inline_false", false, "explicit display inline and displaystyle false");
+ verify_displaystyle("math_inline_true", true, "explicit display inline and displaystyle true");
+ }, `math element (explicit display, ${transform})`);
+ test(function() {
+ verify_displaystyle("mstyle_false", false, "explicit displaystyle false");
+ verify_displaystyle("mstyle_true", true, "explicit displaystyle true");
+ }, `mstyle element (${transform})`);
+ test(function() {
+ verify_displaystyle("mtable_default", false, "default");
+ verify_displaystyle("mtable_false", false, "explicit displaystyle false");
+ verify_displaystyle("mtable_true", true, "explicit displaystyle true");
+ }, `mtable element (${transform})`);
+ test(function() {
+ verify_displaystyle("mfrac_sibling", true, "sibling");
+ verify_displaystyle("mfrac_numerator", false, "numerator");
+ verify_displaystyle("mfrac_denominator", false, "denominator");
+ }, `mfrac element (${transform})`);
+ test(function() {
+ verify_displaystyle("mroot_base", true, "base");
+ verify_displaystyle("mroot_index", false, "index");
+ }, `mroot element (${transform})`);
+ test(function() {
+ verify_displaystyle("msub_base", true, "base");
+ verify_displaystyle("msub_subscript", false, "subscript");
+ }, `msub element (${transform})`);
+ test(function() {
+ verify_displaystyle("msup_base", true, "base");
+ verify_displaystyle("msup_supscript", false, "supscript");
+ }, `msup element (${transform})`);
+ test(function() {
+ verify_displaystyle("msubsup_base", true, "base");
+ verify_displaystyle("msubsup_subscript", false, "subscript");
+ verify_displaystyle("msubsup_supscript", false, "supscript");
+ }, `msubsup element (${transform})`);
+ test(function() {
+ verify_displaystyle("munder_base", true, "base");
+ verify_displaystyle("munder_underscript", false, "underscript");
+ }, `munder element (${transform})`);
+ test(function() {
+ verify_displaystyle("mover_base", true, "base");
+ verify_displaystyle("mover_overscript", false, "overscript");
+ }, `mover element (${transform})`);
+ test(function() {
+ verify_displaystyle("munderover_base", true, "base");
+ verify_displaystyle("munderover_underscript", false, "underscript");
+ verify_displaystyle("munderover_overscript", false, "overscript");
+ }, `munderover element (${transform})`);
+ }
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <math><mo id="math_default">&#x2AFF;</mo></math>
+ <math display="inline"><mo id="math_inline">&#x2AFF;</mo></math>
+ <math display="block"><mo id="math_block">&#x2AFF;</mo></math>
+ <math displaystyle="false"><mo id="math_false">&#x2AFF;</mo></math>
+ <math displaystyle="true"><mo id="math_true">&#x2AFF;</mo></math>
+ <math display="block" displaystyle="false">
+ <mo id="math_block_false">&#x2AFF;</mo>
+ </math>
+ <math display="block" displaystyle="true">
+ <mo id="math_block_true">&#x2AFF;</mo>
+ </math>
+ <math display="inline" displaystyle="false">
+ <mo id="math_inline_false">&#x2AFF;</mo>
+ </math>
+ <math display="inline" displaystyle="true">
+ <mo id="math_inline_true">&#x2AFF;</mo>
+ </math>
+ <math><mstyle displaystyle="false"><mo id="mstyle_false">&#x2AFF;</mo></mstyle></math>
+ <math><mstyle displaystyle="true"><mo id="mstyle_true">&#x2AFF;</mo></mstyle></math>
+ <math displaystyle="true"><mtable><mtr><mtd><mo id="mtable_default">&#x2AFF;</mo></mtd></mtr></mtable></math>
+ <math><mtable displaystyle="true"><mtr><mtd><mo id="mtable_true">&#x2AFF;</mo></mtd></mtr></mtable></math>
+ <math displaystyle="true"><mtable displaystyle="false"><mtr><mtd><mo id="mtable_false">&#x2AFF;</mo></mtd></mtr></mtable></math>
+ <math displaystyle="true"><mo id="mfrac_sibling">&#x2AFF;</mo><mfrac><mo id="mfrac_numerator">&#x2AFF;</mo><mo id="mfrac_denominator">&#x2AFF;</mo></mfrac></math>
+ <math displaystyle="true"><mroot><mo id="mroot_base">&#x2AFF;</mo><mo id="mroot_index">&#x2AFF;</mo></mroot></math>
+ <math displaystyle="true"><msub><mo id="msub_base">&#x2AFF;</mo><mo id="msub_subscript">&#x2AFF;</mo></msub></math>
+ <math displaystyle="true"><msup><mo id="msup_base">&#x2AFF;</mo><mo id="msup_supscript">&#x2AFF;</mo></msup></math>
+ <math displaystyle="true"><msubsup><mo id="msubsup_base">&#x2AFF;</mo><mo id="msubsup_subscript">&#x2AFF;</mo><mo id="msubsup_supscript">&#x2AFF;</mo></msubsup></math>
+ <math displaystyle="true"><mmultiscripts><mo id="mmultiscripts_base">&#x2AFF;</mo><mo id="mmultiscripts_subscript">&#x2AFF;</mo><mo id="mmultiscripts_supscript">&#x2AFF;</mo><mprescripts/><mo id="mmultiscripts_presubscript">&#x2AFF;</mo><mo id="mmultiscripts_presupscript">&#x2AFF;</mo></mmultiscripts></math>
+ <math displaystyle="true"><munder><mo id="munder_base">&#x2AFF;</mo><mo id="munder_underscript">&#x2AFF;</mo></munder></math>
+ <math displaystyle="true"><mover><mo id="mover_base">&#x2AFF;</mo><mo id="mover_overscript">&#x2AFF;</mo></mover></math>
+ <math displaystyle="true"><munderover><mo id="munderover_base">&#x2AFF;</mo><mo id="munderover_underscript">&#x2AFF;</mo><mo id="munderover_overscript">&#x2AFF;</mo></munderover></math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-2.html b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-2.html
new file mode 100644
index 0000000000..68566cfc25
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-2.html
@@ -0,0 +1,208 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>displaystyle</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-displaystyle-and-scriptlevel-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-math-style-property">
+<meta name="assert" content="Verify interaction between automatic displaystyle and specified displaystyle on descendants.">
+<style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/largeop-displayoperatorminheight5000.woff");
+ }
+ math, math * {
+ font-family: TestFont;
+ font-size: 10px;
+ }
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/attribute-values.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script>
+ setup({ explicit_done: true });
+ var emToPx = 10 / 1000; // font-size: 10px, font.em = 1000
+ var epsilon = 5;
+ function verify_displaystyle(elementId, displaystyle, description) {
+ var expectedSize = (displaystyle ? 5000 : 1000) * emToPx;
+ var elementSize = document.getElementById(elementId).
+ getBoundingClientRect().height;
+ assert_approx_equals(elementSize, expectedSize, epsilon, description);
+ }
+
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ for (transform in AttributeValueTransforms) {
+ TransformAttributeValues(transform, ["display", "displaystyle"]);
+ test(function() {
+ verify_displaystyle("cell_false", false, "cell with displaystyle false");
+ verify_displaystyle("cell_true", true, "cell with displaystyle true");
+ }, `mtable element (${transform})`);
+ test(function() {
+ verify_displaystyle("mfrac_numerator", true, "numerator");
+ verify_displaystyle("mfrac_denominator", true, "denominator");
+ }, `mfrac element (${transform})`);
+ test(function() {
+ verify_displaystyle("mroot_base", false, "base");
+ verify_displaystyle("mroot_index", true, "index");
+ }, `mroot element (${transform})`);
+ test(function() {
+ verify_displaystyle("msub_base", false, "base");
+ verify_displaystyle("msub_subscript", true, "subscript");
+ }, `msub element (${transform})`);
+ test(function() {
+ verify_displaystyle("msup_base", false, "base");
+ verify_displaystyle("msup_superscript", true, "superscript");
+ }, `msup element (${transform})`);
+ test(function() {
+ verify_displaystyle("msubsup_base", false, "base");
+ verify_displaystyle("msubsup_subscript", true, "subscript");
+ verify_displaystyle("msubsup_superscript", true, "superscript");
+ }, `msubsup element (${transform})`);
+ test(function() {
+ verify_displaystyle("munder_base", false, "base");
+ verify_displaystyle("munder_underscript", true, "underscript");
+ }, `munder element (${transform})`);
+ test(function() {
+ verify_displaystyle("mover_base", false, "base");
+ verify_displaystyle("mover_overscript", true, "overscript");
+ }, `mover element (${transform})`);
+ test(function() {
+ verify_displaystyle("munderover_base", false, "base");
+ verify_displaystyle("munderover_underscript", true, "underscript");
+ verify_displaystyle("munderover_overscript", true, "overscript");
+ }, `munderover element (${transform})`);
+ }
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <math displaystyle="true">
+ <mtable>
+ <mtr>
+ <mtd>
+ <mstyle displaystyle="false">
+ <mo id="cell_false">&#x2AFF;</mo>
+ </mstyle>
+ </mtd>
+ <mtd>
+ <mstyle displaystyle="true">
+ <mo id="cell_true">&#x2AFF;</mo>
+ </mstyle>
+ </mtd>
+ </mtr>
+ </mtable>
+ </math>
+ <math>
+ <mfrac>
+ <mstyle displaystyle="true">
+ <mo id="mfrac_numerator">&#x2AFF;</mo>
+ </mstyle>
+ <mstyle displaystyle="true">
+ <mo id="mfrac_denominator">&#x2AFF;</mo>
+ </mstyle>
+ </mfrac>
+ </math>
+ <math displaystyle="true">
+ <mroot>
+ <mstyle displaystyle="false">
+ <mo id="mroot_base">&#x2AFF;</mo>
+ </mstyle>
+ <mstyle displaystyle="true">
+ <mo id="mroot_index">&#x2AFF;</mo>
+ </mstyle>
+ </mroot>
+ </math>
+ <math displaystyle="true">
+ <msub>
+ <mstyle displaystyle="false">
+ <mo id="msub_base">&#x2AFF;</mo>
+ </mstyle>
+ <mstyle displaystyle="true">
+ <mo id="msub_subscript">&#x2AFF;</mo>
+ </mstyle>
+ </msub>
+ </math>
+ <math displaystyle="true">
+ <msup>
+ <mstyle displaystyle="false">
+ <mo id="msup_base">&#x2AFF;</mo>
+ </mstyle>
+ <mstyle displaystyle="true">
+ <mo id="msup_superscript">&#x2AFF;</mo>
+ </mstyle>
+ </msup>
+ </math>
+ <math displaystyle="true">
+ <msubsup>
+ <mstyle displaystyle="false">
+ <mo id="msubsup_base">&#x2AFF;</mo>
+ </mstyle>
+ <mstyle displaystyle="true">
+ <mo id="msubsup_subscript">&#x2AFF;</mo>
+ </mstyle>
+ <mstyle displaystyle="true">
+ <mo id="msubsup_superscript">&#x2AFF;</mo>
+ </mstyle>
+ </msubsup>
+ </math>
+ <math displaystyle="true">
+ <mmultiscripts>
+ <mstyle displaystyle="false">
+ <mo id="mmultiscripts_base">&#x2AFF;</mo>
+ </mstyle>
+ <mstyle displaystyle="true">
+ <mo id="mmultiscripts_subscript">&#x2AFF;</mo>
+ </mstyle>
+ <mstyle displaystyle="true">
+ <mo id="mmultiscripts_superscript">&#x2AFF;</mo>
+ </mstyle>
+ <mprescripts/>
+ <mstyle displaystyle="true">
+ <mo id="mmultiscripts_presubscript">&#x2AFF;</mo>
+ </mstyle>
+ <mstyle displaystyle="true">
+ <mo id="mmultiscripts_presuperscript">&#x2AFF;</mo>
+ </mstyle>
+ </mmultiscripts>
+ </math>
+ <math displaystyle="true">
+ <munder>
+ <mstyle displaystyle="false">
+ <mo id="munder_base">&#x2AFF;</mo>
+ </mstyle>
+ <mstyle displaystyle="true">
+ <mo id="munder_underscript">&#x2AFF;</mo>
+ </mstyle>
+ </munder>
+ </math>
+ <math displaystyle="true">
+ <mover>
+ <mstyle displaystyle="false">
+ <mo id="mover_base">&#x2AFF;</mo>
+ </mstyle>
+ <mstyle displaystyle="true">
+ <mo id="mover_overscript">&#x2AFF;</mo>
+ </mstyle>
+ </mover>
+ </math>
+ <math displaystyle="true">
+ <munderover>
+ <mstyle displaystyle="false">
+ <mo id="munderover_base">&#x2AFF;</mo>
+ </mstyle>
+ <mstyle displaystyle="true">
+ <mo id="munderover_underscript">&#x2AFF;</mo>
+ </mstyle>
+ <mstyle displaystyle="true">
+ <mo id="munderover_overscript">&#x2AFF;</mo>
+ </mstyle>
+ </munderover>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-3.html b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-3.html
new file mode 100644
index 0000000000..a5bcab2aaa
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/displaystyle-3.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>displaystyle</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-displaystyle-and-scriptlevel-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-math-style-property">
+<meta name="assert" content="Verify the displaystyle of the underover element is considered (not the one of its base) to determine whether to move limits.">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+ math, math * {
+ font-family: Ahem;
+ font-size: 20px;
+ }
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+ function runTests() {
+ ["munder", "mover", "munderover"].forEach((tag) => {
+ Array.from(document.getElementsByTagName(tag)).forEach(e => {
+ var displaystyle = e.getAttribute('displaystyle') === "true";
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_movablelimits());
+ var elementRight = e.getBoundingClientRect().right;
+ var baseRight = e.firstElementChild.getBoundingClientRect().right;
+ if (displaystyle)
+ assert_approx_equals(elementRight, baseRight, 1);
+ else
+ assert_greater_than(elementRight, baseRight + 10);
+ }, `movablelimits for ${tag} element (displaystyle=${displaystyle})`);
+ });
+ });
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <math>
+ <munder displaystyle="false">
+ <mo displaystyle="true" movablelimits="true">XX</mo>
+ <mtext>X</mtext>
+ </munder>
+ </math>
+ <math>
+ <mover displaystyle="false">
+ <mo displaystyle="true" movablelimits="true">XX</mo>
+ <mtext>X</mtext>
+ </mover>
+ </math>
+ <math>
+ <munderover displaystyle="false">
+ <mo displaystyle="true" movablelimits="true">XX</mo>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </munderover>
+ </math>
+ <math>
+ <munder displaystyle="true">
+ <mo displaystyle="false" movablelimits="true">XX</mo>
+ <mtext>X</mtext>
+ </munder>
+ </math>
+ <math>
+ <mover displaystyle="true">
+ <mo displaystyle="false" movablelimits="true">XX</mo>
+ <mtext>X</mtext>
+ </mover>
+ </math>
+ <math>
+ <munderover displaystyle="true">
+ <mo displaystyle="false" movablelimits="true">XX</mo>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </munderover>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/dynamic-dir-1-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/dynamic-dir-1-ref.html
new file mode 100644
index 0000000000..111ea79e24
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/dynamic-dir-1-ref.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test dynamically changing dir attribute</title>
+</head>
+<body>
+ <p>
+ math:
+ <math dir="rtl">
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </math>
+ <math dir="rtl">
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </math>
+ <math>
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </math>
+ </p>
+ <p>
+ mstyle:
+ <math>
+ <mstyle dir="rtl">
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </mstyle>
+ </math>
+ <math>
+ <mstyle dir="rtl">
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </mstyle>
+ </math>
+ <math>
+ <mstyle>
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </mstyle>
+ </math>
+ </p>
+ <p>
+ mrow:
+ <math>
+ <mrow dir="rtl">
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </mrow>
+ </math>
+ <math>
+ <mrow dir="rtl">
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </mrow>
+ </math>
+ <math>
+ <mrow>
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </mrow>
+ </math>
+ </p>
+</body>
+</html> \ No newline at end of file
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/dynamic-dir-1.html b/testing/web-platform/tests/mathml/relations/css-styling/dynamic-dir-1.html
new file mode 100644
index 0000000000..d97505eff1
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/dynamic-dir-1.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+ <meta charset="utf-8">
+ <title>Test dynamically changing dir attribute</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript">
+ <meta name="assert" content="The dir attribute should update direction map to css properties dynamically">
+ <link rel="match" href="dynamic-dir-1-ref.html">
+ <script>
+ window.addEventListener("load", () => {
+
+ // force initial layout so we're sure what we're testing against
+ document.documentElement.getBoundingClientRect();
+
+ ["math", "mstyle", "mrow"].forEach((tag) => {
+ let elements = document.getElementsByTagName(tag);
+
+ // set an explicit rtl where there was none
+ elements[0].setAttribute("dir", "rtl");
+
+ // change explicit ltr to rtl
+ elements[1].setAttribute("dir", "rtl");
+
+ // remove an explicitly set dir="rtl"
+ elements[2].removeAttribute("dir");
+
+ })
+
+ document.documentElement.classList.remove('reftest-wait');
+ })
+ </script>
+</head>
+<body>
+ <p>
+ math:
+ <math>
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </math>
+ <math dir="ltr">
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </math>
+ <math dir="rtl">
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </math>
+ </p>
+ <p>
+ mstyle:
+ <math>
+ <mstyle>
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </mstyle>
+ </math>
+ <math>
+ <mstyle dir="ltr">
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </mstyle>
+ </math>
+ <math>
+ <mstyle dir="rtl">
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </mstyle>
+ </math>
+ </p>
+ <p>
+ mrow:
+ <math>
+ <mrow>
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </mrow>
+ </math>
+ <math>
+ <mrow dir="ltr">
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </mrow>
+ </math>
+ <math>
+ <mrow dir="rtl">
+ <mi>a</mi>
+ <mi>b</mi>
+ <mi>c</mi>
+ </mrow>
+ </math>
+ </p>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_dir");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/floats/floating-inside-mathml-with-block-display-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/floats/floating-inside-mathml-with-block-display-ref.html
new file mode 100644
index 0000000000..8f25c9db06
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/floats/floating-inside-mathml-with-block-display-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>floating inside display: block MathML (reference)</title>
+</head>
+<body>
+ <p>Test passes if you see a blue square on the left and a smaller magenta square on the right.</p>
+ <div>
+ <div style="display: block">
+ <div style="display: inline-block; width: 50px; height: 50px; background: magenta"></div><div style="float: left; display: inline-block; width: 100px; height: 100px; background: blue"></div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/floats/floating-inside-mathml-with-block-display.html b/testing/web-platform/tests/mathml/relations/css-styling/floats/floating-inside-mathml-with-block-display.html
new file mode 100644
index 0000000000..f398094e15
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/floats/floating-inside-mathml-with-block-display.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>floating inside display: block MathML</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="match" href="floating-inside-mathml-with-block-display-ref.html"/>
+<meta name="assert" content="Verify that float works within a display: block MathML element.">
+</head>
+<body>
+ <p>Test passes if you see a blue square on the left and a smaller magenta square on the right.</p>
+ <math>
+ <mrow style="display: block">
+ <mspace style="display: inline-block; width: 50px; height: 50px; background: magenta"/><mspace style="float: left; display: inline-block; width: 100px; height: 100px; background: blue"/>
+ </mrow>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/floats/floating-math-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/floats/floating-math-ref.html
new file mode 100644
index 0000000000..c82f395644
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/floats/floating-math-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>floating math (reference)</title>
+</head>
+<body>
+ <p>Test passes if you see a blue square on the left and a smaller magenta square on the right.</p>
+ <div>
+ <div style="display: inline-block; width: 50px; height: 50px; background: magenta"></div>
+ <div style="float: left"><div style="width: 100px; height: 100px; background: blue"></div></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/floats/floating-math.html b/testing/web-platform/tests/mathml/relations/css-styling/floats/floating-math.html
new file mode 100644
index 0000000000..1de54ccdcf
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/floats/floating-math.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>floating math</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="match" href="floating-math-ref.html"/>
+<meta name="assert" content="Verify that float applies to the <math> element.">
+</head>
+<body>
+ <p>Test passes if you see a blue square on the left and a smaller magenta square on the right.</p>
+ <div>
+ <div style="display: inline-block; width: 50px; height: 50px; background: magenta"></div>
+ <math style="float: left"><mspace width="100px" height="100px" style="background: blue"/></math>
+ </div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/floats/not-floating-001.html b/testing/web-platform/tests/mathml/relations/css-styling/floats/not-floating-001.html
new file mode 100644
index 0000000000..7166dea5f8
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/floats/not-floating-001.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>float property in math layout</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#user-agent-stylesheet">
+<meta name="assert" content="Assert that float property is ignored for most math layout">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<script src="/mathml/support/layout-comparison.js"></script>
+<style>
+ /* .element class defined in mathml-fragments.js */
+ .element > * {
+ padding: 10px;
+ background: black;
+ }
+ /* override display: none on children of maction/semantics */
+ maction > *, semantics > * {
+ display: math;
+ }
+</style>
+</head>
+<body>
+ <div id="log"></div>
+ <div id="container"></div>
+
+ <script>
+ let container = document.getElementById("container");
+ for (tag in MathMLFragments) {
+ if (!FragmentHelper.isValidChildOfMrow(tag) ||
+ FragmentHelper.isEmpty(tag))
+ continue;
+
+ // Skip mtable since it does not use display: math.
+ if (tag == "mtable")
+ continue;
+
+ document.body.insertAdjacentHTML("beforeend", `<div style="position: absolute;">\
+<div style="display: inline-block"><math>${MathMLFragments[tag]}</math></div>\
+<div style="display: inline-block"><math>${MathMLFragments[tag]}</math></div>\
+</div>`);
+ let div = document.body.lastElementChild;
+ let element =
+ FragmentHelper.element(div.firstElementChild);
+ let reference =
+ FragmentHelper.element(div.lastElementChild);
+ [element, reference].forEach(parent => {
+ if (parent.classList.contains("mathml-container") ||
+ parent.classList.contains("foreign-container")) {
+ FragmentHelper.appendChild(parent);
+ FragmentHelper.appendChild(parent);
+ FragmentHelper.appendChild(parent);
+ }
+ });
+
+ // Try to use float to invert the order in which children are normally
+ // laid out.
+ function layoutChildrenFromLeftToRight(tag) { tag != 'mroot'; }
+ element.firstElementChild.style =
+ `float: ${layoutChildrenFromLeftToRight(tag) ? 'right' : 'left'};`;
+ element.lastElementChild.style =
+ `float: ${layoutChildrenFromLeftToRight(tag) ? 'left' : 'right'};`;
+
+ test(function () {
+ let epsilon = 1;
+ compareLayout(element, reference, epsilon);
+ }, `float child ignored in ${tag}`);
+
+ div.style = "display: none;"; // Hide the div after measurement.
+ }
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/ignored-properties-001.html b/testing/web-platform/tests/mathml/relations/css-styling/ignored-properties-001.html
new file mode 100644
index 0000000000..34de5836ea
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/ignored-properties-001.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Ignored CSS properties</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<meta name="assert" content="Verify style with ignored properties does not affect MathML layout.">
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/layout-comparison.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<script>
+ var epsilon = 1;
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+
+ for (tag in MathMLFragments) {
+ if (!FragmentHelper.isValidChildOfMrow(tag))
+ continue;
+
+ var ignoredProperties = [
+ "writing-mode: vertical-rl;",
+ "white-space: normal;",
+ "float: right;",
+ "align-content: end; justify-content: end;",
+ "align-self: end; justify-self: end;",
+ ];
+
+ ignoredProperties.forEach(ignoredStyle => {
+ document.body.insertAdjacentHTML("beforeend", `<div style="position: absolute;">\
+<div style="display: inline-block"><math>${MathMLFragments[tag]}</math></div>\
+<div style="display: inline-block"><math>${MathMLFragments[tag]}</math></div>\
+</div>`);
+ var div = document.body.lastElementChild;
+
+ // Create MathML structure with ignored style properties.
+ var elementContainer = div.firstElementChild;
+ var elementContainerWidth = elementContainer.getBoundingClientRect().width;
+ var element = FragmentHelper.element(elementContainer);
+ if (!FragmentHelper.isEmpty(tag))
+ FragmentHelper.forceNonEmptyDescendants(element);
+ element.setAttribute("style", ignoredStyle);
+ Array.from(element.getElementsByTagNameNS("*", FragmentHelper.mathml_namespace)).forEach(descendant => {
+ descendant.setAttribute("style", ignoredStyle);
+ });
+
+ var referenceContainer = div.lastElementChild;
+ var referenceContainerWidth = referenceContainer.getBoundingClientRect().width;
+ var reference = FragmentHelper.element(referenceContainer);
+ if (!FragmentHelper.isEmpty(tag))
+ FragmentHelper.forceNonEmptyDescendants(reference);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ assert_approx_equals(elementContainerWidth, referenceContainerWidth, epsilon);
+ }, `${tag} preferred width calculation is not affected by ${ignoredStyle}`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ compareLayout(element, reference, epsilon);
+ }, `${tag} layout is not affected by ${ignoredStyle}`);
+
+ div.style = "display: none;"; // Hide the div after measurement.
+ });
+ }
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/legacy-scriptminsize-attribute-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/legacy-scriptminsize-attribute-ref.html
new file mode 100644
index 0000000000..8e3d7b1c21
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/legacy-scriptminsize-attribute-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>legacy scriptminsize attribute (reference)</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ math {
+ /* Ahem font does not have a MATH table so the font-size scale factor
+ is always 0.71^{computed - inherited math script level} */
+ font: 100px/1 Ahem;
+ }
+</style>
+</head>
+<body>
+ <p>Test passes if you see a square of size 71px.</p>
+ <div>
+ <math>
+ <mstyle>
+ <mstyle scriptlevel="1">
+ <mn>X</mn>
+ </mstyle>
+ </mstyle>
+ </math>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/legacy-scriptminsize-attribute.html b/testing/web-platform/tests/mathml/relations/css-styling/legacy-scriptminsize-attribute.html
new file mode 100644
index 0000000000..0ce87b6147
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/legacy-scriptminsize-attribute.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>legacy scriptminsize attribute</title>
+<link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.mstyle.attrs">
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="match" href="legacy-scriptminsize-attribute-ref.html"/>
+<meta name="assert" content="Verify scriptminsize attribute is no longer parsed.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ math {
+ /* Ahem font does not have a MATH table so the font-size scale factor
+ is always 0.71^{computed - inherited math script level} */
+ font: 100px/1 Ahem;
+ }
+</style>
+</head>
+<body>
+ <p>Test passes if you see a square of size 71px.</p>
+ <div>
+ <math>
+ <mstyle scriptminsize="100px">
+ <mstyle scriptlevel="1">
+ <mn>X</mn>
+ </mstyle>
+ </mstyle>
+ </math>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/legacy-scriptsizemultiplier-attribute-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/legacy-scriptsizemultiplier-attribute-ref.html
new file mode 100644
index 0000000000..422325da28
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/legacy-scriptsizemultiplier-attribute-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>legacy scriptsizemultiplier attribute (reference)</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ math {
+ /* Ahem font does not have a MATH table so the font-size scale factor
+ is always 0.71^{computed - inherited math script level} */
+ font: 100px/1 Ahem;
+ }
+</style>
+</head>
+<body>
+ <p>Test passes if you see a square of size 71px.</p>
+ <div>
+ <math>
+ <mstyle>
+ <mstyle scriptlevel="1">
+ <mn>X</mn>
+ </mstyle>
+ </mstyle>
+ </math>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/legacy-scriptsizemultiplier-attribute.html b/testing/web-platform/tests/mathml/relations/css-styling/legacy-scriptsizemultiplier-attribute.html
new file mode 100644
index 0000000000..9a955612bc
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/legacy-scriptsizemultiplier-attribute.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>legacy scriptsizemultiplier attribute</title>
+<link rel="help" href="https://www.w3.org/TR/MathML3/chapter3.html#presm.mstyle.attrs">
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="match" href="legacy-scriptsizemultiplier-attribute-ref.html"/>
+<meta name="assert" content="Verify scriptsizemultiplier attribute is no longer parsed.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ math {
+ /* Ahem font does not have a MATH table so the font-size scale factor
+ is always 0.71^{computed - inherited math script level} */
+ font: 100px/1 Ahem;
+ }
+</style>
+</head>
+<body>
+ <p>Test passes if you see a square of size 71px.</p>
+ <div>
+ <math>
+ <mstyle scriptsizemultiplier="1">
+ <mstyle scriptlevel="1">
+ <mn>X</mn>
+ </mstyle>
+ </mstyle>
+ </math>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/lengths-1-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/lengths-1-ref.html
new file mode 100644
index 0000000000..9fca6f4963
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/lengths-1-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>MathML lengths (reference)</title>
+</head>
+<body>
+ <p>Test passes if there is a green square and no red.</p>
+ <div>
+ <div id="red" style="position: absolute; width: 200px; height: 200px; background: green;">
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/lengths-1.html b/testing/web-platform/tests/mathml/relations/css-styling/lengths-1.html
new file mode 100644
index 0000000000..896f08d111
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/lengths-1.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>MathML lengths</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#types-for-mathml-attribute-values">
+<link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#space-mspace">
+<link rel="match" href="lengths-1-ref.html"/>
+<meta name="assert" content="Verify whether the different units are accepted for MathML lengths.">
+<style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/xheight500.woff");
+ }
+ span, math {
+ font-family: TestFont;
+ font-size: 10px; /* 1em = 10px, 1ex is about 5px */
+ }
+ span {
+ position: absolute;
+ display: inline-block;
+ height: 10px;
+ }
+ #red > span {
+ background: red;
+ }
+ #green > span {
+ background: green;
+ }
+</style>
+</head>
+<body>
+ <p>Test passes if there is a green square and no red.</p>
+ <div>
+ <div id="red" style="position: absolute; width: 200px; height: 200px; background: green;">
+ <!-- px -->
+ <span style="top: 0px"><math><mspace width="200px"/></math></span>
+ <span style="top: 10px; width: 200px"></span>
+
+ <!-- cm -->
+ <span style="top: 20px"><math><mspace width="5.08cm"/></math></span>
+ <span style="top: 30px; width: 192px"></span>
+
+ <!-- em -->
+ <span style="top: 40px"><math><mspace width="20em"/></math></span>
+ <span style="top: 50px; width: 200px"></span>
+
+ <!-- ex -->
+ <span style="top: 60px"><math><mspace width="30ex"/></math></span>
+ <span style="top: 70px; width: 30ex"></span>
+
+ <!-- in -->
+ <span style="top: 80px"><math><mspace width="2in"/></math></span>
+ <span style="top: 90px; width: 192px"></span>
+
+ <!-- mm -->
+ <span style="top: 100px"><math><mspace width="50.8mm"/></math></span>
+ <span style="top: 110px; width: 192px"></span>
+
+ <!-- pc -->
+ <span style="top: 120px"><math><mspace width="12.5pc"/></math></span>
+ <span style="top: 130px; width: 200px"></span>
+
+ <!-- pt -->
+ <span style="top: 140px"><math><mspace width="150pt"/></math></span>
+ <span style="top: 150px; width: 200px"></span>
+
+ <!-- % -->
+ <span style="top: 160px"><math><mstyle mathsize="2000%"><mspace width="1em"/></mstyle></math></span>
+ <span style="top: 170px; width: 200px"></span>
+
+ <!-- unitless nonzero values should be ignored -->
+ <span style="top: 180px"><math><mstyle mathsize="20.0"><mspace width="1em"/></mstyle></math></span>
+ <span style="top: 190px; width: 10px"></span>
+ </div>
+
+ <div id="green" style="position: absolute; width: 200px; height: 200px;">
+ <!-- px -->
+ <span style="top: 10px"><math><mspace width="200px"/></math></span>
+ <span style="top: 0px; width: 200px"></span>
+
+ <!-- cm -->
+ <span style="top: 30px"><math><mspace width="5.08cm"/></math></span>
+ <span style="top: 20px; width: 192px"></span>
+
+ <!-- em -->
+ <span title="em" style="top: 50px"><math><mspace width="20em"/></math></span>
+ <span title="em" style="top: 40px; width: 200px"></span>
+
+ <!-- ex -->
+ <span title="ex" style="top: 70px"><math><mspace width="30ex"/></math></span>
+ <span title="ex" style="top: 60px; width: 30ex"></span>
+
+ <!-- in -->
+ <span style="top: 90px"><math><mspace width="2in"/></math></span>
+ <span style="top: 80px; width: 192px"></span>
+
+ <!-- mm -->
+ <span style="top: 110px"><math><mspace width="50.8mm"/></math></span>
+ <span style="top: 100px; width: 192px"></span>
+
+ <!-- pc -->
+ <span style="top: 130px"><math><mspace width="12.5pc"/></math></span>
+ <span style="top: 120px; width: 200px"></span>
+
+ <!-- pt -->
+ <span style="top: 150px"><math><mspace width="150pt"/></math></span>
+ <span style="top: 140px; width: 200px"></span>
+
+ <!-- % -->
+ <span style="top: 170px"><math><mstyle mathsize="2000%"><mspace width="1em"/></mstyle></math></span>
+ <span style="top: 160px; width: 200px"></span>
+
+ <!-- unitless nonzero values should be ignored -->
+ <span style="top: 190px"><math><mstyle mathsize="20.0"><mspace width="1em"/></mstyle></math></span>
+ <span style="top: 180px; width: 10px"></span>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/lengths-2.html b/testing/web-platform/tests/mathml/relations/css-styling/lengths-2.html
new file mode 100644
index 0000000000..942611a8da
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/lengths-2.html
@@ -0,0 +1,266 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>MathML lengths</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#types-for-mathml-attribute-values">
+<link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#space-mspace">
+<meta name="assert" content="Verify various cases of the MathML length syntax.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/xheight500.woff");
+ }
+ math {
+ font-family: TestFont;
+ font-size: 10px;
+ }
+</style>
+<script>
+ var epsilon = .5;
+
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_equals(getBox("unitCm").width, 96, "cm");
+ assert_equals(getBox("unitEm").width, 120, "em");
+ assert_equals(getBox("unitEx").width, 500, "ex");
+ assert_equals(getBox("unitIn").width, 288, "in");
+ assert_equals(getBox("unitMm").width, 576, "mm");
+ assert_equals(getBox("unitPc").width, 96, "pc");
+ assert_equals(getBox("unitPercentage").width, 60, "%");
+ assert_equals(getBox("unitPt").width, 96, "pt");
+ assert_equals(getBox("unitPx").width, 123, "px");
+ }, "Units");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_equals(getBox("spaceCm").width, 96, "cm");
+ assert_equals(getBox("spaceEm").width, 120, "em");
+ assert_equals(getBox("spaceEx").width, 500, "ex");
+ assert_equals(getBox("spaceIn").width, 288, "in");
+ assert_equals(getBox("spaceMm").width, 576, "mm");
+ assert_equals(getBox("spacePc").width, 96, "pc");
+ assert_equals(getBox("spacePercentage").width, 60, "%");
+ assert_equals(getBox("spacePt").width, 96, "pt");
+ assert_equals(getBox("spacePx").width, 123, "px");
+ }, "Trimming of space");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_approx_equals(getBox("n0").width, 0, epsilon, "n0");
+ assert_approx_equals(getBox("n1").width, 90, epsilon, "n1");
+ assert_approx_equals(getBox("n2").width, 8, epsilon, "n2");
+ assert_approx_equals(getBox("n4").width, 650, epsilon, "n4");
+ assert_approx_equals(getBox("n5").width, 4320, epsilon, "n5");
+ assert_approx_equals(getBox("n6").width, 1, epsilon, "n6");
+ assert_approx_equals(getBox("n7").width, 8, epsilon, "n7");
+ assert_approx_equals(getBox("n8").width, 65, epsilon, "n8");
+ assert_approx_equals(getBox("n9").width, 432, epsilon, "n9");
+ assert_approx_equals(getBox("n10").width, 123, epsilon, "n10");
+ }, "Non-negative numbers");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var topRef = getBox("ref").top;
+ assert_approx_equals(getBox("N0").top - topRef, -0, epsilon, "N0");
+ assert_approx_equals(topRef - getBox("N1").top, -90, epsilon, "N1");
+ assert_approx_equals(topRef - getBox("N2").top, -8, epsilon, "N2");
+ assert_approx_equals(topRef - getBox("N4").top, -650, epsilon, "N4");
+ assert_approx_equals(topRef - getBox("N5").top, -4320, epsilon, "N5");
+ assert_approx_equals(topRef - getBox("N6").top, -1, epsilon, "N6");
+ assert_approx_equals(topRef - getBox("N7").top, -8, epsilon, "N7");
+ assert_approx_equals(topRef - getBox("N8").top, -65, epsilon, "N8");
+ assert_approx_equals(topRef - getBox("N9").top, -432, epsilon, "N9");
+ assert_approx_equals(topRef - getBox("N10").top, -123, epsilon, "N10");
+ }, "Non-positive numbers");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ // Namedspace values are invalid in MathML Core.
+ ["veryverythinmathspace",
+ "verythinmathspace",
+ "thinmathspace",
+ "mediummathspace",
+ "thickmathspace",
+ "verythickmathspace",
+ "veryverythickmathspace",
+ "negativeveryverythinmathspace",
+ "negativeverythinmathspace",
+ "negativethinmathspace",
+ "negativemediummathspace",
+ "negativethickmathspace",
+ "negativeverythickmathspace",
+ "negativeveryverythickmathspace"
+ ].forEach(function(space) {
+ var mrow = document.getElementById(space);
+ var boxBefore = mrow.firstElementChild.getBoundingClientRect();
+ var boxAfter = mrow.lastElementChild.getBoundingClientRect();
+ assert_equals(boxAfter.left - boxBefore.right, 0, space);
+ });
+ }, "Legacy namedspaces");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ // These values are invalid in MathML Core.
+ assert_equals(getBox("unitNone").width, 30, "Unitless");
+ assert_approx_equals(getBox("n3").width, 0, epsilon, "n3");
+ var topRef = getBox("ref").top;
+ assert_approx_equals(topRef - getBox("N3").top, 0, epsilon, "N3");
+ }, "Legacy numbers");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mspace id="unitCm" width="2.54cm"/>
+ <mspace id="unitEm" width="12em"/>
+ <mspace id="unitEx" width="100ex"/>
+ <mspace id="unitIn" width="3in"/>
+ <mspace id="unitMm" width="152.4mm"/>
+ <mspace id="unitPc" width="6pc"/>
+ <mstyle mathsize="200%"><mspace id="unitPercentage" width="3em"/></mstyle>
+ <mspace id="unitPt" width="72pt"/>
+ <mspace id="unitPx" width="123px"/>
+ <mstyle mathsize="5"><mspace id="unitNone" width="3em"/></mstyle>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mspace id="spaceCm" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;2.54cm&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
+ <mspace id="spaceEm" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;12em&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
+ <mspace id="spaceEx" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;100ex&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
+ <mspace id="spaceIn" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;3in&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
+ <mspace id="spaceMm" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;152.4mm&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
+ <mspace id="spacePc" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;6pc&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
+ <mstyle mathsize="200%"><mspace id="spacePercentage" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;3em&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/></mstyle>
+ <mspace id="spacePt" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;72pt&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
+ <mspace id="spacePx" width="&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;123px&#x20;&#x9;&#xA;&#xD;&#x20;&#x9;&#xA;&#xD;"/>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mspace id="n0" width="0em"/>
+ <mspace id="n1" width="9em"/>
+ <mspace id="n2" width=".8em"/>
+ <mspace id="n3" width="7.em"/>
+ <mspace id="n4" width="65em"/>
+ <mspace id="n5" width="432em"/>
+ <mspace id="n6" width=".10em"/>
+ <mspace id="n7" width=".789em"/>
+ <mspace id="n8" width="6.5em"/>
+ <mspace id="n9" width="43.21em"/>
+ <mspace id="n10" width="012.345em"/>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mspace id="ref"></mspace>
+ <mpadded voffset="-0em"><mspace id="N0"/></mpadded>
+ <mpadded voffset="-9em"><mspace id="N1"/></mpadded>
+ <mpadded voffset="-.8em"><mspace id="N2"/></mpadded>
+ <mpadded voffset="-7.em"><mspace id="N3"/></mpadded>
+ <mpadded voffset="-65em"><mspace id="N4"/></mpadded>
+ <mpadded voffset="-432em"><mspace id="N5"/></mpadded>
+ <mpadded voffset="-.10em"><mspace id="N6"/></mpadded>
+ <mpadded voffset="-.789em"><mspace id="N7"/></mpadded>
+ <mpadded voffset="-6.5em"><mspace id="N8"/></mpadded>
+ <mpadded voffset="-43.21em"><mspace id="N9"/></mpadded>
+ <mpadded voffset="-012.345em"><mspace id="N10"/></mpadded>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow id="veryverythinmathspace">
+ <mspace width="1em"/>
+ <mspace width="veryverythinmathspace"/>
+ <mspace/>
+ </mrow>
+ <mrow id="verythinmathspace">
+ <mspace width="1em"/>
+ <mspace width="verythinmathspace"/>
+ <mspace/>
+ </mrow>
+ <mrow id="thinmathspace">
+ <mspace width="1em"/>
+ <mspace width="thinmathspace"/>
+ <mspace/>
+ </mrow>
+ <mrow id="mediummathspace">
+ <mspace width="1em"/>
+ <mspace width="mediummathspace"/>
+ <mspace/>
+ </mrow>
+ <mrow id="thickmathspace">
+ <mspace width="1em"/>
+ <mspace width="thickmathspace"/>
+ <mspace/>
+ </mrow>
+ <mrow id="verythickmathspace">
+ <mspace width="1em"/>
+ <mspace width="verythickmathspace"/>
+ <mspace/>
+ </mrow>
+ <mrow id="veryverythickmathspace">
+ <mspace width="1em"/>
+ <mspace width="veryverythickmathspace"/>
+ <mspace/>
+ </mrow>
+ </math>
+ <math>
+ <mrow id="negativeveryverythinmathspace">
+ <mspace width="1em"/>
+ <mspace width="veryverythinmathspace"/>
+ <mspace/>
+ </mrow>
+ <mrow id="negativeverythinmathspace">
+ <mspace width="1em"/>
+ <mspace width="verythinmathspace"/>
+ <mspace/>
+ </mrow>
+ <mrow id="negativethinmathspace">
+ <mspace width="1em"/>
+ <mspace width="thinmathspace"/>
+ <mspace/>
+ </mrow>
+ <mrow id="negativemediummathspace">
+ <mspace width="1em"/>
+ <mspace width="mediummathspace"/>
+ <mspace/>
+ </mrow>
+ <mrow id="negativethickmathspace">
+ <mspace width="1em"/>
+ <mspace width="thickmathspace"/>
+ <mspace/>
+ </mrow>
+ <mrow id="negativeverythickmathspace">
+ <mspace width="1em"/>
+ <mspace width="verythickmathspace"/>
+ <mspace/>
+ </mrow>
+ <mrow id="negativeveryverythickmathspace">
+ <mspace width="1em"/>
+ <mspace width="veryverythickmathspace"/>
+ <mspace/>
+ </mrow>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-001-notref.html b/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-001-notref.html
new file mode 100644
index 0000000000..65e2781c5e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-001-notref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mathbackground on mrow (reference)</title>
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow mathbackground="green">
+ <mtext>□■□■□■□</mtext>
+ </mrow>
+</math>
+
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-001.html b/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-001.html
new file mode 100644
index 0000000000..e71fc53eaa
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-001.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mathbackground on mrow</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="help" href="https://w3c.github.io/mathml-core/#horizontally-group-sub-expressions-mrow">
+<link rel="mismatch" href="mathbackground-001-notref.html"/>
+<meta name="assert" content="mathbackground on a mrow has a visual effect.">
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow mathbackground="red">
+ <mtext>□■□■□■□</mtext>
+ </mrow>
+</math>
+
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-002-notref.html b/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-002-notref.html
new file mode 100644
index 0000000000..8c984c2619
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-002-notref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mathbackground on mstyle (reference)</title>
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <mstyle mathbackground="green">
+ <mtext>□■□■□■□</mtext>
+ </mstyle>
+</math>
+
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-002.html b/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-002.html
new file mode 100644
index 0000000000..09407d9269
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-002.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mathbackground on mstyle</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="help" href="https://w3c.github.io/mathml-core/#style-change-mstyle">
+<link rel="mismatch" href="mathbackground-002-notref.html"/>
+<meta name="assert" content="mathbackground on a mstyle has a visual effect.">
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <mstyle mathbackground="red">
+ <mtext>□■□■□■□</mtext>
+ </mstyle>
+</math>
+
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-003-notref.html b/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-003-notref.html
new file mode 100644
index 0000000000..b6adaa8d4e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-003-notref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mathbackground on mtext (reference)</title>
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <mtext mathbackground="green">□■□■□■□</mtext>
+</math>
+
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-003.html b/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-003.html
new file mode 100644
index 0000000000..8cb11889db
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-003.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mathbackground on mtext</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="mismatch" href="mathbackground-003-notref.html"/>
+<meta name="assert" content="mathbackground on a mtext has a visual effect.">
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <mtext mathbackground="red">□■□■□■□</mtext>
+</math>
+
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-004-notref.html b/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-004-notref.html
new file mode 100644
index 0000000000..75465a6c38
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-004-notref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mathbackground on semantics (reference)</title>
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <semantics mathbackground="red">
+ <mtext>□■□■□■□</mtext>
+ </semantics>
+</math>
+
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-004.html b/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-004.html
new file mode 100644
index 0000000000..be174cdbde
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathbackground-004.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mathbackground on semantics</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="help" href="https://w3c.github.io/mathml-core/#semantics-and-presentation">
+<link rel="mismatch" href="mathbackground-004-notref.html"/>
+<meta name="assert" content="mathbackground on a semantics has a visual effect.">
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <semantics mathbackground="green">
+ <mtext>□■□■□■□</mtext>
+ </semantics>
+</math>
+
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-001-notref.html b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-001-notref.html
new file mode 100644
index 0000000000..9bc1ba5436
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-001-notref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mathcolor on mrow (reference)</title>
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow mathcolor="green">
+ <mtext>□■□■□■□</mtext>
+ </mrow>
+</math>
+
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-001.html b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-001.html
new file mode 100644
index 0000000000..2c463cac87
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-001.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mathcolor on mrow</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="help" href="https://w3c.github.io/mathml-core/#horizontally-group-sub-expressions-mrow">
+<link rel="mismatch" href="mathcolor-001-notref.html"/>
+<meta name="assert" content="mathcolor on a mrow has a visual effect.">
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <mrow mathcolor="red">
+ <mtext>□■□■□■□</mtext>
+ </mrow>
+</math>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-002-notref.html b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-002-notref.html
new file mode 100644
index 0000000000..5f9fd2bb9b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-002-notref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mathcolor on mstyle (reference)</title>
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <mstyle mathcolor="green">
+ <mtext>□■□■□■□</mtext>
+ </mstyle>
+</math>
+
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-002.html b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-002.html
new file mode 100644
index 0000000000..147d41b46d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-002.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mathcolor on mstyle</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="help" href="https://w3c.github.io/mathml-core/#style-change-mstyle">
+<link rel="mismatch" href="mathcolor-002-notref.html"/>
+<meta name="assert" content="mathcolor on a mstyle has a visual effect.">
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <mstyle mathcolor="red">
+ <mtext>□■□■□■□</mtext>
+ </mstyle>
+</math>
+
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-003-notref.html b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-003-notref.html
new file mode 100644
index 0000000000..11e018ebc1
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-003-notref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mathcolor on mtext (reference)</title>
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <mtext mathcolor="green">□■□■□■□</mtext>
+</math>
+
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-003.html b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-003.html
new file mode 100644
index 0000000000..5565b0d837
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-003.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mathcolor on mtext</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="mismatch" href="mathcolor-003-notref.html"/>
+<meta name="assert" content="mathcolor on a mtext has a visual effect.">
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <mtext mathcolor="red">□■□■□■□</mtext>
+</math>
+
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-004-notref.html b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-004-notref.html
new file mode 100644
index 0000000000..67a45249e5
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-004-notref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mathcolor on semantics (reference)</title>
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <semantics mathcolor="red">
+ <mtext>□■□■□■□</mtext>
+ </semantics>
+</math>
+
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-004.html b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-004.html
new file mode 100644
index 0000000000..3ea37fecdb
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-004.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>mathcolor on semantics</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="help" href="https://w3c.github.io/mathml-core/#semantics-and-presentation">
+<link rel="mismatch" href="mathcolor-004-notref.html"/>
+<meta name="assert" content="mathcolor on a semantics has a visual effect.">
+<math xmlns="http://www.w3.org/1998/Math/MathML">
+ <semantics mathcolor="green">
+ <mtext>□■□■□■□</mtext>
+ </semantics>
+</math>
+
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-mathbackground-css-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-mathbackground-css-ref.html
new file mode 100644
index 0000000000..682fa64233
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-mathbackground-css-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS color (reference)</title>
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+ math {
+ font-family: Ahem;
+ font-size: 20px;
+ }
+</style>
+</style>
+</head>
+<body>
+ <p>Test passes if you see a green rectangle:</p>
+ <p>
+ <math mathbackground="#0f0" mathcolor="#0f0">
+ <mtext>X X</mtext>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-mathbackground-css.html b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-mathbackground-css.html
new file mode 100644
index 0000000000..2f53215346
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathcolor-mathbackground-css.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS color</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#types-for-mathml-attribute-values">
+<link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+<link rel="match" href="mathcolor-mathbackground-css-ref.html"/>
+<link rel="stylesheet" href="/fonts/ahem.css">
+<meta name="assert" content="Verify that the mathcolor and mathbackground attributes use the CSS definition of colors.">
+<style>
+ math {
+ font-family: Ahem;
+ font-size: 20px;
+ }
+</style>
+</style>
+</head>
+<body>
+ <p>Test passes if you see a green rectangle:</p>
+ <p style="color: red">
+ <math mathbackground="rgb(0,255,0)" mathcolor="rgb(0,255,0)">
+ <mtext>X X</mtext>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-css-keywords-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-css-keywords-ref.html
new file mode 100644
index 0000000000..ebb12a6c6c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-css-keywords-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>mathsize and css keywords</title>
+ </head>
+ <body>
+ <p>Test passes if you see 14 "A" of equal size:</p>
+ <math>
+ <mtext>A</mtext>
+ <mtext>A</mtext>
+ <mtext>A</mtext>
+ <mtext>A</mtext>
+ <mtext>A</mtext>
+ <mtext>A</mtext>
+ <mtext>A</mtext>
+ <mtext>A</mtext>
+ <mtext>A</mtext>
+ <mtext>A</mtext>
+ <mtext>A</mtext>
+ <mtext>A</mtext>
+ <mtext>A</mtext>
+ <mtext>A</mtext>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-css-keywords.html b/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-css-keywords.html
new file mode 100644
index 0000000000..2daed4cdea
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-css-keywords.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>mathsize and css keywords</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+ <meta name="assert" content="Verify that CSS font-size keywords are invalid for the mathsize attribute.">
+ <link rel="match" href="mathsize-attribute-css-keywords-ref.html">
+ <script src="/mathml/support/feature-detection.js"></script>
+ </head>
+ <body>
+ <p>Test passes if you see 14 "A" of equal size:</p>
+ <math>
+ <mtext>A</mtext>
+ <mtext mathsize="xx-small">A</mtext>
+ <mtext mathsize="x-small">A</mtext>
+ <mtext mathsize="small">A</mtext>
+ <mtext mathsize="medium">A</mtext>
+ <mtext mathsize="large">A</mtext>
+ <mtext mathsize="x-large">A</mtext>
+ <mtext mathsize="xx-large">A</mtext>
+ <mtext mathsize="larger">A</mtext>
+ <mtext mathsize="smaller">A</mtext>
+ <mtext mathsize="xx-ſmall">A</mtext>
+ <mtext mathsize="x-ſmall">A</mtext>
+ <mtext mathsize="ſmall">A</mtext>
+ <mtext mathsize="ſmaller">A</mtext>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mathsize");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-legacy-values-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-legacy-values-ref.html
new file mode 100644
index 0000000000..687efa49be
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-legacy-values-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Legacy mathsize values</title>
+ </head>
+ <body>
+ <p>Test passes if you see four "A" of equal size:</p>
+ <math>
+ <mtext>A</mtext>
+ <mtext>A</mtext>
+ <mtext>A</mtext>
+ <mtext>A</mtext>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-legacy-values.html b/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-legacy-values.html
new file mode 100644
index 0000000000..aebf09f9b8
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-legacy-values.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Legacy mathsize values</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+ <meta name="assert" content="Verify that legacy values for mathsize have no effect.">
+ <link rel="match" href="mathsize-attribute-legacy-values-ref.html">
+ <script src="/mathml/support/feature-detection.js"></script>
+ </head>
+ <body>
+ <p>Test passes if you see four "A" of equal size:</p>
+ <math>
+ <mtext>A</mtext>
+ <mtext mathsize="small">A</mtext>
+ <mtext mathsize="medium">A</mtext>
+ <mtext mathsize="big">A</mtext>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mathsize");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-ref.html
new file mode 100644
index 0000000000..7a0450e51e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Verify mathsize attribute</title>
+ </head>
+ <body>
+
+ <!-- The style attribute should have the same effect as the mathsize
+ attribute. -->
+ <div>
+ <math>
+ <mi style="font-size: 200%;">x</mi>
+ <mi style="font-size: 3em;">x</mi>
+ </math>
+ </div>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute.html b/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute.html
new file mode 100644
index 0000000000..66bcb6dd25
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathsize-attribute.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Verify mathsize attribute</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+ <meta name="assert" content="Verify mathsize attribute values.">
+ <link rel="match" href="mathsize-attribute-ref.html">
+ </head>
+ <body>
+
+ <!-- This verifies the effect of the mathsize attribute. -->
+ <div>
+ <math>
+ <mi mathsize="200%">x</mi>
+ <mi mathsize="3em">x</mi>
+ </math>
+ </div>
+
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-auto-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-auto-ref.html
new file mode 100644
index 0000000000..105ba412e6
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-auto-ref.html
@@ -0,0 +1,139 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>mathvariant auto (reference)</title>
+<style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/mathvariant-italic.woff");
+ }
+ body > span {
+ padding: 10px;
+ }
+ span > span {
+ font-family: monospace;
+ font-size: 10px;
+ }
+ .testfont {
+ font-family: TestFont;
+ font-size: 10px;
+ }
+</style>
+<body>
+ <!-- Generated by mathml/tools/mathvariant.py; DO NOT EDIT. -->
+ <p>Test passes if all the equalities below are true.</p>
+ <span><math class="testfont"><mi>&#x1D434;</mi></math>=<span>1D434</span></span>
+ <span><math class="testfont"><mi>&#x1D435;</mi></math>=<span>1D435</span></span>
+ <span><math class="testfont"><mi>&#x1D436;</mi></math>=<span>1D436</span></span>
+ <span><math class="testfont"><mi>&#x1D437;</mi></math>=<span>1D437</span></span>
+ <span><math class="testfont"><mi>&#x1D438;</mi></math>=<span>1D438</span></span>
+ <span><math class="testfont"><mi>&#x1D439;</mi></math>=<span>1D439</span></span>
+ <span><math class="testfont"><mi>&#x1D43A;</mi></math>=<span>1D43A</span></span>
+ <span><math class="testfont"><mi>&#x1D43B;</mi></math>=<span>1D43B</span></span>
+ <span><math class="testfont"><mi>&#x1D43C;</mi></math>=<span>1D43C</span></span>
+ <span><math class="testfont"><mi>&#x1D43D;</mi></math>=<span>1D43D</span></span><br/>
+ <span><math class="testfont"><mi>&#x1D43E;</mi></math>=<span>1D43E</span></span>
+ <span><math class="testfont"><mi>&#x1D43F;</mi></math>=<span>1D43F</span></span>
+ <span><math class="testfont"><mi>&#x1D440;</mi></math>=<span>1D440</span></span>
+ <span><math class="testfont"><mi>&#x1D441;</mi></math>=<span>1D441</span></span>
+ <span><math class="testfont"><mi>&#x1D442;</mi></math>=<span>1D442</span></span>
+ <span><math class="testfont"><mi>&#x1D443;</mi></math>=<span>1D443</span></span>
+ <span><math class="testfont"><mi>&#x1D444;</mi></math>=<span>1D444</span></span>
+ <span><math class="testfont"><mi>&#x1D445;</mi></math>=<span>1D445</span></span>
+ <span><math class="testfont"><mi>&#x1D446;</mi></math>=<span>1D446</span></span>
+ <span><math class="testfont"><mi>&#x1D447;</mi></math>=<span>1D447</span></span><br/>
+ <span><math class="testfont"><mi>&#x1D448;</mi></math>=<span>1D448</span></span>
+ <span><math class="testfont"><mi>&#x1D449;</mi></math>=<span>1D449</span></span>
+ <span><math class="testfont"><mi>&#x1D44A;</mi></math>=<span>1D44A</span></span>
+ <span><math class="testfont"><mi>&#x1D44B;</mi></math>=<span>1D44B</span></span>
+ <span><math class="testfont"><mi>&#x1D44C;</mi></math>=<span>1D44C</span></span>
+ <span><math class="testfont"><mi>&#x1D44D;</mi></math>=<span>1D44D</span></span>
+ <span><math class="testfont"><mi>&#x1D44E;</mi></math>=<span>1D44E</span></span>
+ <span><math class="testfont"><mi>&#x1D44F;</mi></math>=<span>1D44F</span></span>
+ <span><math class="testfont"><mi>&#x1D450;</mi></math>=<span>1D450</span></span>
+ <span><math class="testfont"><mi>&#x1D451;</mi></math>=<span>1D451</span></span><br/>
+ <span><math class="testfont"><mi>&#x1D452;</mi></math>=<span>1D452</span></span>
+ <span><math class="testfont"><mi>&#x1D453;</mi></math>=<span>1D453</span></span>
+ <span><math class="testfont"><mi>&#x1D454;</mi></math>=<span>1D454</span></span>
+ <span><math class="testfont"><mi>&#x210E;</mi></math>=<span>0210E</span></span>
+ <span><math class="testfont"><mi>&#x1D456;</mi></math>=<span>1D456</span></span>
+ <span><math class="testfont"><mi>&#x1D457;</mi></math>=<span>1D457</span></span>
+ <span><math class="testfont"><mi>&#x1D458;</mi></math>=<span>1D458</span></span>
+ <span><math class="testfont"><mi>&#x1D459;</mi></math>=<span>1D459</span></span>
+ <span><math class="testfont"><mi>&#x1D45A;</mi></math>=<span>1D45A</span></span>
+ <span><math class="testfont"><mi>&#x1D45B;</mi></math>=<span>1D45B</span></span><br/>
+ <span><math class="testfont"><mi>&#x1D45C;</mi></math>=<span>1D45C</span></span>
+ <span><math class="testfont"><mi>&#x1D45D;</mi></math>=<span>1D45D</span></span>
+ <span><math class="testfont"><mi>&#x1D45E;</mi></math>=<span>1D45E</span></span>
+ <span><math class="testfont"><mi>&#x1D45F;</mi></math>=<span>1D45F</span></span>
+ <span><math class="testfont"><mi>&#x1D460;</mi></math>=<span>1D460</span></span>
+ <span><math class="testfont"><mi>&#x1D461;</mi></math>=<span>1D461</span></span>
+ <span><math class="testfont"><mi>&#x1D462;</mi></math>=<span>1D462</span></span>
+ <span><math class="testfont"><mi>&#x1D463;</mi></math>=<span>1D463</span></span>
+ <span><math class="testfont"><mi>&#x1D464;</mi></math>=<span>1D464</span></span>
+ <span><math class="testfont"><mi>&#x1D465;</mi></math>=<span>1D465</span></span><br/>
+ <span><math class="testfont"><mi>&#x1D466;</mi></math>=<span>1D466</span></span>
+ <span><math class="testfont"><mi>&#x1D467;</mi></math>=<span>1D467</span></span>
+ <span><math class="testfont"><mi>&#x1D6A4;</mi></math>=<span>1D6A4</span></span>
+ <span><math class="testfont"><mi>&#x1D6A5;</mi></math>=<span>1D6A5</span></span>
+ <span><math class="testfont"><mi>&#x1D6E2;</mi></math>=<span>1D6E2</span></span>
+ <span><math class="testfont"><mi>&#x1D6E3;</mi></math>=<span>1D6E3</span></span>
+ <span><math class="testfont"><mi>&#x1D6E4;</mi></math>=<span>1D6E4</span></span>
+ <span><math class="testfont"><mi>&#x1D6E5;</mi></math>=<span>1D6E5</span></span>
+ <span><math class="testfont"><mi>&#x1D6E6;</mi></math>=<span>1D6E6</span></span>
+ <span><math class="testfont"><mi>&#x1D6E7;</mi></math>=<span>1D6E7</span></span><br/>
+ <span><math class="testfont"><mi>&#x1D6E8;</mi></math>=<span>1D6E8</span></span>
+ <span><math class="testfont"><mi>&#x1D6E9;</mi></math>=<span>1D6E9</span></span>
+ <span><math class="testfont"><mi>&#x1D6EA;</mi></math>=<span>1D6EA</span></span>
+ <span><math class="testfont"><mi>&#x1D6EB;</mi></math>=<span>1D6EB</span></span>
+ <span><math class="testfont"><mi>&#x1D6EC;</mi></math>=<span>1D6EC</span></span>
+ <span><math class="testfont"><mi>&#x1D6ED;</mi></math>=<span>1D6ED</span></span>
+ <span><math class="testfont"><mi>&#x1D6EE;</mi></math>=<span>1D6EE</span></span>
+ <span><math class="testfont"><mi>&#x1D6EF;</mi></math>=<span>1D6EF</span></span>
+ <span><math class="testfont"><mi>&#x1D6F0;</mi></math>=<span>1D6F0</span></span>
+ <span><math class="testfont"><mi>&#x1D6F1;</mi></math>=<span>1D6F1</span></span><br/>
+ <span><math class="testfont"><mi>&#x1D6F2;</mi></math>=<span>1D6F2</span></span>
+ <span><math class="testfont"><mi>&#x1D6F3;</mi></math>=<span>1D6F3</span></span>
+ <span><math class="testfont"><mi>&#x1D6F4;</mi></math>=<span>1D6F4</span></span>
+ <span><math class="testfont"><mi>&#x1D6F5;</mi></math>=<span>1D6F5</span></span>
+ <span><math class="testfont"><mi>&#x1D6F6;</mi></math>=<span>1D6F6</span></span>
+ <span><math class="testfont"><mi>&#x1D6F7;</mi></math>=<span>1D6F7</span></span>
+ <span><math class="testfont"><mi>&#x1D6F8;</mi></math>=<span>1D6F8</span></span>
+ <span><math class="testfont"><mi>&#x1D6F9;</mi></math>=<span>1D6F9</span></span>
+ <span><math class="testfont"><mi>&#x1D6FA;</mi></math>=<span>1D6FA</span></span>
+ <span><math class="testfont"><mi>&#x1D6FB;</mi></math>=<span>1D6FB</span></span><br/>
+ <span><math class="testfont"><mi>&#x1D6FC;</mi></math>=<span>1D6FC</span></span>
+ <span><math class="testfont"><mi>&#x1D6FD;</mi></math>=<span>1D6FD</span></span>
+ <span><math class="testfont"><mi>&#x1D6FE;</mi></math>=<span>1D6FE</span></span>
+ <span><math class="testfont"><mi>&#x1D6FF;</mi></math>=<span>1D6FF</span></span>
+ <span><math class="testfont"><mi>&#x1D700;</mi></math>=<span>1D700</span></span>
+ <span><math class="testfont"><mi>&#x1D701;</mi></math>=<span>1D701</span></span>
+ <span><math class="testfont"><mi>&#x1D702;</mi></math>=<span>1D702</span></span>
+ <span><math class="testfont"><mi>&#x1D703;</mi></math>=<span>1D703</span></span>
+ <span><math class="testfont"><mi>&#x1D704;</mi></math>=<span>1D704</span></span>
+ <span><math class="testfont"><mi>&#x1D705;</mi></math>=<span>1D705</span></span><br/>
+ <span><math class="testfont"><mi>&#x1D706;</mi></math>=<span>1D706</span></span>
+ <span><math class="testfont"><mi>&#x1D707;</mi></math>=<span>1D707</span></span>
+ <span><math class="testfont"><mi>&#x1D708;</mi></math>=<span>1D708</span></span>
+ <span><math class="testfont"><mi>&#x1D709;</mi></math>=<span>1D709</span></span>
+ <span><math class="testfont"><mi>&#x1D70A;</mi></math>=<span>1D70A</span></span>
+ <span><math class="testfont"><mi>&#x1D70B;</mi></math>=<span>1D70B</span></span>
+ <span><math class="testfont"><mi>&#x1D70C;</mi></math>=<span>1D70C</span></span>
+ <span><math class="testfont"><mi>&#x1D70D;</mi></math>=<span>1D70D</span></span>
+ <span><math class="testfont"><mi>&#x1D70E;</mi></math>=<span>1D70E</span></span>
+ <span><math class="testfont"><mi>&#x1D70F;</mi></math>=<span>1D70F</span></span><br/>
+ <span><math class="testfont"><mi>&#x1D710;</mi></math>=<span>1D710</span></span>
+ <span><math class="testfont"><mi>&#x1D711;</mi></math>=<span>1D711</span></span>
+ <span><math class="testfont"><mi>&#x1D712;</mi></math>=<span>1D712</span></span>
+ <span><math class="testfont"><mi>&#x1D713;</mi></math>=<span>1D713</span></span>
+ <span><math class="testfont"><mi>&#x1D714;</mi></math>=<span>1D714</span></span>
+ <span><math class="testfont"><mi>&#x1D715;</mi></math>=<span>1D715</span></span>
+ <span><math class="testfont"><mi>&#x1D716;</mi></math>=<span>1D716</span></span>
+ <span><math class="testfont"><mi>&#x1D717;</mi></math>=<span>1D717</span></span>
+ <span><math class="testfont"><mi>&#x1D718;</mi></math>=<span>1D718</span></span>
+ <span><math class="testfont"><mi>&#x1D719;</mi></math>=<span>1D719</span></span><br/>
+ <span><math class="testfont"><mi>&#x1D71A;</mi></math>=<span>1D71A</span></span>
+ <span><math class="testfont"><mi>&#x1D71B;</mi></math>=<span>1D71B</span></span>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-auto.html b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-auto.html
new file mode 100644
index 0000000000..affb02f0c9
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-auto.html
@@ -0,0 +1,145 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>mathvariant auto</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-mathvariant-attribute">
+<link rel="help" href="https://w3c.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://w3c.github.io/mathml-core/#italic-mappings">
+<link rel="match" href="mathvariant-auto-ref.html"/>
+<meta name="assert" content="Verify that a single-char <mi> is equivalent to an <mi> with the transformed italic unicode character.">
+<style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/mathvariant-italic.woff");
+ }
+ body > span {
+ padding: 10px;
+ }
+ span > span {
+ font-family: monospace;
+ font-size: 10px;
+ }
+ .testfont {
+ font-family: TestFont;
+ font-size: 10px;
+ }
+</style>
+<body>
+ <!-- Generated by mathml/tools/mathvariant.py; DO NOT EDIT. -->
+ <p>Test passes if all the equalities below are true.</p>
+ <span><math class="testfont"><mi>&#x41;</mi></math>=<span>1D434</span></span>
+ <span><math class="testfont"><mi>&#x42;</mi></math>=<span>1D435</span></span>
+ <span><math class="testfont"><mi>&#x43;</mi></math>=<span>1D436</span></span>
+ <span><math class="testfont"><mi>&#x44;</mi></math>=<span>1D437</span></span>
+ <span><math class="testfont"><mi>&#x45;</mi></math>=<span>1D438</span></span>
+ <span><math class="testfont"><mi>&#x46;</mi></math>=<span>1D439</span></span>
+ <span><math class="testfont"><mi>&#x47;</mi></math>=<span>1D43A</span></span>
+ <span><math class="testfont"><mi>&#x48;</mi></math>=<span>1D43B</span></span>
+ <span><math class="testfont"><mi>&#x49;</mi></math>=<span>1D43C</span></span>
+ <span><math class="testfont"><mi>&#x4A;</mi></math>=<span>1D43D</span></span><br/>
+ <span><math class="testfont"><mi>&#x4B;</mi></math>=<span>1D43E</span></span>
+ <span><math class="testfont"><mi>&#x4C;</mi></math>=<span>1D43F</span></span>
+ <span><math class="testfont"><mi>&#x4D;</mi></math>=<span>1D440</span></span>
+ <span><math class="testfont"><mi>&#x4E;</mi></math>=<span>1D441</span></span>
+ <span><math class="testfont"><mi>&#x4F;</mi></math>=<span>1D442</span></span>
+ <span><math class="testfont"><mi>&#x50;</mi></math>=<span>1D443</span></span>
+ <span><math class="testfont"><mi>&#x51;</mi></math>=<span>1D444</span></span>
+ <span><math class="testfont"><mi>&#x52;</mi></math>=<span>1D445</span></span>
+ <span><math class="testfont"><mi>&#x53;</mi></math>=<span>1D446</span></span>
+ <span><math class="testfont"><mi>&#x54;</mi></math>=<span>1D447</span></span><br/>
+ <span><math class="testfont"><mi>&#x55;</mi></math>=<span>1D448</span></span>
+ <span><math class="testfont"><mi>&#x56;</mi></math>=<span>1D449</span></span>
+ <span><math class="testfont"><mi>&#x57;</mi></math>=<span>1D44A</span></span>
+ <span><math class="testfont"><mi>&#x58;</mi></math>=<span>1D44B</span></span>
+ <span><math class="testfont"><mi>&#x59;</mi></math>=<span>1D44C</span></span>
+ <span><math class="testfont"><mi>&#x5A;</mi></math>=<span>1D44D</span></span>
+ <span><math class="testfont"><mi>&#x61;</mi></math>=<span>1D44E</span></span>
+ <span><math class="testfont"><mi>&#x62;</mi></math>=<span>1D44F</span></span>
+ <span><math class="testfont"><mi>&#x63;</mi></math>=<span>1D450</span></span>
+ <span><math class="testfont"><mi>&#x64;</mi></math>=<span>1D451</span></span><br/>
+ <span><math class="testfont"><mi>&#x65;</mi></math>=<span>1D452</span></span>
+ <span><math class="testfont"><mi>&#x66;</mi></math>=<span>1D453</span></span>
+ <span><math class="testfont"><mi>&#x67;</mi></math>=<span>1D454</span></span>
+ <span><math class="testfont"><mi>&#x68;</mi></math>=<span>0210E</span></span>
+ <span><math class="testfont"><mi>&#x69;</mi></math>=<span>1D456</span></span>
+ <span><math class="testfont"><mi>&#x6A;</mi></math>=<span>1D457</span></span>
+ <span><math class="testfont"><mi>&#x6B;</mi></math>=<span>1D458</span></span>
+ <span><math class="testfont"><mi>&#x6C;</mi></math>=<span>1D459</span></span>
+ <span><math class="testfont"><mi>&#x6D;</mi></math>=<span>1D45A</span></span>
+ <span><math class="testfont"><mi>&#x6E;</mi></math>=<span>1D45B</span></span><br/>
+ <span><math class="testfont"><mi>&#x6F;</mi></math>=<span>1D45C</span></span>
+ <span><math class="testfont"><mi>&#x70;</mi></math>=<span>1D45D</span></span>
+ <span><math class="testfont"><mi>&#x71;</mi></math>=<span>1D45E</span></span>
+ <span><math class="testfont"><mi>&#x72;</mi></math>=<span>1D45F</span></span>
+ <span><math class="testfont"><mi>&#x73;</mi></math>=<span>1D460</span></span>
+ <span><math class="testfont"><mi>&#x74;</mi></math>=<span>1D461</span></span>
+ <span><math class="testfont"><mi>&#x75;</mi></math>=<span>1D462</span></span>
+ <span><math class="testfont"><mi>&#x76;</mi></math>=<span>1D463</span></span>
+ <span><math class="testfont"><mi>&#x77;</mi></math>=<span>1D464</span></span>
+ <span><math class="testfont"><mi>&#x78;</mi></math>=<span>1D465</span></span><br/>
+ <span><math class="testfont"><mi>&#x79;</mi></math>=<span>1D466</span></span>
+ <span><math class="testfont"><mi>&#x7A;</mi></math>=<span>1D467</span></span>
+ <span><math class="testfont"><mi>&#x131;</mi></math>=<span>1D6A4</span></span>
+ <span><math class="testfont"><mi>&#x237;</mi></math>=<span>1D6A5</span></span>
+ <span><math class="testfont"><mi>&#x391;</mi></math>=<span>1D6E2</span></span>
+ <span><math class="testfont"><mi>&#x392;</mi></math>=<span>1D6E3</span></span>
+ <span><math class="testfont"><mi>&#x393;</mi></math>=<span>1D6E4</span></span>
+ <span><math class="testfont"><mi>&#x394;</mi></math>=<span>1D6E5</span></span>
+ <span><math class="testfont"><mi>&#x395;</mi></math>=<span>1D6E6</span></span>
+ <span><math class="testfont"><mi>&#x396;</mi></math>=<span>1D6E7</span></span><br/>
+ <span><math class="testfont"><mi>&#x397;</mi></math>=<span>1D6E8</span></span>
+ <span><math class="testfont"><mi>&#x398;</mi></math>=<span>1D6E9</span></span>
+ <span><math class="testfont"><mi>&#x399;</mi></math>=<span>1D6EA</span></span>
+ <span><math class="testfont"><mi>&#x39A;</mi></math>=<span>1D6EB</span></span>
+ <span><math class="testfont"><mi>&#x39B;</mi></math>=<span>1D6EC</span></span>
+ <span><math class="testfont"><mi>&#x39C;</mi></math>=<span>1D6ED</span></span>
+ <span><math class="testfont"><mi>&#x39D;</mi></math>=<span>1D6EE</span></span>
+ <span><math class="testfont"><mi>&#x39E;</mi></math>=<span>1D6EF</span></span>
+ <span><math class="testfont"><mi>&#x39F;</mi></math>=<span>1D6F0</span></span>
+ <span><math class="testfont"><mi>&#x3A0;</mi></math>=<span>1D6F1</span></span><br/>
+ <span><math class="testfont"><mi>&#x3A1;</mi></math>=<span>1D6F2</span></span>
+ <span><math class="testfont"><mi>&#x3F4;</mi></math>=<span>1D6F3</span></span>
+ <span><math class="testfont"><mi>&#x3A3;</mi></math>=<span>1D6F4</span></span>
+ <span><math class="testfont"><mi>&#x3A4;</mi></math>=<span>1D6F5</span></span>
+ <span><math class="testfont"><mi>&#x3A5;</mi></math>=<span>1D6F6</span></span>
+ <span><math class="testfont"><mi>&#x3A6;</mi></math>=<span>1D6F7</span></span>
+ <span><math class="testfont"><mi>&#x3A7;</mi></math>=<span>1D6F8</span></span>
+ <span><math class="testfont"><mi>&#x3A8;</mi></math>=<span>1D6F9</span></span>
+ <span><math class="testfont"><mi>&#x3A9;</mi></math>=<span>1D6FA</span></span>
+ <span><math class="testfont"><mi>&#x2207;</mi></math>=<span>1D6FB</span></span><br/>
+ <span><math class="testfont"><mi>&#x3B1;</mi></math>=<span>1D6FC</span></span>
+ <span><math class="testfont"><mi>&#x3B2;</mi></math>=<span>1D6FD</span></span>
+ <span><math class="testfont"><mi>&#x3B3;</mi></math>=<span>1D6FE</span></span>
+ <span><math class="testfont"><mi>&#x3B4;</mi></math>=<span>1D6FF</span></span>
+ <span><math class="testfont"><mi>&#x3B5;</mi></math>=<span>1D700</span></span>
+ <span><math class="testfont"><mi>&#x3B6;</mi></math>=<span>1D701</span></span>
+ <span><math class="testfont"><mi>&#x3B7;</mi></math>=<span>1D702</span></span>
+ <span><math class="testfont"><mi>&#x3B8;</mi></math>=<span>1D703</span></span>
+ <span><math class="testfont"><mi>&#x3B9;</mi></math>=<span>1D704</span></span>
+ <span><math class="testfont"><mi>&#x3BA;</mi></math>=<span>1D705</span></span><br/>
+ <span><math class="testfont"><mi>&#x3BB;</mi></math>=<span>1D706</span></span>
+ <span><math class="testfont"><mi>&#x3BC;</mi></math>=<span>1D707</span></span>
+ <span><math class="testfont"><mi>&#x3BD;</mi></math>=<span>1D708</span></span>
+ <span><math class="testfont"><mi>&#x3BE;</mi></math>=<span>1D709</span></span>
+ <span><math class="testfont"><mi>&#x3BF;</mi></math>=<span>1D70A</span></span>
+ <span><math class="testfont"><mi>&#x3C0;</mi></math>=<span>1D70B</span></span>
+ <span><math class="testfont"><mi>&#x3C1;</mi></math>=<span>1D70C</span></span>
+ <span><math class="testfont"><mi>&#x3C2;</mi></math>=<span>1D70D</span></span>
+ <span><math class="testfont"><mi>&#x3C3;</mi></math>=<span>1D70E</span></span>
+ <span><math class="testfont"><mi>&#x3C4;</mi></math>=<span>1D70F</span></span><br/>
+ <span><math class="testfont"><mi>&#x3C5;</mi></math>=<span>1D710</span></span>
+ <span><math class="testfont"><mi>&#x3C6;</mi></math>=<span>1D711</span></span>
+ <span><math class="testfont"><mi>&#x3C7;</mi></math>=<span>1D712</span></span>
+ <span><math class="testfont"><mi>&#x3C8;</mi></math>=<span>1D713</span></span>
+ <span><math class="testfont"><mi>&#x3C9;</mi></math>=<span>1D714</span></span>
+ <span><math class="testfont"><mi>&#x2202;</mi></math>=<span>1D715</span></span>
+ <span><math class="testfont"><mi>&#x3F5;</mi></math>=<span>1D716</span></span>
+ <span><math class="testfont"><mi>&#x3D1;</mi></math>=<span>1D717</span></span>
+ <span><math class="testfont"><mi>&#x3F0;</mi></math>=<span>1D718</span></span>
+ <span><math class="testfont"><mi>&#x3D5;</mi></math>=<span>1D719</span></span><br/>
+ <span><math class="testfont"><mi>&#x3F1;</mi></math>=<span>1D71A</span></span>
+ <span><math class="testfont"><mi>&#x3D6;</mi></math>=<span>1D71B</span></span>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-font-style-font-weight-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-font-style-font-weight-ref.html
new file mode 100644
index 0000000000..c3e586f4dd
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-font-style-font-weight-ref.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>mathvariant attribute and font-style/font-weight (reference)</title>
+ <style>
+ .italic { font-style: italic; }
+ .bold { font-weight: bold; }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if you see six lines of text (italic, italic, bold, bold, bold italic and bold italic) with the corresponding style applied:</p>
+ <p>
+ <math>
+ <mtext class="italic">italic</mtext>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtext class="italic">italic</mtext>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtext class="bold">bold</mtext>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtext class="bold">bold</mtext>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtext class="bold italic">bold italic</mtext>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtext class="bold italic">bold italic</mtext>
+ </math>
+ </p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-font-style-font-weight.html b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-font-style-font-weight.html
new file mode 100644
index 0000000000..793c687b09
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mathvariant-font-style-font-weight.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>mathvariant attribute and font-style/font-weight</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#the-mathvariant-attribute">
+ <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1788645">
+ <link rel="match" href="mathvariant-font-style-font-weight-ref.html"/>
+ <meta name="assert" content="Verify that a mathvariant attribute does not cancel the effect of font-style/font-weight.">
+ <style>
+ .italic { font-style: italic; }
+ .bold { font-weight: bold; }
+ </style>
+ </head>
+ <body>
+ <p>This test passes if you see six lines of text (italic, italic, bold, bold, bold italic and bold italic) with the corresponding style applied:</p>
+ <p>
+ <math mathvariant="normal">
+ <mtext class="italic">italic</mtext>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtext mathvariant="normal" class="italic">italic</mtext>
+ </math>
+ </p>
+ <p>
+ <math mathvariant="normal">
+ <mtext class="bold">bold</mtext>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtext mathvariant="normal" class="bold">bold</mtext>
+ </math>
+ </p>
+ <p>
+ <math mathvariant="normal">
+ <mtext class="bold italic">bold italic</mtext>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mtext mathvariant="normal" class="bold italic">bold italic</mtext>
+ </math>
+ </p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mi-fontstyle-fontweight-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/mi-fontstyle-fontweight-ref.html
new file mode 100644
index 0000000000..63e6e2ba9c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mi-fontstyle-fontweight-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>single-char mi and fontstyle/fontweight attributes (reference)</title>
+ <style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/mathvariant-italic.woff");
+ }
+ .testfont {
+ font-family: TestFont;
+ font-size: 32px;
+ }
+ </style>
+ </head>
+ <body>
+ <p>Test passes if you see <span class="testfont">&#x1D715;</span> rendered twice, without any bold or italic style applied:</p>
+ <p><math class="testfont"><mi mathvariant="normal">&#x1D715;</mi></math></p>
+ <p><math class="testfont"><mi mathvariant="normal">&#x1D715;</mi></math></p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/mi-fontstyle-fontweight.html b/testing/web-platform/tests/mathml/relations/css-styling/mi-fontstyle-fontweight.html
new file mode 100644
index 0000000000..b6dd05ea20
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/mi-fontstyle-fontweight.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>single-char mi and fontstyle/fontweight attributes</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+ <link rel="help" href="https://w3c.github.io/mathml-core/#the-mathvariant-attribute">
+ <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1789081">
+ <link rel="match" href="mi-fontstyle-fontweight-ref.html"/>
+ <meta name="assert" content="Verify that fontstyle/fontweight don't cancel the mathvariant transform on single-char mi elements.">
+ <style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/mathvariant-italic.woff");
+ }
+ .testfont {
+ font-family: TestFont;
+ font-size: 32px;
+ }
+ </style>
+ </head>
+ <body>
+ <p>Test passes if you see <span class="testfont">&#x1D715;</span> rendered twice, without any bold or italic style applied:</p>
+ <p><math class="testfont"><mi fontweight="bold">&#x2202;</mi></math></p>
+ <p><math class="testfont"><mi fontstyle="normal">&#x2202;</mi></math></p>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/multi-column-layout.html b/testing/web-platform/tests/mathml/relations/css-styling/multi-column-layout.html
new file mode 100644
index 0000000000..88db5047e9
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/multi-column-layout.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>MathML inside multi-column</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#html-and-svg">
+<meta name="assert" content="Verify that putting MathML inside a multi-column list shouldn't affect its layout.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("DOMContentLoaded", function() {
+ var epsilon = 1;
+ var mfrac = document.getElementById("mfrac");
+ var num = mfrac.firstElementChild.getBoundingClientRect();
+ var denom = mfrac.lastElementChild.getBoundingClientRect();
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_approx_equals(num.width, 30, epsilon, "numerator width");
+ assert_approx_equals(num.height, 40, epsilon, "numerator height");
+ assert_approx_equals(denom.width, 50, epsilon, "numerator width");
+ assert_approx_equals(denom.height, 60, epsilon, "numerator height");
+ }, "mspace layout in multicol");
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mfrac());
+ assert_greater_than_equal(denom.bottom - num.top,
+ (40 + 60),
+ "numerator is above the denominator");
+ assert_approx_equals((num.left + num.right) / 2,
+ (denom.left + denom.right) / 2,
+ epsilon, "numerator and denominator are horizontally aligned");
+ }, "mfrac layout in multicol");
+ done();
+ });
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <div style="column-width: 10em; list-style-type: decimal;">
+ <ol>
+ <li>blah</li>
+ <li>
+ <math>
+ <mfrac id="mfrac">
+ <mspace width="30px" height="40px" style="background: cyan"></mspace>
+ <mspace width="50px" height="60px" style="background: yellow"></mspace>
+ </mfrac>
+ </li>
+ <li>blah</li>
+ <li>blah</li>
+ <li>blah</li>
+ </ol>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/not-participating-to-parent-layout.html b/testing/web-platform/tests/mathml/relations/css-styling/not-participating-to-parent-layout.html
new file mode 100644
index 0000000000..0952679c62
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/not-participating-to-parent-layout.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Elements not participating to the layout of their parent</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<meta name="assert" content="Verify that display: none and out-of-flow positioned elements do not participate to layout of their parent.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/layout-comparison.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<script>
+ var epsilon = 1;
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+
+ for (tag in MathMLFragments) {
+ if (!FragmentHelper.isValidChildOfMrow(tag) ||
+ FragmentHelper.isEmpty(tag))
+ continue;
+ ["display: none",
+ "display: contents",
+ "position: absolute",
+ "position: fixed"
+ ].forEach(style => {
+ document.body.insertAdjacentHTML("beforeend", `<div style="position: absolute;">\
+<div style="display: inline-block"><math>${MathMLFragments[tag]}</math></div>\
+<div style="display: inline-block"><math>${MathMLFragments[tag]}</math></div>\
+</div>`);
+ var div = document.body.lastElementChild;
+
+ var elementContainer = div.firstElementChild;
+ var elementContainerWidth = elementContainer.getBoundingClientRect().width;
+ var element = FragmentHelper.element(elementContainer);
+ if (style === "display: contents" &&
+ !element.classList.contains("mathml-container")) {
+ // A "display: contents" MathML child is not participating to
+ // parent layout because its computed style is "display: none".
+ // If we cannot append a MathML child then skip that test.
+ return;
+ }
+ FragmentHelper.forceNonEmptyElement(element);
+ var allowInvalid = true;
+ var child = FragmentHelper.appendChild(element, allowInvalid);
+ child.setAttribute("style", style);
+
+ var referenceContainer = div.lastElementChild;
+ var referenceContainerWidth = referenceContainer.getBoundingClientRect().width;
+ var reference = FragmentHelper.element(referenceContainer);
+ FragmentHelper.forceNonEmptyElement(reference);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ assert_approx_equals(elementContainerWidth, referenceContainerWidth, epsilon);
+ }, `${tag} preferred width calculation is not affected by children with "${style}" style`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ compareLayout(element, reference, epsilon);
+ }, `${tag} layout is not affected by children with "${style}" style`);
+
+ div.style = "display: none;"; // Hide the div after measurement.
+ });
+ }
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/absolutely-positioned-001-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/absolutely-positioned-001-ref.html
new file mode 100644
index 0000000000..447c5b722a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/absolutely-positioned-001-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Absolutely positioned (reference)</title>
+<body>
+ <p>Test passes if you see a green square and no red.</p>
+ <div style="position: absolute; left: 100px; top: 100px;">
+ <math>
+ <mrow>
+ <mspace width="100px" height="300px" style="background: green"/>
+ <mspace width="100px" height="300px" style="background: green"/>
+ <mspace width="100px" height="300px" style="background: green"/>
+ </mrow>
+ </math>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/absolutely-positioned-001.html b/testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/absolutely-positioned-001.html
new file mode 100644
index 0000000000..9a7851ba23
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/absolutely-positioned-001.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Absolutely positioned</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-mrow">
+<link rel="match" href="absolutely-positioned-001-ref.html"/>
+<meta name="assert" content="Verify visual rendering of absolutely positioned mtext elements.">
+<body>
+ <p>Test passes if you see a green square and no red.</p>
+ <div style="position: absolute; left: 100px; top: 100px;">
+ <math>
+ <mrow>
+ <mspace width="100px" height="300px" style="background: green"/>
+ <mspace width="100px" height="300px" style="background: red"/>
+ <mspace width="100px" height="300px" style="background: green"/>
+ <mtext style="position: absolute; left: 100px; top: 0px;"><span style="display: inline-block; width: 50px; height: 300px; background: green"></span></mtext>
+ <mtext style="position: absolute; left: 150px; top: 0px;"><span style="display: inline-block; width: 50px; height: 150px; background: green"></span></mtext>
+ <mtext style="position: absolute; left: 150px; top: 150px;"><span style="display: inline-block; width: 50px; height: 150px; background: green"></span></mtext>
+ </mrow>
+ </math>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/all-mathml-containers.html b/testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/all-mathml-containers.html
new file mode 100644
index 0000000000..9069b92637
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/all-mathml-containers.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>absolutely positioned in all MathML elements</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<meta name="assert" content="Verify that absolutely positioned node works in all MathML elements.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<style>
+ /* override display: none on children of maction/semantics */
+ maction > *, semantics > * {
+ display: math;
+ }
+</style>
+<script>
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+ ["absolute", "fixed"].forEach(positionValue => {
+ for (tag in MathMLFragments) {
+ if (!FragmentHelper.isValidChildOfMrow(tag) ||
+ FragmentHelper.isEmpty(tag))
+ continue;
+ document.body.insertAdjacentHTML("beforeend", `<div style="position: absolute;">\
+<math>${MathMLFragments[tag]}</math>\
+</div>`);
+ let div = document.body.lastElementChild;
+ let element = FragmentHelper.element(div.firstElementChild);
+ FragmentHelper.forceNonEmptyElement(element);
+ if (element.classList.contains("mathml-container") ||
+ element.classList.contains("foreign-container")) {
+ for (let i = 0; i < 5; i++) {
+ FragmentHelper.appendChild(element);
+ }
+ }
+
+ let middleChild;
+ if (element.children.length >= 2) {
+ middleChild = FragmentHelper.appendChild(element, true /*allowInvalid*/);
+ middleChild.setAttribute("style", `position: ${positionValue}; left: 300px; top: 400px`);
+ let middlePosition = Math.floor(element.children.length/2);
+ element.insertBefore(middleChild, element.children[middlePosition]);
+ }
+
+ let firstChild = FragmentHelper.appendChild(element, true /*allowInvalid*/);
+ firstChild.setAttribute("style", `position: ${positionValue}; left: 100px; top: 200px`);
+ element.insertBefore(firstChild, element.firstElementChild);
+
+ let lastChild = FragmentHelper.appendChild(element, true /*allowInvalid*/);
+ lastChild.setAttribute("style", `position: ${positionValue}; left: 500px; top: 600px`);
+
+ let referenceBox;
+ switch (positionValue) {
+ case "absolute":
+ // Use the absolutely positioned div ancestor.
+ referenceBox = div.getBoundingClientRect();
+ break
+ case "fixed":
+ // Use the viewport.
+ referenceBox = {left: 0, top: 0};
+ break;
+ default:
+ throw "reference box not defined";
+ }
+
+ let firstChildBox = firstChild.getBoundingClientRect();
+ let lastChildBox = lastChild.getBoundingClientRect();
+ let middleChildBox;
+ if (middleChild) {
+ middleChildBox = middleChild.getBoundingClientRect();
+ }
+
+ let epsilon = 1;
+
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ assert_approx_equals(firstChildBox.left - referenceBox.left, 100, epsilon);
+ assert_approx_equals(firstChildBox.top - referenceBox.top, 200, epsilon);
+ if (middleChildBox) {
+ assert_approx_equals(middleChildBox.left - referenceBox.left, 300, epsilon);
+ assert_approx_equals(middleChildBox.top - referenceBox.top, 400, epsilon);
+ }
+ assert_approx_equals(lastChildBox.left - referenceBox.left, 500, epsilon);
+ assert_approx_equals(lastChildBox.top - referenceBox.top, 600, epsilon);
+ }, `position: ${positionValue}; children in ${tag}`);
+
+ div.style = "display: none;"; // Hide the div after measurement.
+ }
+ });
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/fixed-positioned-001-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/fixed-positioned-001-ref.html
new file mode 100644
index 0000000000..03b9f56698
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/fixed-positioned-001-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8"/>
+<title>Fixed positioned (reference)</title>
+<style>
+ body { overflow: hidden; }
+</style>
+<body>
+ <div style="position: absolute; left: 100px; top: 200px;
+ height: 3000px; width: 3000px;">
+ <math>
+ <mrow>
+ <mspace width="100px" height="300px" style="background: green"/>
+ <mspace width="100px" height="300px" style="background: green"/>
+ <mspace width="100px" height="300px" style="background: green"/>
+ </mrow>
+ </math>
+ <p>Test passes if you see a green square and no red.</p>
+ </div>
+ <script>
+ requestAnimationFrame(() => {
+ window.scrollTo(50, 100);
+ document.documentElement.classList.remove("reftest-wait");
+ });
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/fixed-positioned-001.html b/testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/fixed-positioned-001.html
new file mode 100644
index 0000000000..994174162c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/out-of-flow/fixed-positioned-001.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8"/>
+<title>Fixed positioned</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-mrow">
+<link rel="match" href="fixed-positioned-001-ref.html"/>
+<meta name="assert" content="Verify visual rendering of fixed positioned mtext elements.">
+<style>
+ body { overflow: hidden; }
+</style>
+<body>
+ <div style="position: absolute; left: 100px; top: 200px;
+ height: 3000px; width: 3000px;">
+ <math>
+ <mrow>
+ <mspace width="100px" height="300px" style="background: green"/>
+ <mspace width="100px" height="300px" style="background: red"/>
+ <mspace width="100px" height="300px" style="background: green"/>
+ <mtext style="position: fixed; left: 150px; top: 100px;"><span style="display: inline-block; width: 50px; height: 300px; background: green"></span></mtext>
+ <mtext style="position: fixed; left: 200px; top: 100px;"><span style="display: inline-block; width: 50px; height: 150px; background: green"></span></mtext>
+ <mtext style="position: fixed; left: 200px; top: 250px;"><span style="display: inline-block; width: 50px; height: 150px; background: green"></span></mtext>
+ </mrow>
+ </math>
+ <p>Test passes if you see a green square and no red.</p>
+ </div>
+ <script>
+ requestAnimationFrame(() => {
+ window.scrollTo(50, 100);
+ document.documentElement.classList.remove("reftest-wait");
+ });
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/overflow/computed-value-001.html b/testing/web-platform/tests/mathml/relations/css-styling/overflow/computed-value-001.html
new file mode 100644
index 0000000000..0510f1da6d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/overflow/computed-value-001.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>overflow on MathML elements</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#user-agent-stylesheet">
+<meta name="assert" content="overflow can be overridden on MathML elements.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<style>
+ /* selector defined in mathml-fragments.js */
+ .element {
+ overflow: scroll;
+ }
+</style>
+</head>
+<body>
+ <div id="log"></div>
+ <div id="container">
+ <math class="element"></math>
+ </div>
+ <script>
+ test(function () {
+ var container = document.getElementById("container");
+ for (tag in MathMLFragments) {
+ // Skip mtable as browsers don't have interoperable behavior for
+ // display: table.
+ // See https://github.com/w3c/csswg-drafts/issues/8133
+ if (tag == "mtable")
+ continue;
+ container.insertAdjacentHTML("beforeend", `<math>${MathMLFragments[tag]}</math>`);
+ }
+ let unknownElement = FragmentHelper.createElement("unknown");
+ unknownElement.setAttribute("class", "element");
+ container.appendChild(unknownElement);
+ Array.from(document.getElementsByClassName("element")).forEach(element => {
+ var tag = element.tagName;
+ var style = window.getComputedStyle(element);
+ assert_equals(style["overflow"], "scroll", `overflow on ${tag}`);
+ }, `overflow can be overridden on all MathML elements`);
+ });
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/border-001.html b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/border-001.html
new file mode 100644
index 0000000000..fd86388ccd
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/border-001.html
@@ -0,0 +1,179 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>border</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<meta name="assert" content="Verify that border is taken into account.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/box-comparison.js"></script>
+<script>
+ var epsilon = 1;
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var s = measureSpaceAround("mrow-border")
+ assert_approx_equals(s.left, 20, epsilon, "left border");
+ assert_approx_equals(s.right, 30, epsilon, "right border");
+ assert_approx_equals(s.top, 40, epsilon, "top border");
+ assert_approx_equals(s.bottom, 50, epsilon, "bottom border");
+ var b = document.getElementById("mrow-border").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 20 + 50 + 30, epsilon, "element width");
+ assert_approx_equals(b.height, 40 + 50 + 50, epsilon, "element height");
+ }, "Border properties on mrow");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_true(MathMLFeatureDetection.has_dir());
+ var s = measureSpaceAround("mrow-border-rtl")
+ assert_approx_equals(s.left, 20, epsilon, "left border");
+ assert_approx_equals(s.right, 30, epsilon, "right border");
+ assert_approx_equals(s.top, 40, epsilon, "top border");
+ assert_approx_equals(s.bottom, 50, epsilon, "bottom border");
+ var b = document.getElementById("mrow-border-rtl").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 20 + 50 + 30, epsilon, "element width");
+ assert_approx_equals(b.height, 40 + 50 + 50, epsilon, "element height");
+ }, "Border properties on mrow (rtl)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var s = measureSpaceAround("mrow-border-shorthand")
+ assert_approx_equals(s.left, 20, epsilon, "left border");
+ assert_approx_equals(s.right, 20, epsilon, "right border");
+ assert_approx_equals(s.top, 20, epsilon, "top border");
+ assert_approx_equals(s.bottom, 20, epsilon, "bottom border");
+ var b = document.getElementById("mrow-border-shorthand").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 20 + 50 + 20, epsilon, "element width");
+ assert_approx_equals(b.height, 20 + 50 + 20, epsilon, "element height");
+ }, "Border properties on mrow (shorthand)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var s = measureSpaceAround("mrow-border-logical")
+ assert_approx_equals(s.left, 20, epsilon, "left border");
+ assert_approx_equals(s.right, 30, epsilon, "right border");
+ assert_approx_equals(s.top, 40, epsilon, "top border");
+ assert_approx_equals(s.bottom, 50, epsilon, "bottom border");
+ var b = document.getElementById("mrow-border-logical").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 20 + 50 + 30, epsilon, "element width");
+ assert_approx_equals(b.height, 40 + 50 + 50, epsilon, "element height");
+ }, "Border properties on mrow (logical)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_true(MathMLFeatureDetection.has_dir());
+ var s = measureSpaceAround("mrow-border-logical-rtl")
+ assert_approx_equals(s.left, 30, epsilon, "left border");
+ assert_approx_equals(s.right, 20, epsilon, "right border");
+ assert_approx_equals(s.top, 40, epsilon, "top border");
+ assert_approx_equals(s.bottom, 50, epsilon, "bottom border");
+ var b = document.getElementById("mrow-border-logical-rtl").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 20 + 50 + 30, epsilon, "element width");
+ assert_approx_equals(b.height, 40 + 50 + 50, epsilon, "element height");
+ }, "Border properties on mrow (logical, rtl)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var s = measureSpaceAround("mrow-border-logical-shorthand")
+ assert_approx_equals(s.left, 20, epsilon, "left border");
+ assert_approx_equals(s.right, 20, epsilon, "right border");
+ assert_approx_equals(s.top, 30, epsilon, "top border");
+ assert_approx_equals(s.bottom, 30, epsilon, "bottom border");
+ var b = document.getElementById("mrow-border-logical-shorthand").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 20 + 50 + 20, epsilon, "element width");
+ assert_approx_equals(b.height, 30 + 50 + 30, epsilon, "element height");
+ }, "Border properties on mrow (logical, shorthand)");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mrow>
+ <mrow id="mrow-border"
+ style="border-left: 20px solid transparent;
+ border-right: 30px solid transparent;
+ border-top: 40px solid transparent;
+ border-bottom: 50px solid transparent;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math dir="rtl">
+ <mrow>
+ <mrow id="mrow-border-rtl"
+ style="border-left: 20px solid transparent;
+ border-right: 30px solid transparent;
+ border-top: 40px solid transparent;
+ border-bottom: 50px solid transparent;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mrow id="mrow-border-shorthand"
+ style="border: 20px solid transparent;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mrow id="mrow-border-logical"
+ style="border-inline-start: 20px solid transparent;
+ border-inline-end: 30px solid transparent;
+ border-block-start: 40px solid transparent;
+ border-block-end: 50px solid transparent;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math dir="rtl">
+ <mrow>
+ <mrow id="mrow-border-logical-rtl"
+ style="border-inline-start: 20px solid transparent;
+ border-inline-end: 30px solid transparent;
+ border-block-start: 40px solid transparent;
+ border-block-end: 50px solid transparent;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mrow id="mrow-border-logical-shorthand"
+ style="border-inline: 20px solid transparent;
+ border-block: 30px solid transparent;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/border-002.html b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/border-002.html
new file mode 100644
index 0000000000..bfb7f76adc
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/border-002.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>border</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<meta name="assert" content="Verify that border is taken into account.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<script src="/mathml/support/box-comparison.js"></script>
+<script>
+ var epsilon = 1;
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+
+ for (tag in MathMLFragments) {
+ if (!FragmentHelper.isValidChildOfMrow(tag))
+ continue;
+
+ var style = "border-left: 30px solid; border-right: 40px solid; border-top: 50px solid; border-bottom: 60px solid;";
+
+ if (FragmentHelper.isEmpty(tag)) {
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ var s = compareSizeWithAndWithoutStyle(tag, style);
+ assert_approx_equals(s.element_width_delta, 30 + 40, epsilon, "left/right border");
+ assert_approx_equals(s.element_height_delta, 50 + 60, epsilon, "top/bottom border");
+ assert_approx_equals(s.preferred_width_delta, 30 + 40, epsilon, "preferred width");
+ }, `Border properties on ${tag}`);
+ continue;
+ }
+
+ var default_border = tag === "merror" ? 1 : 0;
+
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ var s = compareSpaceWithAndWithoutStyle(tag, style);
+ assert_approx_equals(s.left_delta + default_border, 30, epsilon, "left border");
+ assert_approx_equals(s.right_delta + default_border, 40, epsilon, "right border");
+ assert_approx_equals(s.top_delta + default_border, 50, epsilon, "top border");
+ assert_approx_equals(s.bottom_delta + default_border, 60, epsilon, "bottom border");
+ assert_approx_equals(s.element_width_delta + 2 * default_border, 30 + 40, epsilon, "element width");
+ assert_approx_equals(s.element_height_delta + 2 * default_border, 50 + 60, epsilon, "element height");
+ assert_approx_equals(s.preferred_width_delta + 2 * default_border, 30 + 40, epsilon, "element preferred width");
+ }, `Border properties on ${tag}`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ var s = compareSpaceWithAndWithoutStyle(tag, style, null, "rtl");
+ assert_approx_equals(s.left_delta + default_border, 30, epsilon, "left border");
+ assert_approx_equals(s.right_delta + default_border, 40, epsilon, "right border");
+ assert_approx_equals(s.top_delta + default_border, 50, epsilon, "top border");
+ assert_approx_equals(s.bottom_delta + default_border, 60, epsilon, "bottom border");
+ assert_approx_equals(s.element_width_delta + 2 * default_border, 30 + 40, epsilon, "element width");
+ assert_approx_equals(s.element_height_delta + 2 * default_border, 50 + 60, epsilon, "element height");
+ assert_approx_equals(s.preferred_width_delta + 2 * default_border, 30 + 40, epsilon, "element preferred width");
+ }, `Border properties on ${tag} (rtl)`);
+ }
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/margin-001.html b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/margin-001.html
new file mode 100644
index 0000000000..eabb6f46c7
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/margin-001.html
@@ -0,0 +1,179 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>margin</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<meta name="assert" content="Verify that margin is taken into account.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/box-comparison.js"></script>
+<script>
+ var epsilon = 1;
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var s = measureSpaceAround("mrow-margin")
+ assert_approx_equals(s.left, 20, epsilon, "left margin");
+ assert_approx_equals(s.right, 30, epsilon, "right margin");
+ assert_approx_equals(s.top, 40, epsilon, "top margin");
+ assert_approx_equals(s.bottom, 50, epsilon, "bottom margin");
+ var b = document.getElementById("mrow-margin").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 50, epsilon, "element width");
+ assert_approx_equals(b.height, 50, epsilon, "element height");
+ }, "Margin properties on mrow");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_true(MathMLFeatureDetection.has_dir());
+ var s = measureSpaceAround("mrow-margin-rtl")
+ assert_approx_equals(s.left, 20, epsilon, "left margin");
+ assert_approx_equals(s.right, 30, epsilon, "right margin");
+ assert_approx_equals(s.top, 40, epsilon, "top margin");
+ assert_approx_equals(s.bottom, 50, epsilon, "bottom margin");
+ var b = document.getElementById("mrow-margin-rtl").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 50, epsilon, "element width");
+ assert_approx_equals(b.height, 50, epsilon, "element height");
+ }, "Margin properties on mrow (rtl)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var s = measureSpaceAround("mrow-margin-shorthand")
+ assert_approx_equals(s.left, 20, epsilon, "left margin");
+ assert_approx_equals(s.right, 20, epsilon, "right margin");
+ assert_approx_equals(s.top, 20, epsilon, "top margin");
+ assert_approx_equals(s.bottom, 20, epsilon, "bottom margin");
+ var b = document.getElementById("mrow-margin-shorthand").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 50, epsilon, "element width");
+ assert_approx_equals(b.height, 50, epsilon, "element height");
+ }, "Margin properties on mrow (shorthand)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var s = measureSpaceAround("mrow-margin-logical")
+ assert_approx_equals(s.left, 20, epsilon, "left margin");
+ assert_approx_equals(s.right, 30, epsilon, "right margin");
+ assert_approx_equals(s.top, 40, epsilon, "top margin");
+ assert_approx_equals(s.bottom, 50, epsilon, "bottom margin");
+ var b = document.getElementById("mrow-margin-logical").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 50, epsilon, "element width");
+ assert_approx_equals(b.height, 50, epsilon, "element height");
+ }, "Margin properties on mrow (logical)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_true(MathMLFeatureDetection.has_dir());
+ var s = measureSpaceAround("mrow-margin-logical-rtl")
+ assert_approx_equals(s.left, 30, epsilon, "left margin");
+ assert_approx_equals(s.right, 20, epsilon, "right margin");
+ assert_approx_equals(s.top, 40, epsilon, "top margin");
+ assert_approx_equals(s.bottom, 50, epsilon, "bottom margin");
+ var b = document.getElementById("mrow-margin-logical-rtl").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 50, epsilon, "element width");
+ assert_approx_equals(b.height, 50, epsilon, "element height");
+ }, "Margin properties on mrow (logical, rtl)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var s = measureSpaceAround("mrow-margin-logical-shorthand")
+ assert_approx_equals(s.left, 20, epsilon, "left margin");
+ assert_approx_equals(s.right, 20, epsilon, "right margin");
+ assert_approx_equals(s.top, 30, epsilon, "top margin");
+ assert_approx_equals(s.bottom, 30, epsilon, "bottom margin");
+ var b = document.getElementById("mrow-margin-logical-shorthand").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 50, epsilon, "element width");
+ assert_approx_equals(b.height, 50, epsilon, "element height");
+ }, "Margin properties on mrow (logical, shorthand)");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mrow>
+ <mrow id="mrow-margin"
+ style="margin-left: 20px;
+ margin-right: 30px;
+ margin-top: 40px;
+ margin-bottom: 50px;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math dir="rtl">
+ <mrow>
+ <mrow id="mrow-margin-rtl"
+ style="margin-left: 20px;
+ margin-right: 30px;
+ margin-top: 40px;
+ margin-bottom: 50px;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mrow id="mrow-margin-shorthand"
+ style="margin: 20px;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mrow id="mrow-margin-logical"
+ style="margin-inline-start: 20px;
+ margin-inline-end: 30px;
+ margin-block-start: 40px;
+ margin-block-end: 50px;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math dir="rtl">
+ <mrow>
+ <mrow id="mrow-margin-logical-rtl"
+ style="margin-inline-start: 20px;
+ margin-inline-end: 30px;
+ margin-block-start: 40px;
+ margin-block-end: 50px;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mrow id="mrow-margin-logical-shorthand"
+ style="margin-inline: 20px;
+ margin-block: 30px;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/margin-002.html b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/margin-002.html
new file mode 100644
index 0000000000..b560ed125c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/margin-002.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>margin</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<meta name="assert" content="Verify that margin is taken into account.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<script src="/mathml/support/box-comparison.js"></script>
+<script>
+ var epsilon = 1;
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+
+ for (tag in MathMLFragments) {
+ if (!FragmentHelper.isValidChildOfMrow(tag))
+ continue;
+
+ var style = "margin-left: 30px; margin-right: 40px; margin-top: 50px; margin-bottom: 60px;";
+
+ if (FragmentHelper.isEmpty(tag)) {
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ var s = compareSizeWithAndWithoutStyle(tag, style);
+ assert_approx_equals(s.width_delta, 30 + 40, epsilon, "left/right margin");
+ assert_approx_equals(s.height_delta, 50 + 60, epsilon, "top/bottom margin");
+ assert_approx_equals(s.element_width_delta, 0, epsilon, "element width");
+ assert_approx_equals(s.element_height_delta, 0, epsilon, "element height");
+ assert_approx_equals(s.preferred_width_delta, 30 + 40, epsilon, "preferred width");
+ }, `Margin properties on ${tag}`);
+ continue;
+ }
+
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ var s = compareSpaceWithAndWithoutStyle(tag, style);
+ assert_approx_equals(s.left_delta, 30, epsilon, "left margin");
+ assert_approx_equals(s.right_delta, 40, epsilon, "right margin");
+ assert_approx_equals(s.top_delta, 50, epsilon, "top margin");
+ assert_approx_equals(s.bottom_delta, 60, epsilon, "bottom margin");
+ assert_approx_equals(s.element_width_delta, 0, epsilon, "element width");
+ assert_approx_equals(s.element_height_delta, 0, epsilon, "element height");
+ assert_approx_equals(s.preferred_width_delta, 30 + 40, epsilon, "preferred width");
+ }, `Margin properties on ${tag}`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ var s = compareSpaceWithAndWithoutStyle(tag, style, null, "rtl");
+ assert_approx_equals(s.left_delta, 30, epsilon, "left margin");
+ assert_approx_equals(s.right_delta, 40, epsilon, "right margin");
+ assert_approx_equals(s.top_delta, 50, epsilon, "top margin");
+ assert_approx_equals(s.bottom_delta, 60, epsilon, "bottom margin");
+ assert_approx_equals(s.element_width_delta, 0, epsilon, "element width");
+ assert_approx_equals(s.element_height_delta, 0, epsilon, "element height");
+ assert_approx_equals(s.preferred_width_delta, 30 + 40, epsilon, "preferred width");
+ }, `Margin properties on ${tag} (rtl)`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ // Apply the same margin style on the parent mrow.
+ // The margins are not collapsed so they should be added twice.
+ var s = compareSpaceWithAndWithoutStyle(tag, style, style);
+ assert_approx_equals(s.left_delta, 30 * 2, epsilon, "left margin");
+ assert_approx_equals(s.right_delta, 40 * 2, epsilon, "right margin");
+ assert_approx_equals(s.top_delta, 50 * 2, epsilon, "top margin");
+ assert_approx_equals(s.bottom_delta, 60 * 2, epsilon, "bottom margin");
+ assert_approx_equals(s.element_width_delta, 0, epsilon, "element width");
+ assert_approx_equals(s.element_height_delta, 0, epsilon, "element height");
+ assert_approx_equals(s.preferred_width_delta, (30 + 40) * 2, epsilon, "preferred width");
+ }, `Margin properties on ${tag} (no margin-collapsing)`);
+ }
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/margin-003.html b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/margin-003.html
new file mode 100644
index 0000000000..3b6b2a38db
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/margin-003.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>margin</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<meta name="assert" content="Verify that margin is taken into account on children.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<script src="/mathml/support/layout-comparison.js"></script>
+<script>
+ var epsilon = 1;
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+
+ for (tag in MathMLFragments) {
+ if (!FragmentHelper.isValidChildOfMrow(tag) ||
+ FragmentHelper.isEmpty(tag) ||
+ FragmentHelper.isTokenElement(tag) ||
+ tag == "semantics" ||
+ tag == "maction" ||
+ tag == "mtable")
+ continue;
+
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+
+ document.body.insertAdjacentHTML("beforeend", `<hr/><div>\
+<div style="display: inline-block; border: 1px dashed blue;"><math>${MathMLFragments[tag]}</math></div><br/>\
+<div style="display: inline-block; border: 1px dashed green;"><math>${MathMLFragments[tag]}</math></div>\
+</div>`);
+
+ var div = document.body.lastElementChild;
+ var elementShrinkWrapContainer = div.firstElementChild;
+ var element = elementShrinkWrapContainer.firstElementChild.firstElementChild;
+ var elementContainer = div.firstElementChild;
+ var referenceShrinkWrapContainer = div.lastElementChild;
+ var reference = referenceShrinkWrapContainer.firstElementChild.firstElementChild;
+
+ FragmentHelper.forceNonEmptyElement(element);
+ FragmentHelper.forceNonEmptyElement(reference);
+
+ var mspaceWidth = 20, mspaceHeight = 40, mspaceDepth = 30;
+ var marginLeft = 10, marginRight = 15, marginTop = 20, marginBottom = 25;
+ Array.from(element.children).forEach(mrow => {
+ mrow.outerHTML = `<mspace width="${mspaceWidth}px" height="${mspaceHeight}px" depth='${mspaceDepth}px' style='background: blue; margin-left: ${marginLeft}px; margin-right: ${marginRight}px; margin-top: ${marginTop}px; margin-bottom: ${marginBottom}px;'></mspace>`;
+ });
+
+ Array.from(reference.children).forEach(mrow => {
+ mrow.outerHTML = `<mspace width="${marginLeft+mspaceWidth+marginRight}px" height="${mspaceHeight+marginTop}px" depth='${mspaceDepth+marginBottom}px' style='background: green;'></mspace>`;
+ });
+
+ // Compare sizes.
+ compareSize(element, reference, epsilon);
+
+ // Compare children positions.
+ var elementBox = element.getBoundingClientRect();
+ var referenceBox = reference.getBoundingClientRect();
+ for (var i = 0; i < element.children.length; i++) {
+ var childBox = element.children[i].getBoundingClientRect();
+ var referenceChildBox = reference.children[i].getBoundingClientRect();
+ assert_approx_equals(childBox.width + marginLeft + marginRight, referenceChildBox.width, epsilon, "inline size (child ${i})");
+ assert_approx_equals(childBox.height + marginTop + marginBottom, referenceChildBox.height, epsilon, "block size (child ${i})");
+
+ assert_approx_equals(childBox.left - marginLeft - elementBox.left,
+ referenceChildBox.left - referenceBox.left,
+ epsilon,
+ `inline position (child ${i})`);
+ assert_approx_equals(childBox.top - marginTop - elementBox.top,
+ referenceChildBox.top - referenceBox.top,
+ epsilon,
+ `block position (child ${i})`);
+ }
+
+ // Compare preferred widths.
+ assert_approx_equals(elementShrinkWrapContainer.offsetWidth, referenceShrinkWrapContainer.offsetWidth, epsilon, "preferred width");
+
+ }, `Margin properties on the children of ${tag}`);
+ }
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-001.html b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-001.html
new file mode 100644
index 0000000000..b6d4901f36
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-001.html
@@ -0,0 +1,179 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>padding</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<meta name="assert" content="Verify that padding is taken into account.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/box-comparison.js"></script>
+<script>
+ var epsilon = 1;
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var s = measureSpaceAround("mrow-padding")
+ assert_approx_equals(s.left, 20, epsilon, "left padding");
+ assert_approx_equals(s.right, 30, epsilon, "right padding");
+ assert_approx_equals(s.top, 40, epsilon, "top padding");
+ assert_approx_equals(s.bottom, 50, epsilon, "bottom padding");
+ var b = document.getElementById("mrow-padding").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 20 + 50 + 30, epsilon, "element width");
+ assert_approx_equals(b.height, 40 + 50 + 50, epsilon, "element height");
+ }, "Padding properties on mrow");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_true(MathMLFeatureDetection.has_dir());
+ var s = measureSpaceAround("mrow-padding-rtl")
+ assert_approx_equals(s.left, 20, epsilon, "left padding");
+ assert_approx_equals(s.right, 30, epsilon, "right padding");
+ assert_approx_equals(s.top, 40, epsilon, "top padding");
+ assert_approx_equals(s.bottom, 50, epsilon, "bottom padding");
+ var b = document.getElementById("mrow-padding-rtl").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 20 + 50 + 30, epsilon, "element width");
+ assert_approx_equals(b.height, 40 + 50 + 50, epsilon, "element height");
+ }, "Padding properties on mrow (rtl)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var s = measureSpaceAround("mrow-padding-shorthand")
+ assert_approx_equals(s.left, 20, epsilon, "left padding");
+ assert_approx_equals(s.right, 20, epsilon, "right padding");
+ assert_approx_equals(s.top, 20, epsilon, "top padding");
+ assert_approx_equals(s.bottom, 20, epsilon, "bottom padding");
+ var b = document.getElementById("mrow-padding-shorthand").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 20 + 50 + 20, epsilon, "element width");
+ assert_approx_equals(b.height, 20 + 50 + 20, epsilon, "element height");
+ }, "Padding properties on mrow (shorthand)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var s = measureSpaceAround("mrow-padding-logical")
+ assert_approx_equals(s.left, 20, epsilon, "left padding");
+ assert_approx_equals(s.right, 30, epsilon, "right padding");
+ assert_approx_equals(s.top, 40, epsilon, "top padding");
+ assert_approx_equals(s.bottom, 50, epsilon, "bottom padding");
+ var b = document.getElementById("mrow-padding-logical").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 20 + 50 + 30, epsilon, "element width");
+ assert_approx_equals(b.height, 40 + 50 + 50, epsilon, "element height");
+ }, "Padding properties on mrow (logical)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_true(MathMLFeatureDetection.has_dir());
+ var s = measureSpaceAround("mrow-padding-logical-rtl")
+ assert_approx_equals(s.left, 30, epsilon, "left padding");
+ assert_approx_equals(s.right, 20, epsilon, "right padding");
+ assert_approx_equals(s.top, 40, epsilon, "top padding");
+ assert_approx_equals(s.bottom, 50, epsilon, "bottom padding");
+ var b = document.getElementById("mrow-padding-logical-rtl").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 20 + 50 + 30, epsilon, "element width");
+ assert_approx_equals(b.height, 40 + 50 + 50, epsilon, "element height");
+ }, "Padding properties on mrow (logical, rtl)");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var s = measureSpaceAround("mrow-padding-logical-shorthand")
+ assert_approx_equals(s.left, 20, epsilon, "left padding");
+ assert_approx_equals(s.right, 20, epsilon, "right padding");
+ assert_approx_equals(s.top, 30, epsilon, "top padding");
+ assert_approx_equals(s.bottom, 30, epsilon, "bottom padding");
+ var b = document.getElementById("mrow-padding-logical-shorthand").
+ getBoundingClientRect();
+ assert_approx_equals(b.width, 20 + 50 + 20, epsilon, "element width");
+ assert_approx_equals(b.height, 30 + 50 + 30, epsilon, "element height");
+ }, "Padding properties on mrow (logical, shorthand)");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mrow>
+ <mrow id="mrow-padding"
+ style="padding-left: 20px;
+ padding-right: 30px;
+ padding-top: 40px;
+ padding-bottom: 50px;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math dir="rtl">
+ <mrow>
+ <mrow id="mrow-padding-rtl"
+ style="padding-left: 20px;
+ padding-right: 30px;
+ padding-top: 40px;
+ padding-bottom: 50px;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mrow id="mrow-padding-shorthand"
+ style="padding: 20px;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mrow id="mrow-padding-logical"
+ style="padding-inline-start: 20px;
+ padding-inline-end: 30px;
+ padding-block-start: 40px;
+ padding-block-end: 50px;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math dir="rtl">
+ <mrow>
+ <mrow id="mrow-padding-logical-rtl"
+ style="padding-inline-start: 20px;
+ padding-inline-end: 30px;
+ padding-block-start: 40px;
+ padding-block-end: 50px;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mrow>
+ <mrow id="mrow-padding-logical-shorthand"
+ style="padding-inline: 20px;
+ padding-block: 30px;">
+ <mspace width="50px" height="50px"></mspace>
+ </mrow>
+ </mrow>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-002.html b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-002.html
new file mode 100644
index 0000000000..89d3bdc7ef
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-002.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>padding</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<meta name="assert" content="Verify that padding is taken into account.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<script src="/mathml/support/box-comparison.js"></script>
+<script>
+ var epsilon = 1;
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+
+ for (tag in MathMLFragments) {
+ if (!FragmentHelper.isValidChildOfMrow(tag))
+ continue;
+
+ var defaultInlinePadding = (tag === "mfrac" ? 1 : 0);
+ var style = `padding-left: ${defaultInlinePadding + 30}px; padding-right: ${defaultInlinePadding + 40}px; padding-top: 50px; padding-bottom: 60px;`;
+
+ if (FragmentHelper.isEmpty(tag)) {
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ var s = compareSizeWithAndWithoutStyle(tag, style);
+ assert_approx_equals(s.element_width_delta, 30 + 40, epsilon, "left/right padding");
+ assert_approx_equals(s.element_height_delta, 50 + 60, epsilon, "top/bottom padding");
+ assert_approx_equals(s.preferred_width_delta, 30 + 40, epsilon, "preferred width");
+ }, `Padding properties on ${tag}`);
+ continue;
+ }
+
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ var s = compareSpaceWithAndWithoutStyle(tag, style);
+ assert_approx_equals(s.left_delta, 30, epsilon, "left padding");
+ assert_approx_equals(s.right_delta, 40, epsilon, "right padding");
+ assert_approx_equals(s.top_delta, 50, epsilon, "top padding");
+ assert_approx_equals(s.bottom_delta, 60, epsilon, "bottom padding");
+ assert_approx_equals(s.element_width_delta, 30 + 40, epsilon, "element width");
+ assert_approx_equals(s.element_height_delta, 50 + 60, epsilon, "element height");
+ assert_approx_equals(s.preferred_width_delta, 30 + 40, epsilon, "preferred width");
+ }, `Padding properties on ${tag}`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ var s = compareSpaceWithAndWithoutStyle(tag, style, "rtl");
+ assert_approx_equals(s.left_delta, 30, epsilon, "left padding");
+ assert_approx_equals(s.right_delta, 40, epsilon, "right padding");
+ assert_approx_equals(s.top_delta, 50, epsilon, "top padding");
+ assert_approx_equals(s.bottom_delta, 60, epsilon, "bottom padding");
+ assert_approx_equals(s.element_width_delta, 30 + 40, epsilon, "element width");
+ assert_approx_equals(s.element_height_delta, 50 + 60, epsilon, "element height");
+ assert_approx_equals(s.preferred_width_delta, 30 + 40, epsilon, "preferred width");
+ }, `Padding properties on ${tag} (rtl)`);
+ }
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-001-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-001-ref.html
new file mode 100644
index 0000000000..150a650bc2
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-001-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Padding/border/margin</title>
+<body>
+ <p>This test passes if you see a purple square of side 100px, surrounded by a
+ 10px blue padding, surrounded by a 10px blue/yellow dashed border, itself
+ surrounded by a 10px pink margin.</p>
+ </div>
+ <div style="background: pink; position: absolute; left: 10px; top: 3em;">
+ <div style="background: blue; border: 10px dashed yellow; padding: 10px; margin: 10px;">
+ <div style="width: 100px; height: 100px; background: purple;"></div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-001.html b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-001.html
new file mode 100644
index 0000000000..b0fb17c7d2
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-001.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Padding/border/margin</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-mrow">
+<link rel="match" href="padding-border-margin-001-ref.html"/>
+<meta name="assert" content="Verify visual rendering of padding/border/margin on the mrow element.">
+<body>
+ <p>This test passes if you see a purple square of side 100px, surrounded by a
+ 10px blue padding, surrounded by a 10px blue/yellow dashed border, itself
+ surrounded by a 10px pink margin.</p>
+ <div style="background: pink; position: absolute; left: 10px; top: 3em;">
+ <math>
+ <mrow style="background: blue; border: 10px dashed yellow; padding: 10px; margin: 10px;">
+ <mspace width="100px" height="100px" style="background: purple;"></mspace>
+ </mrow>
+ </math>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-002-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-002-ref.html
new file mode 100644
index 0000000000..e13a9f47ff
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-002-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Padding/border/margin on largeop (reference)</title>
+<body>
+ <p>This test passes if you see a cyan rectangle of width 300px and
+ height 1500px, surrounded by a 10px blue padding, surrounded by a 10px
+ blue/yellow dashed border, itself
+ surrounded by a 10px pink margin.</p>
+ </div>
+ <div style="background: pink; position: absolute; left: 10px; top: 4em;">
+ <div style="background: blue; border: 10px dashed yellow; padding: 10px; margin: 10px;">
+ <div style="width: 300px; height: 1500px; background: cyan;"></div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-002.html b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-002.html
new file mode 100644
index 0000000000..4559fc49ce
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-002.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Padding/border/margin on largeop</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-math-style-property">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-operators">
+<link rel="match" href="padding-border-margin-002-ref.html"/>
+<meta name="assert" content="Verify visual rendering of padding/border/margin on a displaystyle mo element with the largeop property.">
+<style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/largeop-displayoperatorminheight5000.woff");
+ }
+ math {
+ /* Largeop variant for U+2AFF has width 100px
+ and height 300 * 5000 / 1000 = 1500px */
+ font-family: TestFont;
+ font-size: 300px;
+ }
+</style>
+<body>
+ <p>This test passes if you see a cyan rectangle of width 300px and
+ height 1500px, surrounded by a 10px blue padding, surrounded by a 10px
+ blue/yellow dashed border, itself
+ surrounded by a 10px pink margin.</p>
+ <div style="background: pink; position: absolute; left: 10px; top: 4em;">
+ <math displaystyle="true">
+ <mo largeop="true" lspace="0" rspace="0" style="background: blue; border: 10px dashed yellow; padding: 10px; margin: 10px; color: cyan;">&#x2AFF;</mo>
+ </math>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-003-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-003-ref.html
new file mode 100644
index 0000000000..275494ddd8
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-003-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Padding/border/margin on an operator, stretchy along the block axis (reference)</title>
+<body>
+ <p>This test passes if you see a cyan rectangle of width 300px and
+ height 1500px, surrounded by a 10px blue padding, surrounded by a 10px
+ blue/yellow dashed border, itself
+ surrounded by a 10px pink margin.</p>
+ </div>
+ <div style="background: pink; position: absolute; left: 10px; top: 4em;">
+ <div style="background: blue; border: 10px dashed yellow; padding: 10px; margin: 10px;">
+ <div style="width: 300px; height: 1500px; background: cyan;"></div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-003.html b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-003.html
new file mode 100644
index 0000000000..c54682f309
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/padding-border-margin/padding-border-margin-003.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Padding/border/margin on an operator, stretchy along the block axis</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dfn-algorithm-for-stretching-operators-along-the-block-axis">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-of-operators">
+<link rel="match" href="padding-border-margin-003-ref.html"/>
+<meta name="assert" content="Verify visual rendering of padding/border/margin on an operator, stretchy along the block axis.">
+<style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/stretchy.woff");
+ }
+ math {
+ font-family: TestFont;
+ font-size: 300px;
+ }
+</style>
+<body>
+ <p>This test passes if you see a cyan rectangle of width 300px and
+ height 1500px, surrounded by a 10px blue padding, surrounded by a 10px
+ blue/yellow dashed border, itself
+ surrounded by a 10px pink margin.</p>
+ <div style="background: pink; position: absolute; left: 10px; top: 4em;">
+ <math>
+ <mspace height="750px" depth="750px"/>
+ <mo lspace="0" rspace="0" style="background: blue; border: 10px dashed yellow; padding: 10px; margin: 10px; color: cyan;">⥜</mo>
+ </math>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/presentational-hints-001-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/presentational-hints-001-ref.html
new file mode 100644
index 0000000000..ca539440f8
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/presentational-hints-001-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>presentational hints</title>
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+ @font-face {
+ font-family: DoubleStruck;
+ src: url("/fonts/math/mathvariant-double-struck.woff");
+ }
+ @font-face {
+ font-family: Italic;
+ src: url("/fonts/math/mathvariant-italic.woff");
+ }
+ math {
+ font: 25px/1 Ahem;
+ }
+</style>
+<body>
+ <p>dir:
+ <math style="direction: ltr;">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ </math>
+ </p>
+ <p>mathcolor:
+ <math style="color: green;">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ </math>
+ </p>
+ <p>mathbackground:
+ <math style="background: green;">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ </p>
+ <p>mathsize:
+ <math>
+ <mtext style="font-size: 100%">X</mtext>
+ </math>
+ </p>
+ <p>mathvariant:
+ <math>
+ <mi style="text-transform: uppercase">sin</mi>
+ </math>
+ </p>
+ <p>displaystyle:
+ <math style="math-style: compact">
+ <munder>
+ <mo movablelimits="true">X</mo>
+ <mo>X</mo>
+ </munder>
+ </math>
+ </p>
+ <p>scriptlevel:
+ <math>
+ <mtext style="math-depth: 0;">X</mtext>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/presentational-hints-001.html b/testing/web-platform/tests/mathml/relations/css-styling/presentational-hints-001.html
new file mode 100644
index 0000000000..96ee69541b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/presentational-hints-001.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>presentational hints</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#double-struck-mappings">
+<link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-displaystyle-and-scriptlevel-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-mathvariant-attribute">
+<link rel="match" href="presentational-hints-001-ref.html"/>
+<link rel="stylesheet" href="/fonts/ahem.css">
+<meta name="assert" content="Verify that local author style wins over presentation hints attributes">
+<style>
+ math {
+ font: 25px/1 Ahem;
+ }
+</style>
+<body>
+ <p>dir:
+ <math dir="rtl" style="direction: ltr;">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ </math>
+ </p>
+ <p>mathcolor:
+ <math mathcolor="red" style="color: green;">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ </math>
+ </p>
+ <p>mathbackground:
+ <math mathbackground="red" style="background: green;">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ </p>
+ <p>mathsize:
+ <math>
+ <mtext mathsize="300%" style="font-size: 100%">X</mtext>
+ </math>
+ </p>
+ <p>mathvariant:
+ <math>
+ <mi mathvariant="normal" style="text-transform: uppercase">sin</mi>
+ </math>
+ </p>
+ <p>displaystyle:
+ <math displaystyle="true" style="math-style: compact">
+ <munder>
+ <mo movablelimits="true">X</mo>
+ <mo>X</mo>
+ </munder>
+ </math>
+ </p>
+ <p>scriptlevel:
+ <math>
+ <mtext scriptlevel="1" style="math-depth: 0;">X</mtext>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/presentational-hints-002-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/presentational-hints-002-ref.html
new file mode 100644
index 0000000000..fa22741efe
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/presentational-hints-002-ref.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>presentational hints (dynamic)</title>
+<link rel="stylesheet" href="/fonts/ahem.css">
+<style>
+ math {
+ font: 25px/1 Ahem;
+ }
+ @font-face {
+ font-family: Italic;
+ src: url("/fonts/math/mathvariant-italic.woff");
+ }
+</style>
+</head>
+<body>
+ <p>dir:
+ <math dir="rtl">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ </math>
+ </p>
+ <p>mathcolor:
+ <math mathcolor="green">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ </math>
+ </p>
+ <p>mathbackground:
+ <math mathbackground="green">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ </p>
+ <p>mathsize:
+ <math>
+ <mtext mathsize="300%">X</mtext>
+ </math>
+ </p>
+ <p>mathvariant:
+ <math style="font-family: Italic">
+ <mi mathvariant="normal">X</mi>
+ </math>
+ </p>
+ <p>displaystyle:
+ <math displaystyle="true">
+ <munder>
+ <mo movablelimits="true">X</mo>
+ <mo>X</mo>
+ </munder>
+ </math>
+ </p>
+ <p>scriptlevel:
+ <math>
+ <mtext scriptlevel="-1">X</mtext>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/presentational-hints-002.html b/testing/web-platform/tests/mathml/relations/css-styling/presentational-hints-002.html
new file mode 100644
index 0000000000..8bb9153b86
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/presentational-hints-002.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8"/>
+<title>presentational hints (dynamic)</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#double-struck-mappings">
+<link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#new-text-transform-values">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-displaystyle-and-scriptlevel-attributes">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-mathvariant-attribute">
+<link rel="match" href="presentational-hints-002-ref.html"/>
+<link rel="stylesheet" href="/fonts/ahem.css">
+<meta name="assert" content="Verify dynamically setting attributes mapped to style.">
+<style>
+ math {
+ font: 25px/1 Ahem;
+ }
+ @font-face {
+ font-family: Italic;
+ src: url("/fonts/math/mathvariant-italic.woff");
+ }
+</style>
+<script>
+ window.addEventListener("load", function() {
+ // force initial layout so we're sure what we're testing against
+ document.documentElement.getBoundingClientRect();
+
+ document.getElementById("dir").setAttribute("dir", "rtl");
+ document.getElementById("mathcolor").setAttribute("mathcolor", "green");
+ document.getElementById("mathbackground").setAttribute("mathbackground", "green");
+ document.getElementById("mathsize").setAttribute("mathsize", "300%");
+ document.getElementById("mathvariant").setAttribute("mathvariant", "normal");
+ document.getElementById("displaystyle").setAttribute("displaystyle", "true");
+ document.getElementById("scriptlevel").setAttribute("scriptlevel", "-1");
+
+ document.documentElement.classList.remove('reftest-wait');
+ });
+</script>
+</head>
+<body>
+ <p>dir:
+ <math id="dir">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ </math>
+ </p>
+ <p>mathcolor:
+ <math id="mathcolor">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ </math>
+ </p>
+ <p>mathbackground:
+ <math id="mathbackground">
+ <mtext>X</mtext>
+ <mtext>p</mtext>
+ </p>
+ <p>mathsize:
+ <math>
+ <mtext id="mathsize">X</mtext>
+ </math>
+ </p>
+ <p>mathvariant:
+ <math style="font-family: Italic">
+ <mi id="mathvariant">X</mi>
+ </math>
+ </p>
+ <p>displaystyle:
+ <math id="displaystyle">
+ <munder>
+ <mo movablelimits="true">X</mo>
+ <mo>X</mo>
+ </munder>
+ </math>
+ </p>
+ <p>scriptlevel:
+ <math>
+ <mtext id="scriptlevel">X</mtext>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/scriptlevel-001.html b/testing/web-platform/tests/mathml/relations/css-styling/scriptlevel-001.html
new file mode 100644
index 0000000000..e9be1f2965
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/scriptlevel-001.html
@@ -0,0 +1,219 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Automatic scriptlevel</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-mathvariant-attribute">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-displaystyle-and-scriptlevel-attributes">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<meta name="assert" content="Verify automatic scriptlevel changes">
+<style>
+ #container, math {
+ /* Ahem font does not have a MATH table so the font-size scale factor
+ is always 0.71^{computed - inherited math script level} */
+ font: 100px/1 Ahem;
+ }
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+ function fontSize(element) {
+ return parseFloat((/(.+)px/).exec(window.getComputedStyle(element).getPropertyValue("font-size"))[1]);
+ }
+ function runTests() {
+ var container = document.getElementById("container");
+ var epsilon = .1
+ var fontSizeAtScriptLevelZero = fontSize(container);
+
+ test(function() {
+ var element = document.getElementById("mfrac_displaystyle");
+ assert_approx_equals(fontSize(element.children[0]), fontSizeAtScriptLevelZero, epsilon, "numerator");
+ assert_approx_equals(fontSize(element.children[1]), fontSizeAtScriptLevelZero, epsilon, "denominator");
+ }, "automatic scriptlevel on mfrac (displaystyle=true)");
+
+ test(function() {
+ var element = document.getElementById("mfrac_notdisplaystyle");
+ assert_approx_equals(fontSize(element.children[0]), fontSizeAtScriptLevelZero * .71, epsilon, "numerator");
+ assert_approx_equals(fontSize(element.children[1]), fontSizeAtScriptLevelZero * .71, epsilon, "denominator");
+ }, "automatic scriptlevel on mfrac (displaystyle=false)");
+
+ test(function() {
+ var element = document.getElementsByTagName("mroot")[0];
+ assert_approx_equals(fontSize(element.children[0]), fontSizeAtScriptLevelZero, epsilon, "base");
+ assert_approx_equals(fontSize(element.children[1]), fontSizeAtScriptLevelZero * .71 * .71, epsilon, "index");
+ }, "automatic scriptlevel on mroot");
+
+ ["msub", "msup", "msubsup", "munder", "mover", "munderover", "mmultiscripts"].forEach(tag => {
+ test(function() {
+ var element = document.getElementsByTagName(tag)[0];
+ for (var i = 0; i < element.children.length; i++)
+ assert_approx_equals(fontSize(element.children[i]), i > 0 ? fontSizeAtScriptLevelZero * .71 : fontSizeAtScriptLevelZero, epsilon, `child ${i}`);
+ }, `automatic scriptlevel on ${tag}`);
+ });
+
+ test(function() {
+ var element = document.querySelector("munder[accentunder='true']");
+ assert_approx_equals(fontSize(element.children[0]), fontSizeAtScriptLevelZero, epsilon, "base");
+ assert_approx_equals(fontSize(element.children[1]), fontSizeAtScriptLevelZero, epsilon, "under");
+ }, `automatic scriptlevel on munder (accentunder=true)`);
+
+ test(function() {
+ var element = document.querySelector("mover[accent='true']");
+ assert_approx_equals(fontSize(element.children[0]), fontSizeAtScriptLevelZero, epsilon, "base");
+ assert_approx_equals(fontSize(element.children[1]), fontSizeAtScriptLevelZero, epsilon, "over");
+ }, `automatic scriptlevel on mover (accent=true)`);
+
+ test(function() {
+ var element = document.querySelector("munderover[accentunder='true']");
+ assert_approx_equals(fontSize(element.children[0]), fontSizeAtScriptLevelZero, epsilon, "base");
+ assert_approx_equals(fontSize(element.children[1]), fontSizeAtScriptLevelZero, epsilon, "under");
+ assert_approx_equals(fontSize(element.children[2]), fontSizeAtScriptLevelZero * .71, epsilon, "over");
+ }, `automatic scriptlevel on munderover (accentunder=true)`);
+
+ test(function() {
+ var element = document.querySelector("munderover[accent='true']");
+ assert_approx_equals(fontSize(element.children[0]), fontSizeAtScriptLevelZero, epsilon, "base");
+ assert_approx_equals(fontSize(element.children[1]), fontSizeAtScriptLevelZero * .71, epsilon, "under");
+ assert_approx_equals(fontSize(element.children[2]), fontSizeAtScriptLevelZero, epsilon, "over");
+ }, `automatic scriptlevel on munderover (accent=true)`);
+
+ test(function() {
+ var element = document.getElementById("munderover-dynamic-case-insensitive")
+ assert_approx_equals(fontSize(element.children[0]), fontSizeAtScriptLevelZero, epsilon, "base");
+ assert_approx_equals(fontSize(element.children[1]), fontSizeAtScriptLevelZero * .71, epsilon, "under");
+ assert_approx_equals(fontSize(element.children[2]), fontSizeAtScriptLevelZero, epsilon, "over");
+
+ element.removeAttribute("accent");
+ element.setAttribute("accentunder", "TrUe");
+ assert_approx_equals(fontSize(element.children[0]), fontSizeAtScriptLevelZero, epsilon, "base");
+ assert_approx_equals(fontSize(element.children[1]), fontSizeAtScriptLevelZero, epsilon, "under");
+ assert_approx_equals(fontSize(element.children[2]), fontSizeAtScriptLevelZero * .71, epsilon, "over");
+ }, "checking dynamic/case-insensitive accent/accentunder");
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <div id="container">
+ <p>
+ <math displaystyle="true">
+ <mfrac id="mfrac_displaystyle">
+ <mn>0</mn>
+ <mn>1</mn>
+ </mfrac>
+ </math>
+
+ <math displaystyle="false">
+ <mfrac id="mfrac_notdisplaystyle">
+ <mn>0</mn>
+ <mn>1</mn>
+ </mfrac>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mroot>
+ <mn>0</mn>
+ <mn>1</mn>
+ </mroot>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msub>
+ <mn>0</mn>
+ <mn>1</mn>
+ </msub>
+ </math>
+ <math>
+ <msup>
+ <mn>0</mn>
+ <mn>1</mn>
+ </msup>
+ </math>
+ <math>
+ <msubsup>
+ <mn>0</mn>
+ <mn>1</mn>
+ <mn>2</mn>
+ </msubsup>
+ </math>
+ <math>
+ <munder>
+ <mn>0</mn>
+ <mn>1</mn>
+ </munder>
+ </math>
+ <math>
+ <mover>
+ <mn>0</mn>
+ <mn>1</mn>
+ </mover>
+ </math>
+ <math>
+ <munderover>
+ <mn>0</mn>
+ <mn>1</mn>
+ <mn>2</mn>
+ </munderover>
+ </math>
+ <math>
+ <mmultiscripts>
+ <mn>0</mn>
+ <mn>1</mn>
+ <mn>2</mn>
+ <mn>3</mn>
+ <mn>4</mn>
+ <mprescripts/>
+ <mn>6</mn>
+ <mn>7</mn>
+ <mn>8</mn>
+ <mn>9</mn>
+ </mmultiscripts>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munder accentunder="true">
+ <mn>0</mn>
+ <mn>1</mn>
+ </munder>
+ </math>
+ <math>
+ <mover accent="true">
+ <mn>0</mn>
+ <mn>1</mn>
+ </mover>
+ </math>
+ <math>
+ <munderover accent="true">
+ <mn>0</mn>
+ <mn>1</mn>
+ <mn>2</mn>
+ </munderover>
+ </math>
+ <math>
+ <munderover accentunder="true">
+ <mn>0</mn>
+ <mn>1</mn>
+ <mn>2</mn>
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover id="munderover-dynamic-case-insensitive" accent="TrUe">
+ <mn>0</mn>
+ <mn>1</mn>
+ <mn>2</mn>
+ </munderover>
+ </math>
+ </p>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/transform-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/transform-ref.html
new file mode 100644
index 0000000000..005e8a7882
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/transform-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Transform property (reference)</title>
+</head>
+<body>
+ <p>Rectangles should be rotated.</p>
+ <div style="background: green; width: 200px; height: 200px; position: absolute; top: 100px; transform: rotate(90deg)"></div>
+ <div style="background: green; width: 200px; height: 200px; position: absolute; top: 300px; transform: rotate(90deg)"></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/transform.html b/testing/web-platform/tests/mathml/relations/css-styling/transform.html
new file mode 100644
index 0000000000..c45fda3469
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/transform.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Transform property</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="match" href="transform-ref.html"/>
+<meta name="assert" content="Verify that the transform property works on MathML elements.">
+</head>
+<body>
+ <p>Rectangles should be rotated.</p>
+ <div>
+ <math><mspace width="200px" height="200px" style="position:absolute; top:100px; background: green; transform: rotate(90deg)"/></math>
+ </div>
+ <div style="position: absolute; top: 300px; width: 200px; height: 200px">
+ <math style="position: absolute; transform: rotate(90deg)"><mspace width="200px" height="200px" style="background: green"/></math>
+ </div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/visibility-001-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/visibility-001-ref.html
new file mode 100644
index 0000000000..fcaf5fe85b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/visibility-001-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>visibility (reference)</title>
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; width: 200px; height: 200px;">
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/visibility-001.html b/testing/web-platform/tests/mathml/relations/css-styling/visibility-001.html
new file mode 100644
index 0000000000..56bf7b7da2
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/visibility-001.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>visibility</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="match" href="visibility-001-ref.html"/>
+<meta name="assert" content="Verify that visibility=hidden is used for the text of token elements.">
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; color: red; width: 200px; height: 200px;">
+ <math><mi style="visibility: hidden">1</mi></math>
+ <math><mn style="visibility: hidden">2</mn></math>
+ <math><mo style="visibility: hidden">3</mo></math>
+ <math><mtext style="visibility: hidden">4</mtext></math>
+ <math><ms style="visibility: hidden">5</ms></math>
+ <div id="dynamic">
+ <math><mi>1</mi></math>
+ <math><mn>2</mn></math>
+ <math><mo>3</mo></math>
+ <math><mtext>4</mtext></math>
+ <math><ms>5</ms></math>
+ </div>
+ </div>
+ <script>
+ window.addEventListener("load", () => {
+ document.getElementById("dynamic").style.visibility = "hidden";
+ document.documentElement.classList.remove("reftest-wait");
+ });
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/visibility-002-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/visibility-002-ref.html
new file mode 100644
index 0000000000..fcaf5fe85b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/visibility-002-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>visibility (reference)</title>
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; width: 200px; height: 200px;">
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/visibility-002.html b/testing/web-platform/tests/mathml/relations/css-styling/visibility-002.html
new file mode 100644
index 0000000000..f92d0faf6d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/visibility-002.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>visibility</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="help" href="https://w3c.github.io/mathml-core/#fraction-with-nonzero-line-thickness">
+<link rel="match" href="visibility-002-ref.html"/>
+<meta name="assert" content="Verify that visibility=hidden is used for the text and fraction bar of the mfrac element.">
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; color: red; width: 200px; height: 200px;">
+ <math><mfrac style="visibility: hidden"><mn>1</mn><mn>2</mn></mfrac></math>
+ <div id="dynamic">
+ <math><mfrac><mn>1</mn><mn>2</mn></mfrac></math>
+ </div>
+ </div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>
+ window.addEventListener("load", () => {
+ document.getElementById("dynamic").style.visibility = "hidden";
+ document.documentElement.classList.remove("reftest-wait");
+ });
+ </script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mfrac");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/visibility-003-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/visibility-003-ref.html
new file mode 100644
index 0000000000..fcaf5fe85b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/visibility-003-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>visibility (reference)</title>
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; width: 200px; height: 200px;">
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/visibility-003.html b/testing/web-platform/tests/mathml/relations/css-styling/visibility-003.html
new file mode 100644
index 0000000000..4bf4d45c81
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/visibility-003.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>visibility</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="help" href="https://w3c.github.io/mathml-core/#radical-symbol">
+<link rel="match" href="visibility-003-ref.html"/>
+<meta name="assert" content="Verify that visibility=hidden is used for the text and radical symbol of the msqrt and mroot elements.">
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; color: red; width: 200px; height: 200px;">
+ <math><msqrt style="visibility: hidden"><mn>1</mn></msqrt></math>
+ <math><mroot style="visibility: hidden"><mn>2</mn><mn>3</mn></mroot></math>
+ <div id="dynamic">
+ <math><msqrt><mn>1</mn></msqrt></math>
+ <math><mroot><mn>2</mn><mn>3</mn></mroot></math>
+ </div>
+ </div>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>
+ window.addEventListener("load", () => {
+ document.getElementById("dynamic").style.visibility = "hidden";
+ document.documentElement.classList.remove("reftest-wait");
+ });
+ </script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_msqrt");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/visibility-004.tentative-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/visibility-004.tentative-ref.html
new file mode 100644
index 0000000000..fcaf5fe85b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/visibility-004.tentative-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>visibility (reference)</title>
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; width: 200px; height: 200px;">
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/visibility-004.tentative.html b/testing/web-platform/tests/mathml/relations/css-styling/visibility-004.tentative.html
new file mode 100644
index 0000000000..28678eaf0c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/visibility-004.tentative.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>visibility</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-mtext">
+<link rel="help" href="https://github.com/mathml-refresh/mathml-core/pull/24">
+<link rel="match" href="visibility-004.tentative-ref.html"/>
+<meta name="assert" content="Verify that visibility=hidden is used for the text and graphical elements of the menclose element.">
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; color: red; width: 200px; height: 200px;">
+ <math><menclose notation="left" style="visibility: hidden"><mn>1</mn></menclose></math>
+ <math><menclose notation="right" style="visibility: hidden"><mn>2</mn></menclose></math>
+ <math><menclose notation="top" style="visibility: hidden"><mn>3</mn></menclose></math>
+ <math><menclose notation="bottom" style="visibility: hidden"><mn>4</mn></menclose></math>
+ <math><menclose notation="box" style="visibility: hidden"><mn>5</mn></menclose></math>
+ <math><menclose notation="roundedbox" style="visibility: hidden"><mn>6</mn></menclose></math>
+ <math><menclose notation="actuarial" style="visibility: hidden"><mn>7</mn></menclose></math>
+ <math><menclose notation="madruwb" style="visibility: hidden"><mn>8</mn></menclose></math>
+ <math><menclose notation="horizontalstrike" style="visibility: hidden"><mn>9</mn></menclose></math>
+ <math><menclose notation="verticalstrike" style="visibility: hidden"><mn>10</mn></menclose></math>
+ <math><menclose notation="updiagonalstrike" style="visibility: hidden"><mn>11</mn></menclose></math>
+ <math><menclose notation="downdiagonalstrike" style="visibility: hidden"><mn>12</mn></menclose></math>
+ <math><menclose notation="longdiv" style="visibility: hidden"><mn>13</mn></menclose></math>
+ <math><menclose notation="circle" style="visibility: hidden"><mn>14</mn></menclose></math>
+ <div id="dynamic">
+ <math><menclose notation="left"><mn>1</mn></menclose></math>
+ <math><menclose notation="right"><mn>2</mn></menclose></math>
+ <math><menclose notation="top"><mn>3</mn></menclose></math>
+ <math><menclose notation="bottom"><mn>4</mn></menclose></math>
+ <math><menclose notation="box"><mn>5</mn></menclose></math>
+ <math><menclose notation="roundedbox"><mn>6</mn></menclose></math>
+ <math><menclose notation="actuarial"><mn>7</mn></menclose></math>
+ <math><menclose notation="madruwb"><mn>8</mn></menclose></math>
+ <math><menclose notation="horizontalstrike"><mn>9</mn></menclose></math>
+ <math><menclose notation="verticalstrike"><mn>10</mn></menclose></math>
+ <math><menclose notation="updiagonalstrike"><mn>11</mn></menclose></math>
+ <math><menclose notation="downdiagonalstrike"><mn>12</mn></menclose></math>
+ <math><menclose notation="longdiv"><mn>13</mn></menclose></math>
+ <math><menclose notation="circle"><mn>14</mn></menclose></math>
+ </div>
+ </div>
+ <script>
+ window.addEventListener("load", () => {
+ document.getElementById("dynamic").style.visibility = "hidden";
+ document.documentElement.classList.remove("reftest-wait");
+ });
+ </script>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_menclose");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/visibility-005-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/visibility-005-ref.html
new file mode 100644
index 0000000000..fcaf5fe85b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/visibility-005-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>visibility (reference)</title>
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; width: 200px; height: 200px;">
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/visibility-005.html b/testing/web-platform/tests/mathml/relations/css-styling/visibility-005.html
new file mode 100644
index 0000000000..a3af376fea
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/visibility-005.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<title>visibility</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#operator-fence-separator-or-accent-mo">
+<link rel="match" href="visibility-005-ref.html"/>
+<meta name="assert" content="Verify that visibility=hidden is used for normal, stretchy and large operators.">
+<style>
+ math {
+ font: 20px/1 Ahem;
+ }
+ @font-face {
+ font-family: operators;
+ src: url("/fonts/math/operators.woff");
+ }
+ mo {
+ font-family: operators;
+ }
+</style>
+</head>
+<body>
+ <p>Test passes if you see a green square.</p>
+ <div style="background: green; color: red; width: 200px; height: 200px;">
+ <math>
+ <!-- unstretched operators -->
+ <mo style="visibility: hidden">⥯</mo>
+ <mo style="visibility: hidden">+</mo>
+ <mo style="visibility: hidden">-</mo>
+ </math>
+ <math displaystyle="true">
+ <!-- large operator -->
+ <mo largeop="true" style="visibility: hidden">⥯</mo>
+ </math>
+ <math>
+ <mrow>
+ <!-- stretchy, small size -->
+ <mspace height="2em"/>
+ <mo style="visibility: hidden">⥯</mo>
+ </mrow>
+ </math>
+ <math>
+ <mrow>
+ <!-- stretchy, large size -->
+ <mspace height="4em"/>
+ <mo style="visibility: hidden">⥯</mo>
+ </mrow>
+ </math>
+ <div id="dynamic">
+ <math>
+ <!-- unstretched operators -->
+ <mo stretchy="false">⥯</mo>
+ <mo>+</mo>
+ <mo>-</mo>
+ </math>
+ <math displaystyle="true">
+ <!-- large operator -->
+ <mo largeop="true">⥯</mo>
+ </math>
+ <math>
+ <mrow>
+ <!-- stretchy, small size -->
+ <mspace height="2em"/>
+ <mo>⥯</mo>
+ </mrow>
+ </math>
+ <math>
+ <mrow>
+ <!-- stretchy, large size -->
+ <mspace height="4em"/>
+ <mo>⥯</mo>
+ </mrow>
+ </math>
+ </div>
+ </div>
+ <script src="/mathml/support/fonts.js"></script>
+ <script>
+ window.addEventListener("load", () => loadAllFonts().then(() => {
+ document.getElementById("dynamic").style.visibility = "hidden";
+ document.documentElement.classList.remove("reftest-wait");
+ }));
+ </script>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_menclose");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/width-height-001.html b/testing/web-platform/tests/mathml/relations/css-styling/width-height-001.html
new file mode 100644
index 0000000000..2deedc3f0b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/width-height-001.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>width, height, inline-size and block-size</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<meta name="assert" content="Verify that width, height, inline-size and block-size properties are ignored.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<script src="/mathml/support/box-comparison.js"></script>
+<style>
+ /* Revert style specified in the UA style sheet that changes box size. */
+ merror { border: 0; }
+ mfrac { padding: 0; }
+</style>
+<script>
+ var epsilon = 1;
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+
+ for (tag in MathMLFragments) {
+ if (!FragmentHelper.isValidChildOfMrow(tag))
+ continue;
+
+ document.body.insertAdjacentHTML("beforeend", `<div style="position: absolute;"><math><mrow>${MathMLFragments[tag]}</mrow></math></div>`);
+ let div = document.body.lastElementChild;
+ let element = FragmentHelper.element(div.firstElementChild);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ var style = `width: 500px; height: 400px;`;
+ element.setAttribute("style", style);
+ let box = element.getBoundingClientRect();
+ assert_approx_equals(box.width, 500, epsilon, "width");
+ assert_approx_equals(box.height, 400, epsilon, "height");
+ }, `width and height properties on ${tag}`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection[`has_${tag}`](), `${tag} is supported`);
+ var style = `inline-size: 600px; block-size: 700px;`;
+ element.setAttribute("style", style);
+ let box = element.getBoundingClientRect();
+ assert_approx_equals(box.width, 600, epsilon, "width");
+ assert_approx_equals(box.height, 700, epsilon, "height");
+ }, `inline-size and block-size properties on ${tag}`);
+
+ div.style = "display: none;"; // Hide the div after measurement.
+ }
+
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/width-height-002-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/width-height-002-ref.html
new file mode 100644
index 0000000000..ed5125e952
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/width-height-002-ref.html
@@ -0,0 +1,162 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>content position with width/height (reference)</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body, math {
+ font: 25px/1 Ahem;
+ color: black;
+ }
+ .test {
+ margin: .5em;
+ }
+ .box {
+ width: 7em;
+ height: 3em;
+ border: 1px solid blue;
+ display: inline-block;
+ }
+ .center {
+ text-align: center;
+ }
+
+ /* Revert style specified in the UA style sheet that changes box size. */
+ mfrac { padding: 0; }
+</style>
+</head>
+<body>
+ <div class="test">
+ <div class="box">
+ <math>
+ <mtext>X</mtext>
+ </math>
+ </div>
+ <div class="box" dir="rtl">
+ <math dir="rtl">
+ <mtext>X</mtext>
+ </math>
+ </div>
+ </div>
+
+ <div class="test">
+ <div class="box">
+ <math>
+ <mrow>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mrow>
+ </math>
+ </div>
+ <div class="box" dir="rtl">
+ <math dir="rtl">
+ <mrow>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mrow>
+ </math>
+ </div>
+ </div>
+
+ <div class="test">
+ <div class="box">
+ <math>
+ <mpadded lspace="1em" voffset="-1em">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mpadded>
+ </math>
+ </diV>
+ <div class="box" dir="rtl">
+ <math dir="rtl">
+ <mpadded lspace="1em" voffset="-1em">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mpadded>
+ </math>
+ </div>
+ </div>
+
+ <div class="test">
+ <div class="box">
+ <math>
+ <mpadded width="9em" height="1em" depth=".5em">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mpadded>
+ </math>
+ </div>
+ <div class="box" dir="rtl">
+ <math dir="rtl">
+ <mpadded width="9em" height="1em" depth=".5em">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mpadded>
+ </math>
+ </div>
+ </div>
+
+ <div class="test">
+ <div class="box center">
+ <math>
+ <mfrac linethickness="0">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mfrac>
+ </math>
+ </div>
+ <div class="box center" dir="rtl">
+ <math dir="rtl">
+ <mfrac linethickness="0">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mfrac>
+ </math>
+ </div>
+ </div>
+
+ <div class="test">
+ <div class="box">
+ <math>
+ <msqrt>
+ <mtext>X</mtext>
+ </msqrt>
+ </math>
+ </div>
+ <div class="box" dir="rtl">
+ <math dir="rtl">
+ <msqrt>
+ <mtext>X</mtext>
+ </msqrt>
+ </math>
+ </div>
+ </div>
+
+ <div class="test">
+ <div class="box">
+ <math>
+ <mroot>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mroot>
+ </math>
+ </div>
+ <div class="box" dir="rtl">
+ <math dir="rtl">
+ <mroot>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mroot>
+ </math>
+ </div>
+ </div>
+
+</body>
+</htmL>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/width-height-002.html b/testing/web-platform/tests/mathml/relations/css-styling/width-height-002.html
new file mode 100644
index 0000000000..99822c1ed9
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/width-height-002.html
@@ -0,0 +1,135 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>content position with width/height</title>
+<link rel="match" href="width-height-002-ref.html">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<meta name="assert" content="Verify the inline-start and block-start edges of the math content box for the mtext, mrow, mpadded, mfrac, msqrt, mroot layout algorithms."/>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body, math {
+ font: 25px/1 Ahem;
+ color: black;
+ }
+ .test {
+ margin: .5em;
+ }
+ .box {
+ width: 7em;
+ height: 3em;
+ border: 1px solid blue;
+ }
+
+ /* Revert style specified in the UA style sheet that changes box size. */
+ mfrac { padding: 0; }
+</style>
+</head>
+<body>
+
+ <div class="test">
+ <math>
+ <mtext class="box">X</mtext>
+ </math>
+ <math dir="rtl">
+ <mtext class="box">X</mtext>
+ </math>
+ </div>
+
+ <div class="test">
+ <math>
+ <mrow class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mrow>
+ </math>
+ <math dir="rtl">
+ <mrow class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mrow>
+ </math>
+ </div>
+
+ <div class="test">
+ <math>
+ <mpadded lspace="1em" voffset="-1em" class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mpadded>
+ </math>
+ <math dir="rtl">
+ <mpadded lspace="1em" voffset="-1em" class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mpadded>
+ </math>
+ </div>
+
+ <div class="test">
+ <math>
+ <mpadded width="9em" height="1em" depth=".5em" class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mpadded>
+ </math>
+ <math dir="rtl">
+ <mpadded width="9em" height="1em" depth=".5em" class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mpadded>
+ </math>
+ </div>
+
+ <div class="test">
+ <math>
+ <mfrac class="box" linethickness="0">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mfrac>
+ </math>
+ <math dir="rtl">
+ <mfrac class="box" linethickness="0">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mfrac>
+ </math>
+ </div>
+
+ <div class="test">
+ <math>
+ <msqrt class="box">
+ <mtext>X</mtext>
+ </msqrt>
+ </math>
+ <math dir="rtl">
+ <msqrt class="box">
+ <mtext>X</mtext>
+ </msqrt>
+ </math>
+ </div>
+
+ <div class="test">
+ <math>
+ <mroot class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mroot>
+ </math>
+ <math dir="rtl">
+ <mroot class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mroot>
+ </math>
+ </div>
+
+</body>
+</htmL>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/width-height-003-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/width-height-003-ref.html
new file mode 100644
index 0000000000..84eb2cd089
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/width-height-003-ref.html
@@ -0,0 +1,178 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>content position with width/height (reference)</title>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body, math {
+ font: 25px/1 Ahem;
+ color: black;
+ }
+ .test {
+ margin: .5em;
+ }
+ .box {
+ width: 7em;
+ height: 3em;
+ border: 1px solid blue;
+ display: inline-block;
+ }
+ .center {
+ text-align: center;
+ }
+</style>
+</head>
+<body>
+
+ <div class="test">
+ <div class="box center">
+ <math>
+ <munder>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </munder>
+ </math>
+ </div>
+ <div class="box center" dir="rtl">
+ <math dir="rtl">
+ <munder>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </munder>
+ </math>
+ </div>
+ </div>
+
+ <div class="test">
+ <div class="box center">
+ <math>
+ <mover>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mover>
+ </math>
+ </div>
+ <div class="box center" dir="rtl">
+ <math dir="rtl">
+ <mover>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mover>
+ </math>
+ </div>
+ </div>
+
+ <div class="test">
+ <div class="box center">
+ <math>
+ <munderover>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </munderover>
+ </math>
+ </div>
+ <div class="box center" dir="rtl">
+ <math dir="rtl">
+ <munderover>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </munderover>
+ </math>
+ </div>
+ </div>
+
+ <div class="test">
+ <div class="box">
+ <math>
+ <msub>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </msub>
+ </math>
+ </div>
+ <div class="box" dir="rtl">
+ <math dir="rtl">
+ <msub>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </msub>
+ </math>
+ </div>
+ </div>
+
+ <div class="test">
+ <div class="box">
+ <math>
+ <msup>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </msup>
+ </math>
+ </div>
+ <div class="box" dir="rtl">
+ <math dir="rtl">
+ <msup>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </msup>
+ </math>
+ </div>
+ </div>
+
+ <div class="test">
+ <div class="box">
+ <math>
+ <msubsup>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </msubsup>
+ </math>
+ </div>
+ <div class="box" dir="rtl">
+ <math dir="rtl">
+ <msubsup>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </msubsup>
+ </math>
+ </div>
+ </div>
+
+ <div class="test">
+ <div class="box">
+ <math>
+ <mmultiscripts>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mprescripts/>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mmultiscripts>
+ </math>
+ </div>
+ <div class="box" dir="rtl">
+ <math dir="rtl">
+ <mmultiscripts>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mprescripts/>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mmultiscripts>
+ </math>
+ </div>
+ </div>
+
+</body>
+</htmL>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/width-height-003.html b/testing/web-platform/tests/mathml/relations/css-styling/width-height-003.html
new file mode 100644
index 0000000000..05e00f4759
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/width-height-003.html
@@ -0,0 +1,150 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>content position with width/height</title>
+<link rel="match" href="width-height-003-ref.html">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+<meta name="assert" content="Verify the inline-start and block-start edges of the math content box for the munder, mover, munderover, msub, msup, msubsup, multiscripts layout algorithms."/>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ body, math {
+ font: 25px/1 Ahem;
+ color: black;
+ }
+ .test {
+ margin: .5em;
+ }
+ .box {
+ width: 7em;
+ height: 3em;
+ border: 1px solid blue;
+ }
+</style>
+</head>
+<body>
+
+ <div class="test">
+ <math>
+ <munder class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </munder>
+ </math>
+ <math dir="rtl">
+ <munder class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </munder>
+ </math>
+ </div>
+
+ <div class="test">
+ <math>
+ <mover class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mover>
+ </math>
+ <math dir="rtl">
+ <mover class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mover>
+ </math>
+ </div>
+
+ <div class="test">
+ <math>
+ <munderover class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </munderover>
+ </math>
+ <math dir="rtl">
+ <munderover class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </munderover>
+ </math>
+ </div>
+
+ <div class="test">
+ <math>
+ <msub class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </msub>
+ </math>
+ <math dir="rtl">
+ <msub class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </msub>
+ </math>
+ </div>
+
+ <div class="test">
+ <math>
+ <msup class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </msup>
+ </math>
+ <math dir="rtl">
+ <msup class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </msup>
+ </math>
+ </div>
+
+ <div class="test">
+ <math>
+ <msubsup class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </msubsup>
+ </math>
+ <math dir="rtl">
+ <msubsup class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </msubsup>
+ </math>
+ </div>
+
+ <div class="test">
+ <math>
+ <mmultiscripts class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mprescripts/>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mmultiscripts>
+ </math>
+ <math dir="rtl">
+ <mmultiscripts class="box">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mprescripts/>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mmultiscripts>
+ </math>
+ </div>
+
+</body>
+</htmL>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/width-height-004.html b/testing/web-platform/tests/mathml/relations/css-styling/width-height-004.html
new file mode 100644
index 0000000000..7133573b04
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/width-height-004.html
@@ -0,0 +1,133 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>content position with width/height</title>
+<link rel="match" href="width-height-003-ref.html">
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+<meta name="assert" content="Verify the inline-start of the children of the munder, mover, munderover and mfrac layout algorithms."/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<script src="/mathml/support/fonts.js"></script>
+<style>
+ .test, math {
+ font: 25px/1 Ahem;
+ color: black;
+ }
+ .test {
+ margin: .5em;
+ }
+ [data-name] {
+ width: 7em;
+ height: 3em;
+ border: 1px solid blue;
+ }
+</style>
+<script>
+ var epsilon = 1;
+
+ function getMiddle(aElement) {
+ let box = aElement.getBoundingClientRect();
+ return (box.left + box.right) / 2;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", () => { loadAllFonts().then(runTests); });
+
+ function runTests() {
+ Array.from(document.querySelectorAll("[data-name]")).forEach(element => {
+ test(() => {
+ let elementMiddle = getMiddle(element);
+ Array.from(element.children).forEach(child => {
+ assert_approx_equals(getMiddle(child), elementMiddle, epsilon);
+ });
+ }, element.dataset.name);
+ });
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+
+ <div class="test">
+ <math>
+ <mfrac data-name="mfrac">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mfrac>
+ </math>
+ <math dir="rtl">
+ <mfrac data-name="RTL mfrac">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mfrac>
+ </math>
+ </div>
+
+ <div class="test">
+ <math>
+ <mfrac linethickness="0" data-name="mfrac without bar">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mfrac>
+ </math>
+ <math dir="rtl">
+ <mfrac linethickness="0" data-name="RTL mfrac without bar">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mfrac>
+ </math>
+ </div>
+
+ <div class="test">
+ <math>
+ <munder data-name="munder">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </munder>
+ </math>
+ <math dir="rtl">
+ <munder data-name="RTL munder">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </munder>
+ </math>
+ </div>
+
+ <div class="test">
+ <math>
+ <mover data-name="mover">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mover>
+ </math>
+ <math dir="rtl">
+ <mover data-name="RTL mover">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </mover>
+ </math>
+ </div>
+
+ <div class="test">
+ <math>
+ <munderover data-name="munderover">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </munderover>
+ </math>
+ <math dir="rtl">
+ <munderover data-name="RTL munderover">
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ <mtext>X</mtext>
+ </munderover>
+ </math>
+ </div>
+
+</body>
+</htmL>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/writing-mode/force-horizontal-tb.html b/testing/web-platform/tests/mathml/relations/css-styling/writing-mode/force-horizontal-tb.html
new file mode 100644
index 0000000000..e239cdca5a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/writing-mode/force-horizontal-tb.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Forced writing-mode on MathML elements</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#user-agent-stylesheet">
+<meta name="assert" content="Test that writing-mode is forced to horizontal-tb on MathML elements.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<style>
+ /* selector defined in mathml-fragments.js */
+ .element {
+ writing-mode: vertical-lr;
+ padding-block-start: 10px;
+ padding-block-end: 15px;
+ padding-inline-start: 20px;
+ padding-inline-end: 25px;
+ }
+</style>
+</head>
+<body>
+ <div id="log"></div>
+ <div id="container">
+ <math class="element"></math>
+ </div>
+ <script>
+ var container = document.getElementById("container");
+ for (tag in MathMLFragments) {
+ container.insertAdjacentHTML("beforeend", `<math>${MathMLFragments[tag]}</math>`);
+ }
+ let unknownElement = FragmentHelper.createElement("unknown");
+ unknownElement.setAttribute("class", "element");
+ container.appendChild(unknownElement);
+ Array.from(document.getElementsByClassName("element")).forEach(element => {
+ var tag = element.tagName;
+ var style = window.getComputedStyle(element);
+ test(function () {
+ assert_equals(style["writing-mode"], "horizontal-tb");
+ }, `writing-mode is forced to horizontal-tb on <${tag}> element`);
+ test(function () {
+ assert_equals(style["padding-block-start"], style["padding-top"]);
+ assert_equals(style["padding-block-end"], style["padding-bottom"]);
+ assert_equals(style["padding-inline-start"], style["padding-left"]);
+ assert_equals(style["padding-inline-end"], style["padding-right"]);
+ }, `logical properties interpreted in horizontal-tb on <${tag}> element`);
+ });
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/writing-mode/reset-and-logicial-property-ref.html b/testing/web-platform/tests/mathml/relations/css-styling/writing-mode/reset-and-logicial-property-ref.html
new file mode 100644
index 0000000000..6eae88efb1
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/writing-mode/reset-and-logicial-property-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Reset writing-mode and logical property (reference)</title>
+ </head>
+ <body>
+ <p>Test passes if you see a green square.</p>
+ <math style="writing-mode: horizontal-tb;
+ padding-top: 200px;
+ background: green">
+ <mspace width="200px"/>
+ </math>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/writing-mode/reset-and-logicial-property.html b/testing/web-platform/tests/mathml/relations/css-styling/writing-mode/reset-and-logicial-property.html
new file mode 100644
index 0000000000..939cfc5ba6
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/writing-mode/reset-and-logicial-property.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Reset writing-mode and logical property</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+ <meta name="assert" content="Verify how forced writing-mode is taken into account for logicial properties.">
+ <link rel="match" href="reset-and-logicial-property-ref.html">
+ </head>
+ <body>
+ <p>Test passes if you see a green square.</p>
+ <math style="writing-mode: vertical-lr;
+ padding-block-start: 200px;
+ background: green">
+ <mspace width="200px"/>
+ </math>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");</script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/writing-mode/writing-mode-001.html b/testing/web-platform/tests/mathml/relations/css-styling/writing-mode/writing-mode-001.html
new file mode 100644
index 0000000000..b751caf90d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/writing-mode/writing-mode-001.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>writing mode</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<meta name="assert" content="Verify CSS writing mode (writing-mode and directionproperties) for mrow.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/layout-comparison.js"></script>
+<script>
+ var epsilon = 1;
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+ var reference = document.getElementById("horizontal-tb_ltr");
+
+ ["horizontal-tb_rtl"].forEach(id => {
+ var element = document.getElementById(id);
+
+ test(function() {
+ var style = window.getComputedStyle(element);
+ var writingMode = id.split("_");
+ assert_equals(style.getPropertyValue("writing-mode"),
+ writingMode[0], "writing-mode");
+ assert_equals(style.getPropertyValue("direction"),
+ writingMode[1], "direction");
+ }, `Inheritance of CSS writing-mode and direction (id='${id}')`);
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ compareLayout(element, reference, epsilon);
+ }, `Layout of mrow (id='${id}')`);
+ });
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mrow id="horizontal-tb_ltr">
+ <mspace style="background: blue"
+ width="20px" height="30px" depth="40px"></mspace>
+ <mspace style="background: black"
+ width="50px" depth="60px"></mspace>
+ <mspace style="background: yellow"
+ width="70px" height="80px"></mspace>
+ </mrow>
+ </math>
+ </p>
+ <p>
+ <math style="direction: rtl;">
+ <mrow id="horizontal-tb_rtl">
+ <mspace style="background: blue"
+ width="20px" height="30px" depth="40px"></mspace>
+ <mspace style="background: black"
+ width="50px" depth="60px"></mspace>
+ <mspace style="background: yellow"
+ width="70px" height="80px"></mspace>
+ </mrow>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/css-styling/writing-mode/writing-mode-002.html b/testing/web-platform/tests/mathml/relations/css-styling/writing-mode/writing-mode-002.html
new file mode 100644
index 0000000000..c0b64a917a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/css-styling/writing-mode/writing-mode-002.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>writing mode</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#layout-algorithms">
+<meta name="assert" content="Verify CSS writing mode (writing-mode and direction properties) for mrow.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/layout-comparison.js"></script>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<script>
+ var epsilon = 1;
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", runTests);
+
+ function runTests() {
+ for (tag in MathMLFragments) {
+ if (tag == "annotation" || tag == "annotation-xml")
+ continue; // These tags have display: none.
+
+ ["horizontal-tb_rtl"].forEach(id => {
+ var writingMode = id.split("_");
+ var writingModeString = `writing-mode: ${writingMode[0]}; direction: ${writingMode[1]};`;
+
+ document.body.insertAdjacentHTML("beforeend", `<div>\
+<math>${MathMLFragments[tag]}</math>\
+<math>${MathMLFragments[tag]}</math>\
+</div>`);
+ var div = document.body.lastElementChild;
+
+ var styleMath = div.firstElementChild;
+ styleMath.setAttribute("style", writingModeString);
+ var styleElement = FragmentHelper.element(styleMath);
+
+ var referenceMath = div.lastElementChild;
+ var referenceElement = FragmentHelper.element(referenceMath);
+
+ [styleMath, referenceMath].forEach(math => {
+ Array.from(math.getElementsByClassName("mathml-container")).forEach(container => {
+ container.insertAdjacentHTML("beforeend", "\
+<mspace style='background: blue'\
+ width='20px' height='30px' depth='40px'></mspace>\
+<mspace style='background: black'\
+ width='50px' depth='60px'></mspace>\
+<mspace style='background: yellow'\
+ width='70px' height='80px'></mspace>");
+ });
+ Array.from(math.getElementsByClassName("foreign-container")).forEach(container => {
+ container.insertAdjacentHTML("beforeend", "\
+<span style='display: inline-block; background: lightblue;\
+ inline-size: 20px; block-size: 30px;\
+ vertical-align: bottom;'></span>\
+<span style='display: inline-block; background: pink;\
+ inline-size: 40px; block-size: 50px;\
+ vertical-align: bottom;'></span>");
+ });
+ });
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ var style = window.getComputedStyle(styleElement);
+ assert_equals(style.getPropertyValue("writing-mode"),
+ writingMode[0], "writing-mode");
+ assert_equals(style.getPropertyValue("direction"),
+ writingMode[1], "direction");
+ compareLayout(styleElement, referenceElement, epsilon);
+ }, `Layout of ${tag} (${writingModeString})`);
+
+ div.style = "display: none;"; // Hide the div after testing.
+ });
+ }
+ done();
+ }
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/class-1-ref.html b/testing/web-platform/tests/mathml/relations/html5-tree/class-1-ref.html
new file mode 100644
index 0000000000..5afa59ecf2
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/class-1-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Class (reference)</title>
+</head>
+<body>
+
+ <p>Test passes if you see the text "PASS".</p>
+ <math>
+ <mtext style="background: green; color: white;">PASS</mtext>
+ </math>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/class-1.html b/testing/web-platform/tests/mathml/relations/html5-tree/class-1.html
new file mode 100644
index 0000000000..fd1678d440
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/class-1.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Class</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="match" href="class-1-ref.html"/>
+<meta name="assert" content="Verify that the class attribute affects CSS selectors.">
+<style>
+ mtext.fail { display: none; }
+ mtext.pass { background: green; }
+</style>
+</head>
+<body>
+
+ <p>Test passes if you see the text "PASS".</p>
+ <math>
+ <mtext class="fail" style="background: red; color: white;">FAIL</mtext>
+ <mtext class="pass" style="color: white;">PASS</mtext>
+ </math>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/class-2.html b/testing/web-platform/tests/mathml/relations/html5-tree/class-2.html
new file mode 100644
index 0000000000..e694b063a6
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/class-2.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Class</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript">
+<meta name="assert" content="Verify whether the getElementsByClassName() works for MathML elements.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("DOMContentLoaded", function() {
+ var mtext = document.getElementsByClassName("cl");
+ test(function() {
+ assert_equals(mtext.length, 3);
+ var mtext_ref = document.body.lastElementChild.firstElementChild;
+ mtext_ref = mtext_ref.nextElementSibling.nextElementSibling
+ assert_equals(mtext[0], mtext_ref);
+ mtext_ref = mtext_ref.nextElementSibling.nextElementSibling;
+ assert_equals(mtext[1], mtext_ref);
+ mtext_ref = mtext_ref.nextElementSibling.nextElementSibling;
+ assert_equals(mtext[2], mtext_ref);
+ }, "getElementsByClassName()");
+ done();
+ });
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <math>
+ <mtext class="cl_"></mtext>
+ <mtext class="c"></mtext>
+ <mtext class="cl"></mtext>
+ <mtext class="cl_"></mtext>
+ <mtext class="cl"></mtext>
+ <mtext class="c"></mtext>
+ <mtext class="cl"></mtext>
+ <mtext class="cl_"></mtext>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/clipboard-event-handlers.tentative.html b/testing/web-platform/tests/mathml/relations/html5-tree/clipboard-event-handlers.tentative.html
new file mode 100644
index 0000000000..bf2f8d11ed
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/clipboard-event-handlers.tentative.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<title>clipboard event handlers for MathML</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript"/>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/webappapis.html#globaleventhandlers"/>
+<link rel="help" href="https://w3c.github.io/clipboard-apis/#clipboard-event-copy"/>
+<link rel="help" href="https://w3c.github.io/clipboard-apis/#clipboard-event-cut"/>
+<link rel="help" href="https://w3c.github.io/clipboard-apis/#clipboard-event-paste"/>
+<meta
+ name="assert"
+ content="MathMLElements incorporates oncopy / oncut / onpaste event handlers"
+/>
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<math
+ oncopy="window.copyHappened1 = true"
+ oncut="window.cutHappened1 = true"
+ onpaste="window.pasteHappened1 = true"
+>
+ <mi>E</mi>
+</math>
+<script>
+ const EVENTS = ["copy", "cut", "paste"];
+ const el = document.querySelector("math");
+
+ function dispatchEventTest(name) {
+ const mathEl = document.createElementNS(
+ "http://www.w3.org/1998/Math/MathML",
+ "math"
+ );
+ test(() => {
+ let target = undefined;
+ mathEl[`on${name}`] = (e) => { target = e.currentTarget; }
+ const event = new ClipboardEvent(name, {
+ bubbles: true,
+ cancellable: true
+ });
+ mathEl.dispatchEvent(event);
+ assert_equals(target, mathEl, "The event must be fired at the <math> element");
+ }, `${name}: dispatching an Event at a <math> element must trigger element.on${name}`);
+ }
+
+ function evaluatedHandlerTest(name) {
+ const handlerName = "on" + name;
+
+ test(() => {
+ const compiledHandler = el[handlerName];
+
+ assert_equals(
+ typeof compiledHandler,
+ "function",
+ `The ${handlerName} property must be a function`
+ );
+ compiledHandler();
+ assert_true(
+ window[`${name}Happened1`],
+ "Calling the handler must run the code"
+ );
+ }, `${handlerName}: the content attribute must be compiled into a function as the corresponding property`);
+
+ test(() => {
+ const mathEl = document.createElementNS(
+ "http://www.w3.org/1998/Math/MathML",
+ "math"
+ );
+ assert_equals(mathEl[handlerName], null, `The ${handlerName} property must be null (no attribute)`);
+
+ mathEl.setAttribute(handlerName, `window.${handlerName}Happened2 = true;`);
+ const compiledHandler = mathEl[handlerName];
+ assert_equals(
+ typeof compiledHandler,
+ "function",
+ `The ${handlerName} property must be a function (set attribute)`
+ );
+ compiledHandler();
+ assert_true(
+ window[`${handlerName}Happened2`],
+ "Calling the handler must run the code (set attribute)"
+ );
+
+ window[`${handlerName}Happened2`] = false;
+ const clonedMathEl = mathEl.cloneNode(true);
+ const clonedCompiledHandler = clonedMathEl[handlerName];
+ assert_equals(
+ typeof clonedCompiledHandler,
+ "function",
+ `The ${handlerName} property must be a function (clone node)`
+ );
+ clonedCompiledHandler();
+ assert_true(
+ window[`${handlerName}Happened2`],
+ "Calling the handler must run the code (clone node)"
+ );
+
+ mathEl.setAttribute(handlerName, `window.${handlerName}Happened3 = true;`);
+ const newCompiledHandler = mathEl[handlerName];
+ assert_equals(
+ typeof newCompiledHandler,
+ "function",
+ `The ${handlerName} property must be a function (modify attribute)`
+ );
+ newCompiledHandler();
+ assert_true(
+ window[`${handlerName}Happened3`],
+ "Calling the handler must run the code (modify attribute)"
+ );
+
+ mathEl.removeAttribute(handlerName);
+ assert_equals(mathEl[handlerName], null, `The ${handlerName} property must be null (remove attribute)`);
+ }, `${handlerName}: dynamic changes on the attribute`);
+
+ }
+
+ EVENTS.forEach(name => {
+ dispatchEventTest(name);
+ evaluatedHandlerTest(name);
+ });
+</script>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/color-attributes-1-ref.html b/testing/web-platform/tests/mathml/relations/html5-tree/color-attributes-1-ref.html
new file mode 100644
index 0000000000..71ee8cea9d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/color-attributes-1-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Color Attributes (reference)</title>
+<style>
+ #content > div {
+ position: absolute;
+ }
+</style>
+</head>
+<body>
+
+ <p>Test passes if you see the text below is written in white on a green
+ background.</p>
+
+ <div id="content">
+ <div>
+ <math style="background: green;">
+ <mtext style="color: white;">Hello World!</mtext>
+ </math>
+ </div>
+ </div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/color-attributes-1.html b/testing/web-platform/tests/mathml/relations/html5-tree/color-attributes-1.html
new file mode 100644
index 0000000000..211bda7f85
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/color-attributes-1.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Color Attributes</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#legacy-mathml-style-attributes">
+<meta name="assert" content="Verify that the mathcolor and mathbackground attributes are supported on the math element.">
+<link rel="match" href="color-attributes-1-ref.html"/>
+<style>
+ #content {
+ color: red;
+ }
+ #content > div {
+ position: absolute;
+ }
+</style>
+</head>
+<body>
+
+ <p>Test passes if you see the text below is written in white on a green
+ background.</p>
+
+ <div id="content">
+ <div>
+ <math style="background: red;">
+ <mtext style="visibility: hidden;">Hello World!</mtext>
+ </math>
+ </div>
+ <div>
+ <math mathcolor="white" mathbackground="green">
+ <mtext>Hello World!</mtext>
+ </math>
+ </div>
+ </div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/content-editable.html b/testing/web-platform/tests/mathml/relations/html5-tree/content-editable.html
new file mode 100644
index 0000000000..28e8630829
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/content-editable.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>MathML inside content-editable</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#html-and-svg">
+<meta name="assert" content="Verify that putting MathML inside a content-editable div shouldn't affect its layout.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("DOMContentLoaded", function() {
+ var epsilon = 1;
+ var mfrac = document.getElementById("mfrac");
+ var num = mfrac.firstElementChild.getBoundingClientRect();
+ var denom = mfrac.lastElementChild.getBoundingClientRect();
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_approx_equals(num.width, 30, epsilon, "numerator width");
+ assert_approx_equals(num.height, 40, epsilon, "numerator height");
+ assert_approx_equals(denom.width, 50, epsilon, "denominator width");
+ assert_approx_equals(denom.height, 60, epsilon, "denominator height");
+ }, "mspace layout in content-editable div");
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mfrac());
+ assert_greater_than_equal(denom.bottom - num.top,
+ (40 + 60),
+ "numerator is above the denominator");
+ assert_approx_equals((num.left + num.right) / 2,
+ (denom.left + denom.right) / 2,
+ epsilon, "numerator and denominator are horizontally aligned");
+ }, "mfrac layout in content-editable div");
+ done();
+ });
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <div contenteditable="true">
+ This is
+ <math>
+ <mfrac id="mfrac">
+ <mspace width="30px" height="40px" style="background: cyan"></mspace>
+ <mspace width="50px" height="60px" style="background: yellow"></mspace>
+ </mfrac>
+ </math>
+ a content editable div
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/css-inline-style-dynamic.tentative-ref.html b/testing/web-platform/tests/mathml/relations/html5-tree/css-inline-style-dynamic.tentative-ref.html
new file mode 100644
index 0000000000..19f3e6c82a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/css-inline-style-dynamic.tentative-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>MathML 'ElementCSSInlineStyle` Dynamic Tests</title>
+<style>
+mspace {
+ background-color: green;
+}
+</style>
+</head>
+<body>
+ <span>This tests that `ElementCSSInlineStyle` interface changes update rendering.</span>
+ <div>
+ <math><mspace width="50px" height="100px"/><mspace width="50px" height="100px"/></math>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/css-inline-style-dynamic.tentative.html b/testing/web-platform/tests/mathml/relations/html5-tree/css-inline-style-dynamic.tentative.html
new file mode 100644
index 0000000000..5d27d6a7e6
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/css-inline-style-dynamic.tentative.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <meta charset="utf-8" />
+ <title>MathML 'ElementCSSInlineStyle` Dynamic Tests</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript"/>
+ <link rel="match" href="css-inline-style-dynamic.tentative-ref.html"/>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <style>
+ #hidden {
+ visibility: hidden;
+ background-color: green;
+ }
+ #red {
+ background-color: red;
+ }
+ </style>
+ <meta
+ name="assert"
+ content="MathMLElements ElementCSSInlineStyle interface changes update rendering"
+ />
+ <script type="text/javascript">
+ function test()
+ {
+ MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");
+ document.body.offsetTop; // Update layout
+
+ var mspace = document.getElementById("hidden");
+ if (mspace.style)
+ mspace.style.visibility = "visible";
+
+ mspace = document.getElementById("red");
+ if (mspace.style)
+ mspace.style.backgroundColor = "green";
+
+ document.documentElement.className = "";
+ }
+ </script>
+ </head>
+ <body onload="test()">
+ <span>This tests that `ElementCSSInlineStyle` interface changes update rendering.</span>
+ <div>
+ <math><mspace width="50px" height="100px" id="hidden"/><mspace width="50px" height="100px" id="red"/></math>
+ </div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/css-inline-style-interface.tentative.html b/testing/web-platform/tests/mathml/relations/html5-tree/css-inline-style-interface.tentative.html
new file mode 100644
index 0000000000..f8348c15b2
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/css-inline-style-interface.tentative.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>MathML 'ElementCSSInlineStyle` Mixin Tests</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript"/>
+ <style>
+ math * {
+ background-color: red;
+ }
+ </style>
+ <meta
+ name="assert"
+ content="MathMLElements incorporate a functional ElementCSSInlineStyle interface"
+ />
+ <script src="/mathml/support/mathml-fragments.js"></script>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <span
+ >This tests the presence and functionality of features of the
+ `ElementCSSInlineStyle` interface for MathMLElements</span
+ >
+ <math></math>
+ <script>
+ let mathEl = document.querySelector("math");
+
+ test(function() {
+ mathEl.style.backgroundColor = "lime";
+ assert_equals(
+ getComputedStyle(mathEl).backgroundColor,
+ "rgb(0, 255, 0)",
+ "The applied background should be green."
+ );
+ }, `The <math> element style property should be present and be functional.`);
+
+ Object.keys(MathMLFragments).forEach(elName => {
+ mathEl.innerHTML = MathMLFragments[elName];
+
+ test(function() {
+ let el = FragmentHelper.element(mathEl);
+ el.style.backgroundColor = "blue";
+
+ assert_equals(
+ getComputedStyle(el).backgroundColor,
+ "rgb(0, 0, 255)",
+ "The applied background should be blue."
+ );
+ }, `The ${elName}'s style property should be present and be functional.`);
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/display-1.html b/testing/web-platform/tests/mathml/relations/html5-tree/display-1.html
new file mode 100644
index 0000000000..fa92771fac
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/display-1.html
@@ -0,0 +1,175 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>MathML display attribute</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-top-level-math-element">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript">
+<meta name="assert" content="Verify that the display attribute on the math element is supported and impacts centering and line breaking with surrounding content.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/attribute-values.js"></script>
+<script>
+ function getBox(aId) {
+ return document.getElementById(aId).getBoundingClientRect();
+ }
+ window.addEventListener("DOMContentLoaded", function() {
+ for (transform in AttributeValueTransforms) {
+ TransformAttributeValues(transform, ["display"]);
+ var content = getBox("content");
+
+ var before_block = getBox("before_block");
+ var mspace_block = getBox("mspace_block");
+ var after_block = getBox("after_block");
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_approx_equals(before_block.left, content.left, 1,
+ "content before must be left aligned");
+ assert_approx_equals((mspace_block.left + mspace_block.right) / 2,
+ (content.left + content.right) / 2,
+ 1,
+ "math must be centered.");
+ assert_approx_equals(after_block.left, content.left, 1,
+ "content after must be left aligned");
+ assert_less_than_equal(before_block.bottom, mspace_block.top,
+ "new line before math");
+ assert_less_than_equal(mspace_block.bottom, after_block.top,
+ "new line after math");
+ }, `Test display math ${transform}`);
+
+ var before_inline = getBox("before_inline");
+ var mspace_inline = getBox("mspace_inline");
+ var after_inline = getBox("after_inline");
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_approx_equals((before_inline.top + before_inline.bottom) / 2,
+ (mspace_inline.top + mspace_inline.bottom) / 2,
+ 1,
+ "content before must be horizontally aligned with math");
+ assert_approx_equals((after_inline.top + after_inline.bottom) / 2,
+ (mspace_inline.top + mspace_inline.bottom) / 2,
+ 1,
+ "content after must be horizontally aligned with math");
+ assert_less_than_equal(before_inline.right, mspace_inline.left,
+ "content before must be on the left of math");
+ assert_less_than_equal(mspace_inline.right, after_inline.left,
+ "content after must be on the right of math");
+ }, `Test inline math ${transform}`);
+
+ var before_block_and_specified_width = getBox("before_block_and_specified_width");
+ var mspace_width = getBox("mspace_width");
+ var after_block_and_specified_width = getBox("after_block_and_specified_width");
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ let math = getBox("math_with_specified_width");
+ assert_approx_equals(before_block_and_specified_width.left, math.left, 1,
+ "content before must be left aligned");
+ assert_approx_equals(math.width, 100, 1,
+ "math uses specified width.");
+ assert_approx_equals((mspace_width.left + mspace_width.right) / 2,
+ (math.left + math.right) / 2,
+ 1,
+ "math must be centered.");
+ assert_approx_equals(after_block_and_specified_width.left, math.left, 1,
+ "content after must be left aligned");
+ assert_less_than_equal(before_block_and_specified_width.bottom, mspace_width.top,
+ "new line before math");
+ assert_less_than_equal(mspace_width.bottom, after_block_and_specified_width.top,
+ "new line after math");
+ }, `Test width on display=block math ${transform}`);
+ }
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ document.getElementById("mspace_dynamic_block").parentNode.
+ setAttribute("display", "block");
+ var before_block = getBox("before_dynamic_block");
+ var mspace_block = getBox("mspace_dynamic_block");
+ var after_block = getBox("after_dynamic_block");
+
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_approx_equals(before_block.left, content.left, 1,
+ "content before must be left aligned");
+ assert_approx_equals((mspace_block.left + mspace_block.right) / 2,
+ (content.left + content.right) / 2,
+ 1,
+ "math must be centered.");
+ assert_approx_equals(after_block.left, content.left, 1,
+ "content after must be left aligned");
+ assert_less_than_equal(before_block.bottom, mspace_block.top,
+ "new line before math");
+ assert_less_than_equal(mspace_block.bottom, after_block.top,
+ "new line after math");
+ }, "Test dynamically setting display=block");
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ document.getElementById("mspace_dynamic_inline").parentNode.
+ removeAttribute("display");
+ var before_inline = getBox("before_dynamic_inline");
+ var mspace_inline = getBox("mspace_dynamic_inline");
+ var after_inline = getBox("after_dynamic_inline");
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_approx_equals((before_inline.top + before_inline.bottom) / 2,
+ (mspace_inline.top + mspace_inline.bottom) / 2,
+ 1,
+ "content before must be horizontally aligned with math");
+ assert_approx_equals((after_inline.top + after_inline.bottom) / 2,
+ (mspace_inline.top + mspace_inline.bottom) / 2,
+ 1,
+ "content after must be horizontally aligned with math");
+ assert_less_than_equal(before_inline.right, mspace_inline.left,
+ "content before must be on the left of math");
+ assert_less_than_equal(mspace_inline.right, after_inline.left,
+ "content after must be on the right of math");
+ }, "Test dynamically setting display=inline");
+
+ done();
+ });
+</script>
+<style>
+ #content {
+ width: 600px;
+ background: #ccc;
+ }
+ span.square {
+ display: inline-block;
+ width: 50px;
+ height: 50px;
+ background: black;
+ }
+ mspace {
+ background: blue;
+ }
+</style>
+</head>
+<body>
+ <div id="log"></div>
+ <div id="content">
+ <span id="before_block" class="square"></span>
+ <math display="block"><mspace id="mspace_block" width="50px" height="50px"/></math>
+ <span id="after_block" class="square"></span>
+ <br/>
+ <span id="before_inline" class="square"></span>
+ <math display="inline"><mspace id="mspace_inline" width="50px" height="50px"/></math>
+ <span id="after_inline" class="square"></span>
+ <br/>
+ <span id="before_block_and_specified_width" class="square"></span>
+ <math display="block" id="math_with_specified_width" style="background: pink; width:100px"><mspace id="mspace_width" width="50px" height="50px"/></math>
+ <span id="after_block_and_specified_width" class="square"></span>
+ <br/>
+ <div>
+ <span id="before_dynamic_block" class="square"></span>
+ <math><mspace id="mspace_dynamic_block" width="50px" height="50px"/></math>
+ <span id="after_dynamic_block" class="square"></span>
+ </div>
+ <div>
+ <span id="before_dynamic_inline" class="square"></span>
+ <math display="block"><mspace id="mspace_dynamic_inline" width="50px" height="50px"/></math>
+ <span id="after_dynamic_inline" class="square"></span>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/display-2-ref.html b/testing/web-platform/tests/mathml/relations/html5-tree/display-2-ref.html
new file mode 100644
index 0000000000..7864c04099
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/display-2-ref.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>display attribute VS legacy mode attribute (reference)</title>
+</head>
+<body>
+ <p>Test passes if you see four green squares, the last one
+ centered and the others left-aligned.</p>
+ <p>
+ <math>
+ <mspace width="100px" height="100px" style="background: green"></mspace>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mspace width="100px" height="100px" style="background: green"></mspace>
+ </math>
+ </p>
+ <p>
+ <math display="inline">
+ <mspace width="100px" height="100px" style="background: green"></mspace>
+ </math>
+ </p>
+ <p>
+ <math display="block">
+ <mspace width="100px" height="100px" style="background: green"></mspace>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/display-2.html b/testing/web-platform/tests/mathml/relations/html5-tree/display-2.html
new file mode 100644
index 0000000000..b4e79395a1
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/display-2.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>display attribute VS legacy mode attribute</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-top-level-math-element">
+<link rel="help" href="https://www.w3.org/TR/MathML3/chapter2.html#id.2.2.2">
+<link rel="match" href="display-2-ref.html"/>
+<meta name="assert" content="Verify that the legacy mode attribute has no effect.">
+</head>
+<body>
+ <p>Test passes if you see four green squares, the last one
+ centered and the others left-aligned.</p>
+ <p>
+ <math mode="inline">
+ <mspace width="100px" height="100px" style="background: green"></mspace>
+ </math>
+ </p>
+ <p>
+ <math mode="display">
+ <mspace width="100px" height="100px" style="background: green"></mspace>
+ </math>
+ </p>
+ <p>
+ <math display="inline" mode="display">
+ <mspace width="100px" height="100px" style="background: green"></mspace>
+ </math>
+ </p>
+ <p>
+ <math display="block" mode="inline">
+ <mspace width="100px" height="100px" style="background: green"></mspace>
+ </math>
+ </p>
+ <script src="/mathml/support/feature-detection.js"></script>
+ <script>MathMLFeatureDetection.ensure_for_match_reftest("has_mspace");</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-1-ref.html b/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-1-ref.html
new file mode 100644
index 0000000000..5fa90e9d2f
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-1-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Dynamic MathML DOM (reference)</title>
+<style>
+ mtext.pass { background: green; color: white; }
+</style>
+</head>
+<body>
+ <p>Test passes if you see the text "PASS".</p>
+ <math>
+ <mtext class="pass">PASS</mtext>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-1.html b/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-1.html
new file mode 100644
index 0000000000..59403196a8
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-1.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Dynamic MathML DOM</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript"/>
+<link rel="match" href="dynamic-1-ref.html"/>
+<meta name="assert" content="Verify that the MathML DOM tree can be modified via javascript and that the rendering is correctly updated.">
+<style>
+ mtext.fail { background: red; color: white; }
+ mtext.pass { background: green; color: white; }
+</style>
+<script>
+ window.addEventListener("DOMContentLoaded", function() {
+ var kMathMLNamespace = "http://www.w3.org/1998/Math/MathML";
+ var mtext = document.createElementNS(kMathMLNamespace, "mtext");
+ mtext.setAttribute("class", "pass");
+ mtext.textContent = "PASS";
+ var math = document.getElementsByTagNameNS(kMathMLNamespace, "math")[0];
+ math.replaceChild(mtext, math.firstElementChild);
+ });
+</script>
+</head>
+<body>
+ <p>Test passes if you see the text "PASS".</p>
+ <math>
+ <mtext class="fail">FAIL</mtext>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-2-ref.html b/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-2-ref.html
new file mode 100644
index 0000000000..272e8b33ca
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-2-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Dynamic id and style (reference)</title>
+<style>
+ #pass { background: green; color: white; }
+</style>
+</head>
+<body>
+ <p>Test passes if you see the text "PASS".</p>
+ <math>
+ <mtext id="pass">PASS</mtext>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-2.html b/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-2.html
new file mode 100644
index 0000000000..8ad47c5cd9
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-2.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Dynamic id and style</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript"/>
+<link rel="match" href="dynamic-2-ref.html"/>
+<meta name="assert" content="Verify dynamic change of id and style attributes.">
+<style>
+ #fail, #fail2 { background: red; color: white; }
+ #pass { background: green; color: white; }
+</style>
+<script>
+ window.addEventListener("DOMContentLoaded", function() {
+ document.getElementById("fail2").setAttribute("id", "pass");
+ document.getElementById("fail").setAttribute("style", "display: none");
+ });
+</script>
+</head>
+<body>
+ <p>Test passes if you see the text "PASS".</p>
+ <math>
+ <mtext id="fail">FAIL</mtext>
+ <mtext id="fail2">PASS</mtext>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-childlist-001.html b/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-childlist-001.html
new file mode 100644
index 0000000000..ffd0ae239f
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-childlist-001.html
@@ -0,0 +1,630 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Dynamic childlist of MathML elements</title>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<link rel="help" href="https://w3c.github.io/mathml-core/#adjust-space-around-content-mpadded">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript">
+<link rel="help" href="https://w3c.github.io/mathml-core/#fractions-mfrac">
+<link rel="help" href="https://w3c.github.io/mathml-core/#prescripts-and-tensor-indices-mmultiscripts">
+<link rel="help" href="https://w3c.github.io/mathml-core/#radicals-msqrt-mroot">
+<link rel="help" href="https://w3c.github.io/mathml-core/#space-mspace">
+<link rel="help" href="https://w3c.github.io/mathml-core/#subscripts-and-superscripts-msub-msup-msubsup">
+<link rel="help" href="https://w3c.github.io/mathml-core/#underscripts-and-overscripts-munder-mover-munderover">
+<meta name="assert" content="Dynamically modify DOM tree of some MathML elements by adding or removing children.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/layout-comparison.js"></script>
+<script>
+ function forceNumberOfChildren(element, count) {
+ while (element.children.length > count)
+ element.removeChild(element.lastElementChild);
+ for (let i = element.children.length; i < count; i++) {
+ if (element.tagName === "mmultiscripts" && i === 5) {
+ element.appendChild(FragmentHelper.createElement("mprescripts"));
+ } else {
+ let mspace = FragmentHelper.createElement("mspace");
+ mspace.setAttribute("width", `10px`);
+ mspace.setAttribute("height", `${10*(i+1)}px`);
+ mspace.setAttribute("style", `background: black;`);
+ element.appendChild(mspace);
+ }
+ }
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", function() {
+ // force initial layout so we're sure what we're testing against
+ document.documentElement.getBoundingClientRect();
+
+ let reference = document.getElementById("reference");
+
+ Array.from(document.querySelectorAll("[data-title]")).forEach(element => {
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ let reference = document.getElementById(`${element.getAttribute("data-reference")}`);
+ forceNumberOfChildren(element, reference.children.length);
+ const epsilon = 1;
+ if (element.tagName == "mspace") {
+ compareSize(element, reference, epsilon);
+ childrenHaveEmptyBoundingClientRects(element);
+ childrenHaveEmptyBoundingClientRects(reference);
+ } else {
+ compareLayout(element, reference, epsilon);
+ }
+ }, `${element.getAttribute("data-title")}`);
+ });
+ done();
+ });
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <p>
+ <math>
+ <mfrac id="mfrac-reference-1">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ </mfrac>
+ <mfrac id="mfrac-reference-2">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </mfrac>
+ <mfrac id="mfrac-reference-3">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </mfrac>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mfrac data-reference="mfrac-reference-2" data-title="Adding missing children to mfrac">
+ </mfrac>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mfrac data-reference="mfrac-reference-1" data-title="Removing child from valid mfrac">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </mfrac>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mfrac data-reference="mfrac-reference-3" data-title="Adding child to valid mfrac">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </mfrac>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mfrac data-reference="mfrac-reference-2" data-title="Removing extra child from mfrac">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </mfrac>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math>
+ <munder id="munder-reference-1">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ </munder>
+ <munder id="munder-reference-2">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </munder>
+ <munder id="munder-reference-3">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </munder>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munder data-reference="munder-reference-2" data-title="Adding missing children to munder">
+ </munder>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munder data-reference="munder-reference-1" data-title="Removing child from valid munder">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </munder>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munder data-reference="munder-reference-3" data-title="Adding child to valid munder">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </munder>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munder data-reference="munder-reference-2" data-title="Removing extra child from munder">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </munder>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math>
+ <mover id="mover-reference-1">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ </mover>
+ <mover id="mover-reference-2">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </mover>
+ <mover id="mover-reference-3">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </mover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mover data-reference="mover-reference-2" data-title="Adding missing children to mover">
+ </mover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mover data-reference="mover-reference-1" data-title="Removing child from valid mover">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </mover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mover data-reference="mover-reference-3" data-title="Adding child to valid mover">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </mover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mover data-reference="mover-reference-2" data-title="Removing extra child from mover">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </mover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math>
+ <munderover id="munderover-reference-2">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </munderover>
+ <munderover id="munderover-reference-3">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </munderover>
+ <munderover id="munderover-reference-4">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ <mspace width="10px" height="40px" style="background: black;"/>
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover data-reference="munderover-reference-3" data-title="Adding missing children to munderover">
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover data-reference="munderover-reference-2" data-title="Removing child from valid munderover">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover data-reference="munderover-reference-4" data-title="Adding child to valid munderover">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </munderover>
+ </math>
+ </p>
+ <p>
+ <math>
+ <munderover data-reference="munderover-reference-3" data-title="Removing extra child from munderover">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ <mspace width="10px" height="40px" style="background: black;"/>
+ </munderover>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math>
+ <msub id="msub-reference-1">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ </msub>
+ <msub id="msub-reference-2">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </msub>
+ <msub id="msub-reference-3">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </msub>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msub data-reference="msub-reference-2" data-title="Adding missing children to msub">
+ </msub>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msub data-reference="msub-reference-1" data-title="Removing child from valid msub">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </msub>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msub data-reference="msub-reference-3" data-title="Adding child to valid msub">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </msub>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msub data-reference="msub-reference-2" data-title="Removing extra child from msub">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </msub>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math>
+ <msup id="msup-reference-1">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ </msup>
+ <msup id="msup-reference-2">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </msup>
+ <msup id="msup-reference-3">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </msup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msup data-reference="msup-reference-2" data-title="Adding missing children to msup">
+ </msup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msup data-reference="msup-reference-1" data-title="Removing child from valid msup">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </msup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msup data-reference="msup-reference-3" data-title="Adding child to valid msup">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </msup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msup data-reference="msup-reference-2" data-title="Removing extra child from msup">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </msup>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math>
+ <msubsup id="msubsup-reference-2">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </msubsup>
+ <msubsup id="msubsup-reference-3">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </msubsup>
+ <msubsup id="msubsup-reference-4">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ <mspace width="10px" height="40px" style="background: black;"/>
+ </msubsup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msubsup data-reference="msubsup-reference-3" data-title="Adding missing children to msubsup">
+ </msubsup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msubsup data-reference="msubsup-reference-2" data-title="Removing child from valid msubsup">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </msubsup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msubsup data-reference="msubsup-reference-4" data-title="Adding child to valid msubsup">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </msubsup>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msubsup data-reference="msubsup-reference-3" data-title="Removing extra child from msubsup">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ <mspace width="10px" height="40px" style="background: black;"/>
+ </msubsup>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math>
+ <mroot id="mroot-reference-1">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ </mroot>
+ <mroot id="mroot-reference-2">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </mroot>
+ <mroot id="mroot-reference-3">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </mroot>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mroot data-reference="mroot-reference-2" data-title="Adding missing children to mroot">
+ </mroot>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mroot data-reference="mroot-reference-1" data-title="Removing child from valid mroot">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </mroot>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mroot data-reference="mroot-reference-3" data-title="Adding child to valid mroot">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </mroot>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mroot data-reference="mroot-reference-2" data-title="Removing extra child from mroot">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </mroot>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math>
+ <msqrt id="msqrt-reference-0">
+ </msqrt>
+ <msqrt id="msqrt-reference-2">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </msqrt>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msqrt data-reference="msqrt-reference-0" data-title="Removing children from msqrt">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </msqrt>
+ </math>
+ </p>
+ <p>
+ <math>
+ <msqrt data-reference="msqrt-reference-2" data-title="Adding children to msqrt">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ </msqrt>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math>
+ <mpadded id="mpadded-reference-0">
+ </mpadded>
+ <mpadded id="mpadded-reference-2">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </mpadded>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mpadded data-reference="mpadded-reference-0" data-title="Removing children from mpadded">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </mpadded>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mpadded data-reference="mpadded-reference-2" data-title="Adding children to mpadded">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ </mpadded>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math>
+ <mspace id="mspace-reference-0" width="30px" height="70px" style="background: blue">
+ </mspace>
+ <mspace id="mspace-reference-2" width="30px" height="70px" style="background: green">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </mspace>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mspace data-reference="mspace-reference-0" data-title="Removing children from mspace" width="30px" height="70px" style="background: lightblue">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </mspace>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mspace data-reference="mspace-reference-2" data-title="Adding children to mspace" width="30px" height="70px" style="background: lightgreen">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ </mspace>
+ </math>
+ </p>
+ <hr/>
+ <p>
+ <math>
+ <mmultiscripts id="mmultiscripts-reference-0">
+ </mmultiscripts>
+ <mmultiscripts id="mmultiscripts-reference-1">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ </mmultiscripts>
+ <mmultiscripts id="mmultiscripts-reference-2">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ </mmultiscripts>
+ <mmultiscripts id="mmultiscripts-reference-3">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </mmultiscripts>
+ <mmultiscripts id="mmultiscripts-reference-6">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ <mspace width="10px" height="40px" style="background: black;"/>
+ <mspace width="10px" height="50px" style="background: black;"/>
+ <mprescripts/>
+ </mmultiscripts>
+ <mmultiscripts id="mmultiscripts-reference-8">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ <mspace width="10px" height="40px" style="background: black;"/>
+ <mspace width="10px" height="50px" style="background: black;"/>
+ <mprescripts/>
+ <mspace width="10px" height="70px" style="background: black;"/>
+ <mspace width="10px" height="80px" style="background: black;"/>
+ </mmultiscripts>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts data-reference="mmultiscripts-reference-0" data-title="multiscripts child count from 3 to 0">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </mmultiscripts>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts data-reference="mmultiscripts-reference-1" data-title="multiscripts child count from 3 to 1">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </mmultiscripts>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts data-reference="mmultiscripts-reference-2" data-title="multiscripts child count from 3 to 2">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </mmultiscripts>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts data-reference="mmultiscripts-reference-3" data-title="multiscripts child count from 0 to 3">
+ </mmultiscripts>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts data-reference="mmultiscripts-reference-6" data-title="multiscripts child count from 3 to 6">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </mmultiscripts>
+ </math>
+ </p>
+ <p>
+ <math>
+ <mmultiscripts data-reference="mmultiscripts-reference-8" data-title="multiscripts child count from 3 to 8">
+ <mspace width="10px" height="10px" style="background: black;"/>
+ <mspace width="10px" height="20px" style="background: black;"/>
+ <mspace width="10px" height="30px" style="background: black;"/>
+ </mmultiscripts>
+ </math>
+ </p>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-childlist-002.html b/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-childlist-002.html
new file mode 100644
index 0000000000..099401eacc
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/dynamic-childlist-002.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Dynamic childlist of MathML elements</title>
+<script src="/mathml/support/mathml-fragments.js"></script>
+<link rel="help" href="https://w3c.github.io/mathml-core/#adjust-space-around-content-mpadded">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript">
+<meta name="assert" content="Dynamically modify DOM tree of some MathML elements by adding or removing children.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script src="/mathml/support/layout-comparison.js"></script>
+<script>
+ function generateMathForTag(tag, childCount) {
+ let math = FragmentHelper.createElement("math");
+ let element = FragmentHelper.createElement(tag);
+ // Add the children with different sizes at odd positions and OOF
+ // mrow at even position.
+ for (let i = 0; i < childCount; i++) {
+ if (i % 2) {
+ let mspace = FragmentHelper.createElement("mspace");
+ mspace.setAttribute("width", `10px`);
+ mspace.setAttribute("height", `${10*(i+1)}px`);
+ mspace.setAttribute("style", `background: black;`);
+ element.appendChild(mspace);
+ } else {
+ let mrow = FragmentHelper.createElement("mrow");
+ mrow.setAttribute("style", "position: absolute");
+ element.appendChild(mrow);
+ }
+ }
+ if (FragmentHelper.isValidChildOfMrow(tag)) {
+ math.appendChild(element);
+ } else if (tag === "mtd") {
+ let mtr = FragmentHelper.createElement("mtr");
+ mtr.appendChild(element);
+ let mtable = FragmentHelper.createElement("mtable");
+ mtable.appendChild(mtr);
+ math.appendChild(mtable);
+ } else {
+ throw `Invalid argument: ${tag}`;
+ }
+ return math;
+ }
+
+ setup({ explicit_done: true });
+ window.addEventListener("load", function() {
+
+ for (tag in MathMLFragments) {
+ if (!FragmentHelper.isValidChildOfMrow(tag) || tag === "mtd")
+ continue;
+
+ document.body.insertAdjacentHTML("beforeend", `<div style='display: none; background: pink;'>${tag}: <div></div><div></div><div></div></div>`);
+
+ let container = document.body.lastElementChild;
+ let referenceDiv = container.children[0];
+ const maxChild = 10;
+ const epsilon = 1;
+
+ // Create the references for different number of children as well
+ // as the element that will get the children added / removed.
+ for (let i = 0; i <= maxChild; i++)
+ referenceDiv.append(generateMathForTag(tag, i));
+ let fullReferenceMath = referenceDiv.lastElementChild;
+ let fullReferenceTag = fullReferenceMath.firstElementChild;
+
+ let removeChildrenMath = generateMathForTag(tag, maxChild);
+ container.children[1].append(removeChildrenMath);
+ let removeChildrenTag = removeChildrenMath.firstElementChild;
+
+ let appendChildrenMath = generateMathForTag(tag, 0);
+ container.children[2].append(appendChildrenMath);
+ let appendChildrenTag = appendChildrenMath.firstElementChild;
+
+ // Make content visible after the DOM is ready so that the layout
+ // only happens now.
+ container.style.display = "block";
+
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_true(MathMLFeatureDetection[`has_${tag}`]());
+
+ for (let i = 0; i < maxChild; i++) {
+ // append and remove children.
+ appendChildrenTag.append(fullReferenceTag.children[i].cloneNode(true));
+ removeChildrenTag.removeChild(removeChildrenTag.lastElementChild);
+
+ // force layout so we're sure what we're testing against
+ container.getBoundingClientRect();
+
+ let appendCount = appendChildrenTag.children.length;
+ let removeCount = removeChildrenTag.children.length;
+ if (tag == "mspace") {
+ compareSize(appendChildrenTag, referenceDiv.children[appendCount].firstElementChild, epsilon);
+ childrenHaveEmptyBoundingClientRects(appendChildrenTag);
+ childrenHaveEmptyBoundingClientRects(referenceDiv.children[appendCount].firstElementChild);
+ childrenHaveEmptyBoundingClientRects(removeChildrenTag);
+ childrenHaveEmptyBoundingClientRects(referenceDiv.children[removeCount].firstElementChild);
+ } else {
+ compareLayout(appendChildrenTag, referenceDiv.children[appendCount].firstElementChild, epsilon, `appending ${appendCount}-th child`);
+ compareLayout(removeChildrenTag, referenceDiv.children[removeCount].firstElementChild, epsilon, `removing ${appendCount + 1}-th child`);
+ }
+ }
+
+ // Hide back the div after successful testing.
+ container.style.display = "none";
+
+ }, `Appending and removing children to ${tag}`);
+ }
+
+ done();
+ });
+</script>
+</head>
+<body>
+ <div id="log"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/href-click-1-ref.html b/testing/web-platform/tests/mathml/relations/html5-tree/href-click-1-ref.html
new file mode 100644
index 0000000000..86952567c7
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/href-click-1-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>href click (reference)</title>
+</head>
+<body>
+
+ <p>This test passes if you see a green square.</p>
+
+ <div style="width: 150px; height: 150px; background: green">
+ </div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/href-click-1.html b/testing/web-platform/tests/mathml/relations/html5-tree/href-click-1.html
new file mode 100644
index 0000000000..c3e605cb72
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/href-click-1.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8"/>
+<title>href click</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript">
+<link rel="match" href="href-click-1-ref.html"/>
+<meta name="assert" content="Verify that a click on a link moves to the target.">
+<script type="text/javascript">
+ function test()
+ {
+ var event = new MouseEvent('click', {bubbles: true, cancelable: true});
+ document.getElementById('link').dispatchEvent(event);
+ document.documentElement.className = "";
+ }
+</script>
+</head>
+<body onload="test()">
+
+ <p>This test passes if you see a green square.</p>
+
+ <div style="width: 150px; height: 150px; overflow: hidden">
+ <math>
+ <mrow id="link" href="#target">
+ <mspace id="space" width="150px" height="150px" style="background: red"/>
+ </mrow>
+ </math>
+ <div style="height: 500px;"></div>
+ <math id="target">
+ <mspace width="150px" height="150px" style="background: green"/>
+ </math>
+ </div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/href-click-2-ref.html b/testing/web-platform/tests/mathml/relations/html5-tree/href-click-2-ref.html
new file mode 100644
index 0000000000..86952567c7
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/href-click-2-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>href click (reference)</title>
+</head>
+<body>
+
+ <p>This test passes if you see a green square.</p>
+
+ <div style="width: 150px; height: 150px; background: green">
+ </div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/href-click-2.html b/testing/web-platform/tests/mathml/relations/html5-tree/href-click-2.html
new file mode 100644
index 0000000000..8ffec61cc7
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/href-click-2.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8"/>
+<title>href click</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript">
+<link rel="match" href="href-click-2-ref.html"/>
+<meta name="assert" content="Verify that a click on an element bubbles to an ancestor link.">
+<script type="text/javascript">
+ function test()
+ {
+ var event = new MouseEvent('click', {bubbles: true, cancelable: true});
+ document.getElementById('space').dispatchEvent(event);
+ document.documentElement.className = "";
+ }
+</script>
+</head>
+<body onload="test()">
+
+ <p>This test passes if you see a green square.</p>
+
+ <div style="width: 150px; height: 150px; overflow: hidden">
+ <math>
+ <mrow href="#target">
+ <mrow>
+ <mrow>
+ <mspace id="space" width="150px" height="150px" style="background: red"/>
+ </mrow>
+ </mrow>
+ </mrow>
+ </math>
+ <div style="height: 500px;"></div>
+ <math id="target">
+ <mspace width="150px" height="150px" style="background: green"/>
+ </math>
+ </div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/href-click-3.html b/testing/web-platform/tests/mathml/relations/html5-tree/href-click-3.html
new file mode 100644
index 0000000000..f6f1ada6d7
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/href-click-3.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>href click</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+</head>
+<body>
+ <p>To test manually, click the blue rectangle.</p>
+ <p>
+ <math>
+ <mspace width="50px" height="10px" style="background: gray"></mspace>
+ <mspace id="target" href="javascript:handler()" width="50px" height="10px" style="background: blue"></mspace>
+ <mspace width="50px" height="10px" style="background: gray"></mspace>
+ </math>
+ </p>
+ <a id="badTarget" href="javascript:badHandler()">DON'T CLICK ME</a>
+ <script>
+ var t = async_test("Click element with href");
+ function handler() { t.done(); }
+ function badHandler() {
+ t.step(() => { assert_unreached("Bad handler executed"); });
+ t.done();
+ }
+ test_driver.click(document.getElementById("target")).then(() => {
+ return test_driver.click(document.getElementById("badTarget"));
+ }).catch(() => {
+ t.step(() => { assert_unreached("Click failed"); });
+ t.done();
+ });
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/html-or-foreign-element-interfaces.tentative.html b/testing/web-platform/tests/mathml/relations/html5-tree/html-or-foreign-element-interfaces.tentative.html
new file mode 100644
index 0000000000..028428cd75
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/html-or-foreign-element-interfaces.tentative.html
@@ -0,0 +1,111 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>MathML 'HTMLOrForeignElement` Mixin Tests</title>
+ <link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript"/>
+ <style>
+ mi {
+ background-color: red;
+ }
+ :focus {
+ background-color: rgb(0, 255, 0);
+ }
+ </style>
+ <meta
+ name="assert"
+ content="MathMLElements incorporate a functional HTMLOrForeignElement interface"
+ />
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body tabindex="-1">
+ <span tabindex="-1"
+ >This tests the presence and functionality of features of
+ `HTMLOrForeignElement` (currently `HTMLOrSVGElement`)</span
+ >
+ <math tabindex="-1">
+ <mi>E</mi>
+ </math>
+ </body>
+ <script>
+ // spot check the functionality of several interfaces
+ let el = document.querySelector("mi");
+ let mathEl = document.querySelector("math");
+
+ // this really belongs in
+ // https://github.com/web-platform-tests/wpt/blob/master/html/dom/elements/global-attributes/dataset.html
+ // it is here tentatively
+ test(function() {
+ var mathml = document.createElementNS(
+ "http://www.w3.org/1998/Math/MathML",
+ "math"
+ );
+ assert_true(mathml.dataset instanceof DOMStringMap);
+ }, "MathML elements should have a .dataset");
+
+ // exercise some basic tests on .dataset
+ test(function() {
+ assert_equals(
+ Object.keys(el.dataset).toString(),
+ "",
+ "The .dataset property should be present"
+ );
+
+ el.setAttribute("data-one", "x");
+ el.setAttribute("data-two", "y");
+
+ assert_equals(
+ el.dataset.one,
+ "x",
+ '.one should be "x" after setting the data-one attribute'
+ );
+ assert_equals(
+ el.dataset.two,
+ "y",
+ '.one should be "y" after setting the data-two attribute'
+ );
+
+ el.dataset.one = "o";
+ assert_equals(
+ el.getAttribute("data-one"),
+ "o",
+ 'the data-one attribute should reflect a change to dataset.one and contain "o"'
+ );
+ }, "The dataset property should be present and be functional.");
+
+ test(function() {
+ assert_equals(mathEl.tabIndex, -1);
+ }, "MathML elements should have a tabIndex property");
+
+ promise_test(function() {
+ function focus() {
+ mathEl.focus();
+ return Promise.resolve();
+ }
+
+ return focus().then(() => {
+ assert_equals(
+ getComputedStyle(mathEl).backgroundColor,
+ "rgb(0, 255, 0)",
+ "MathML elements with tabindex=-1 should be programmatically focusable and apply :focus"
+ );
+ });
+ }, "MathML elements should work with focus predictably");
+
+ promise_test(function() {
+ function blur() {
+ mathEl.blur();
+ return Promise.resolve();
+ }
+
+ return blur().then(() => {
+ assert_equals(
+ getComputedStyle(mathEl).backgroundColor,
+ "rgba(0, 0, 0, 0)",
+ "MathML elements with tabindex=-1 be programmatically blur() able"
+ );
+ });
+ }, "MathML elements should work with blur predictably");
+ </script>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-1-ref.html b/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-1-ref.html
new file mode 100644
index 0000000000..4987754967
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-1-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>MathML inside foreignObject (reference)</title>
+</head>
+<body>
+ <p>Test passes if there is a green square and no red.</p>
+ <div>
+ <div style="position: absolute; width: 200px; height: 200px; background: green"></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-1.html b/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-1.html
new file mode 100644
index 0000000000..bc725e9d19
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-1.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>MathML inside foreignObject</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#html-and-svg">
+<link rel="match" href="integration-point-1-ref.html"/>
+<meta name="assert" content="Verify that MathML can be used inside a foreignObject element.">
+</head>
+<body>
+ <p>Test passes if there is a green square and no red.</p>
+ <div>
+ <div style="position: absolute; width: 200px; height: 200px; background: red"></div>
+ <div style="position: absolute;">
+ <svg width="200px" height="200px">
+ <rect width="200px" height="100px" fill="red"/>
+ <foreignObject width="200px" height="200px"
+ requiredExtensions="http://www.w3.org/1998/Math/MathML">
+ <div style="width: 200px; height: 200px; background: green"></div>
+ </foreignObject>
+ </svg>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-2-ref.html b/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-2-ref.html
new file mode 100644
index 0000000000..33c4b7e910
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-2-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>MathML as a phrasing content (reference)</title>
+</head>
+<body>
+ <p>Test passes if there is a green square and no red.</p>
+
+ <div>
+ <div style="position: absolute; background: green; width: 300px; height: 300px;"></div>
+ </div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-2.html b/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-2.html
new file mode 100644
index 0000000000..7e6c11a5ac
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-2.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>MathML as a phrasing content</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#html-and-svg">
+<link rel="match" href="integration-point-2-ref.html"/>
+<meta name="assert" content="Verify that MathML can be used at positions where phrasing content is accepted.">
+<style type="text/css">
+ span, math { font-family: monospace; font-size: 10px; }
+ div {
+ color: green;
+ }
+ span.redsquare {
+ display: inline-block;
+ width: 10px;
+ height: 10px;
+ background: red;
+ }
+ mspace {
+ background: green;
+ }
+</style>
+</head>
+<body>
+ <p>Test passes if there is a green square and no red.</p>
+
+ <div>
+
+ <div style="position: absolute; background: green; width: 300px; height: 300px;">
+ <p><span class="redsquare"></span></p>
+ <h1><span class="redsquare"></span></h1>
+ <h2><span class="redsquare"></span></h2>
+ <ul>
+ <li><span class="redsquare"></span></li>
+ </ul>
+ <ol>
+ <li><span class="redsquare"></span></li>
+ </ol>
+ <table><tr><td><span class="redsquare"></span></td></tr></table>
+ <a href="#id"><span class="redsquare"></span></a>
+ <em><span class="redsquare"></span></em>
+ <strong><span class="redsquare"></span></strong>
+ <small><span class="redsquare"></span></small>
+ <span><span class="redsquare"></span></span>
+ <u><span class="redsquare"></span></u>
+ <q><span class="redsquare"></span></q>
+ </div>
+ <div style="position: absolute; width: 400px;">
+ <p><math><mspace width="10px" height="10px"/></math></p>
+ <h1><math><mspace width="10px" height="10px"/></math></h1>
+ <h2><math><mspace width="10px" height="10px"/></math></h2>
+ <ul>
+ <li><math><mspace width="10px" height="10px"/></math></li>
+ </ul>
+ <ol>
+ <li><math><mspace width="10px" height="10px"/></math></li>
+ </ol>
+ <table><tr><td><math><mspace width="10px" height="10px"/></math></td></tr></table>
+ <a href="#id"><math><mspace width="10px" height="10px"/></math></a>
+ <em><math><mspace width="10px" height="10px"/></math></em>
+ <strong><math><mspace width="10px" height="10px"/></math></strong>
+ <small><math><mspace width="10px" height="10px"/></math></small>
+ <span><math><mspace width="10px" height="10px"/></math></span>
+ <u><math><mspace width="10px" height="10px"/></math></u>
+ <q><math><mspace width="10px" height="10px"/></math></q>
+ </div>
+
+ </div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-3-ref.html b/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-3-ref.html
new file mode 100644
index 0000000000..8362ed28e3
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-3-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>phrasing content inside mtext (reference)</title>
+</head>
+<body>
+ <p>Test passes if there is a green square and no red.</p>
+
+ <div>
+
+ <div style="position: absolute; background: green; width: 200px; height: 200px;"></div>
+
+ </div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-3.html b/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-3.html
new file mode 100644
index 0000000000..4c6f89ee93
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-3.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>phrasing content inside mtext</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#html-and-svg">
+<link rel="match" href="integration-point-3-ref.html"/>
+<meta name="assert" content="Verify that <mtext> can contain phrasing content">
+<style type="text/css">
+ div {
+ color: green;
+ }
+ span, math, mtext { font-family: monospace; font-size: 10px; }
+ span.redsquare, span.greensquare {
+ display: inline-block;
+ width: 10px;
+ height: 10px;
+ }
+ span.redsquare {
+ background: red;
+ }
+ span.greensquare {
+ background: green;
+ }
+ mspace {
+ background: green;
+ }
+</style>
+</head>
+<body>
+ <p>Test passes if there is a green square and no red.</p>
+
+ <div>
+
+ <div style="position: absolute; background: green; width: 200px; height: 200px;">
+ <span><span><span><span class="redsquare"></span></span></span></span>
+ <span><span><u><span class="redsquare"></span></u></span></span>
+ <span><span><a href="#id"><span class="redsquare"></span></a></span></span>
+ <span><span><del><span class="redsquare"></span></del></span></span>
+ <span><span><em><span class="redsquare"></span></em></span></span>
+ <span><span><strong><span class="redsquare"></span></strong></span></span>
+ <span><span><q><span class="redsquare"></span></q></span></span>
+ <span><span><small><span class="redsquare"></span></small></span></span>
+ <span><span><var><span class="redsquare"></span></var></span></span>
+ <span><span><samp><span class="redsquare"></span></samp></span></span>
+ </div>
+ <div style="position: absolute; width: 200px;">
+ <math><mtext><span><span class="greensquare"></span></span></mtext></math>
+ <math><mtext><u><span class="greensquare"></span></u></mtext></math>
+ <math><mtext><a href="#id"><span class="greensquare"></span></a></mtext></math>
+ <math><mtext><del><span class="greensquare"></span></del></mtext></math>
+ <math><mtext><em><span class="greensquare"></span></em></mtext></math>
+ <math><mtext><strong><span class="greensquare"></span></strong></mtext></math>
+ <math><mtext><q><span class="greensquare"></span></q></mtext></math>
+ <math><mtext><small><span class="greensquare"></span></small></mtext></math>
+ <math><mtext><var><span class="greensquare"></span></var></mtext></math>
+ <math><mtext><samp><span class="greensquare"></span></samp></mtext></math>
+ </div>
+
+ </div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-4.html b/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-4.html
new file mode 100644
index 0000000000..c3bc95d1ef
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-4.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>MathML inside foreignObject</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#html-and-svg">
+<meta name="assert" content="Verify that MathML can be used inside a foreignObject element.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("DOMContentLoaded", function() {
+ var scale = 2;
+ var epsilon = 1;
+ var mfrac = document.getElementById("mfrac");
+ var num = mfrac.firstElementChild.getBoundingClientRect();
+ var denom = mfrac.lastElementChild.getBoundingClientRect();
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ // The values of width and height are inverted (because of the
+ // rotation) and multiplied by the scale factor.
+ assert_approx_equals(num.height, 30 * scale, epsilon, "numerator width");
+ assert_approx_equals(num.width, 40 * scale, epsilon, "numerator height");
+ assert_approx_equals(denom.height, 50 * scale, epsilon, "numerator width");
+ assert_approx_equals(denom.width, 60 * scale, epsilon, "numerator height");
+ }, "mspace layout in SVG foreignObject");
+ test(function() {
+ // The horizontal/vertical metrics are inverted (because of the
+ // rotation) and multiplied by the scale factor.
+ assert_true(MathMLFeatureDetection.has_mfrac());
+ assert_greater_than_equal(num.right - denom.left,
+ (40 + 60) * scale,
+ "numerator is on the right of denominator");
+ assert_approx_equals((num.top + num.bottom) / 2,
+ (denom.top + denom.bottom) / 2,
+ epsilon, "numerator and denominator are vertically aligned");
+ }, "mfrac layout in SVG foreignObject");
+ done();
+ });
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <svg width="400px" height="400px">
+ <g transform="rotate(90, 200, 200) scale(2)">
+ <foreignObject width="400px" height="400px"
+ requiredExtensions="http://www.w3.org/1998/Math/MathML">
+ <math>
+ <mfrac id="mfrac">
+ <mspace width="30px" height="40px" style="background: cyan"></mspace>
+ <mspace width="50px" height="60px" style="background: yellow"></mspace>
+ </mfrac>
+ </math>
+ </foreignObject>
+ </g>
+ </svg>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-5.html b/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-5.html
new file mode 100644
index 0000000000..b63ab7a63c
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/integration-point-5.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>MathML sibling of SVG with foreignObject[overflow=visible]</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#html-and-svg">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=989920">
+<meta name="assert" content="Verify that an SVG containing a foreignObject with visible overflow does not affect layout of MathML siblings.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/mathml/support/feature-detection.js"></script>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("DOMContentLoaded", function() {
+ var scale = 2;
+ var epsilon = 1;
+ var mfrac = document.getElementById("mfrac");
+ var num = mfrac.firstElementChild.getBoundingClientRect();
+ var denom = mfrac.lastElementChild.getBoundingClientRect();
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mspace());
+ assert_approx_equals(num.width, 30, epsilon, "numerator width");
+ assert_approx_equals(num.height, 40, epsilon, "numerator height");
+ assert_approx_equals(denom.width, 50, epsilon, "denonimator width");
+ assert_approx_equals(denom.height, 60, epsilon, "denonimator height");
+ }, "mspace layout in sibling of SVG foreignObject[overflow=visible]");
+ test(function() {
+ assert_true(MathMLFeatureDetection.has_mfrac());
+ assert_greater_than_equal(denom.bottom - num.top,
+ (40 + 60),
+ "numerator above denominator");
+ assert_approx_equals((num.left + num.right) / 2,
+ (denom.left + denom.right) / 2,
+ epsilon, "numerator and denominator are horizontally aligned");
+ }, "mfrac layout in sibling of SVG with foreignObject[overflow=visible]");
+ done();
+ });
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <math>
+ <mfrac id="mfrac">
+ <mspace width="30px" height="40px" style="background: cyan"></mspace>
+ <mspace width="50px" height="60px" style="background: yellow"></mspace>
+ </mfrac>
+ </math>
+ <svg width="200px" height="200px" style="background: lightblue">
+ <foreignObject width="200px" height="200px"
+ overflow="visible">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ This is a foreignObject
+ </div>
+ </foreignObject>
+ </svg>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/math-global-event-handlers.tentative.html b/testing/web-platform/tests/mathml/relations/html5-tree/math-global-event-handlers.tentative.html
new file mode 100644
index 0000000000..b924eefa7d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/math-global-event-handlers.tentative.html
@@ -0,0 +1,155 @@
+<!DOCTYPE html>
+<title>MathMLElement GlobalEventHandlers</title>
+<link rel="author" title="Brian Kardell" href="mailto:bkardell@igalia.com" />
+<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript"/>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#event-handler-idl-attributes"/>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#event-handler-content-attributes"/>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/WebIDLParser.js"></script>
+
+<script>
+ "use strict";
+
+ // The prefixed animation events are special; their event types are
+ // camel-case.
+ const prefixedAnimationAttributeToEventType = new Map([
+ ["webkitanimationend", "webkitAnimationEnd"],
+ ["webkitanimationiteration", "webkitAnimationIteration"],
+ ["webkitanimationstart", "webkitAnimationStart"],
+ ["webkittransitionend", "webkitTransitionEnd"],
+ ]);
+
+ // basic pattern lifted from /html/webappapis/scripting/events/event-handler-all-global-events.html
+ promise_setup(async function() {
+ const res = await fetch("/interfaces/html.idl");
+ const htmlIDL = await res.text();
+ // Parsing the whole IDL file is slow, so use a small regexp to extract only
+ // the part that is relevant for this test.
+ const parsedHTMLIDL = WebIDL2.parse(htmlIDL.
+ match(/^interface mixin GlobalEventHandlers {[^{}]*};$/m)[0]);
+ const globalEventHandlers = parsedHTMLIDL.find(
+ idl => idl.name === "GlobalEventHandlers"
+ );
+
+ // onerror is too special
+ const names = globalEventHandlers.members
+ .map(member => member.name)
+ .filter(name => name !== "onerror");
+
+ for (const name of names) {
+ const withoutOn = name.substring(2);
+
+ promise_test(async () => {
+ const location = MathMLElement.prototype;
+ assert_true(
+ location.hasOwnProperty(name),
+ `${location.constructor.name} has an own property named "${name}"`
+ );
+
+ assert_false(
+ name in Element.prototype,
+ `Element.prototype must not contain a "${name}" property`
+ );
+ }, `${name}: must be on the appropriate locations for GlobalEventHandlers`);
+
+ promise_test(async () => {
+ const location = document.createElementNS(
+ "http://www.w3.org/1998/Math/MathML",
+ "math"
+ );
+
+ assert_equals(
+ location[name],
+ null,
+ `The default value of the property is null for a ${
+ location.constructor.name
+ } instance`
+ );
+ }, `${name}: the default value must be null`);
+
+ promise_test(async () => {
+ const div = document.createElement("div");
+ div.insertAdjacentHTML("beforeend", `<math ${name}="window.${name}Happened1 = true;"></math>`);
+ const compiledHandler = div.firstElementChild[name];
+ assert_equals(
+ typeof compiledHandler,
+ "function",
+ `The ${name} property must be a function`
+ );
+ compiledHandler();
+ assert_true(
+ window[`${name}Happened1`],
+ "Calling the handler must run the code"
+ );
+ }, `${name}: the content attribute must be compiled into a function as the corresponding property`);
+
+ promise_test(async () => {
+ const el = document.createElementNS(
+ "http://www.w3.org/1998/Math/MathML",
+ "math"
+ );
+ assert_equals(el[name], null, `The ${name} property must be null (no attribute)`);
+
+ el.setAttribute(name, `window.${name}Happened2 = true;`);
+ const compiledHandler = el[name];
+ assert_equals(
+ typeof compiledHandler,
+ "function",
+ `The ${name} property must be a function (set attribute)`
+ );
+ compiledHandler();
+ assert_true(
+ window[`${name}Happened2`],
+ "Calling the handler must run the code (set attribute)"
+ );
+
+ window[`${name}Happened2`] = false;
+ const clonedEl = el.cloneNode(true);
+ const clonedCompiledHandler = clonedEl[name];
+ assert_equals(
+ typeof clonedCompiledHandler,
+ "function",
+ `The ${name} property must be a function (clone node)`
+ );
+ clonedCompiledHandler();
+ assert_true(
+ window[`${name}Happened2`],
+ "Calling the handler must run the code (clone node)"
+ );
+
+ el.setAttribute(name, `window.${name}Happened3 = true;`);
+ const newCompiledHandler = el[name];
+ assert_equals(
+ typeof newCompiledHandler,
+ "function",
+ `The ${name} property must be a function (modify attribute)`
+ );
+ newCompiledHandler();
+ assert_true(
+ window[`${name}Happened3`],
+ "Calling the handler must run the code (modify attribute)"
+ );
+
+ el.removeAttribute(name);
+ assert_equals(el[name], null, `The ${name} property must be null (remove attribute)`);
+ }, `${name}: dynamic changes on the attribute`);
+
+ promise_test(async () => {
+ const element = document.createElementNS(
+ "http://www.w3.org/1998/Math/MathML",
+ "math"
+ );
+ let target = undefined;
+ element[name] = (e) => { target = e.currentTarget; }
+ let eventType = withoutOn;
+ if (prefixedAnimationAttributeToEventType.has(eventType)) {
+ eventType = prefixedAnimationAttributeToEventType.get(eventType);
+ }
+ element.dispatchEvent(new Event(eventType));
+ assert_equals(target, element, "The event must be fired at the <math> element");
+ }, `${name}: dispatching an Event at a <math> element must trigger element.${name}`);
+ }
+ });
+</script>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/required-extensions-2-ref.html b/testing/web-platform/tests/mathml/relations/html5-tree/required-extensions-2-ref.html
new file mode 100644
index 0000000000..dcc5b2b7d3
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/required-extensions-2-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>SVG requiredExtensions (reference)</title>
+</head>
+<body>
+ <p>Test passes if there is a green square and no red.</p>
+ <svg width="200px" height="200px">
+ <rect width="200px" height="200px" fill="green"/>
+ </svg>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/required-extensions-2.html b/testing/web-platform/tests/mathml/relations/html5-tree/required-extensions-2.html
new file mode 100644
index 0000000000..738f125507
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/required-extensions-2.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>SVG requiredExtensions</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#html-and-svg">
+<link rel="match" href="required-extensions-2-ref.html"/>
+<meta name="assert" content="Verify that a foreignObject with MathML used as a requiredExtensions value is selected for display in a SVG switch element.">
+</head>
+<body>
+ <p>Test passes if there is a green square and no red.</p>
+ <svg width="200px" height="200px">
+ <rect width="200px" height="100px" fill="red"/>
+ <switch>
+ <foreignObject width="200px" height="200px"
+ requiredExtensions="http://www.w3.org/1998/Math/MathML">
+ <div style="width: 200px; height: 200px; background: green"></div>
+ </foreignObject>
+ <rect y="100px" width="200px" height="100px" fill="red"/>
+ </switch>
+ </svg>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/tabindex-001.html b/testing/web-platform/tests/mathml/relations/html5-tree/tabindex-001.html
new file mode 100644
index 0000000000..3aaf0d955a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/tabindex-001.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>MathML tabIndex attribute</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="help" href="https://w3c.github.io/mathml-core/#the-top-level-math-element">
+<meta name="assert" content="Verify default values for the tabIndex attribute">
+
+<script src="/mathml/support/mathml-fragments.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <div id="log"></div>
+ <math>
+ </math>
+ <script>
+ const htmlLinkableElements =
+ new Set([
+ 'mi', 'mo', 'mn', 'ms', 'mtext', 'mrow'
+ ]);
+
+ Object.keys(MathMLFragments).forEach(elName => {
+ const mathEl = document.querySelector('math');
+
+ mathEl.innerHTML = `
+ <${elName} id="el" onfocus="alert('fail')"></${elName}>
+ <${elName} id="el-link" href="javascript:alert('fail')" onfocus="alert('fail')"></${elName}>
+ `;
+
+ const el = mathEl.querySelector('#el');
+ const elLink = mathEl.querySelector('#el-link');
+
+ const expectedDefault = (htmlLinkableElements.has(elName)) ? 0 : -1;
+
+ test(() => {
+ assert_equals(el.tabIndex, expectedDefault, "no attribute");
+ el.setAttribute("tabindex", "invalid");
+ assert_equals(el.getAttribute("tabindex"), "invalid");
+ assert_equals(el.tabIndex, expectedDefault, "invalid");
+ el.setAttribute("tabindex", "9999999999");
+ assert_equals(el.getAttribute("tabindex"), "9999999999");
+ assert_equals(el.tabIndex, expectedDefault, "too large integer");
+ }, `default and invalid values for ${elName} without href`);
+ test(() => {
+ assert_equals(elLink.tabIndex, expectedDefault, "no attribute");
+ elLink.setAttribute("tabindex", "invalid");
+ assert_equals(elLink.getAttribute("tabindex"), "invalid");
+ assert_equals(elLink.tabIndex, expectedDefault, "invalid");
+ elLink.setAttribute("tabindex", "9999999999");
+ assert_equals(elLink.getAttribute("tabindex"), "9999999999");
+ assert_equals(elLink.tabIndex, expectedDefault, "too large integer");
+ }, `default and invalid values for ${elName} with href`);
+ });
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/tabindex-002.html b/testing/web-platform/tests/mathml/relations/html5-tree/tabindex-002.html
new file mode 100644
index 0000000000..d2144e3d01
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/tabindex-002.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<meta charset="utf-8"/>
+<title>MathML tabindex attribute</title>
+<meta name="timeout" content="long">
+<link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+<meta assert="flag" content="interact">
+<meta assert="assert" content="Check the sequential focus navigation order for MathML">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<div id="log"></div>
+<a href="#link">tabindex(html,href)</a>
+<math>
+ <mtext id="text1">tabindex(omitted)</mtext>
+ <mtext id="text2" tabindex="">tabindex(empty)</mtext>
+ <mtext id="text3" tabindex="a">tabindex(a)</mtext>
+ <mtext id="text4" tabindex="-1">tabindex(-1)</mtext>
+ <mtext id="text5" tabindex="0">tabindex(0)</mtext>
+ <mtext id="text6" href="#link">tabindex(href)</mtext>
+ <mtext id="text7" tabindex="3">tabindex(3)</mtext>
+ <mtext id="text8" tabindex="2">tabindex(2)</mtext>
+ <mtext id="text9" tabindex="2">tabindex(2)</mtext>
+ <mtext id="text10" tabindex="2">tabindex(2)</mtext>
+ <mtext id="text11" tabindex="1">tabindex(1)</mtext>
+</math>
+<script>
+
+var i = 0,
+ expectation = ["text11", "text8", "text9", "text10", "text7", "text5"],
+ results = [],
+ t = async_test("Elements with different tabindex must be focused sequentially when pressing 'Tab' keys");
+
+setup(function () {
+ document.body.focus();
+});
+
+document.querySelector("a").addEventListener("focus", function (evt) {
+ // Links are tab-navigable on that platform.
+ expectation.push("text6");
+ // TAB = '\ue004'
+ test_driver.send_keys(document.body, "\ue004");
+}, true);
+
+document.querySelector("math").addEventListener("focus", function (evt) {
+ results.push(evt.target.id);
+ i++;
+ if (i >= expectation.length) {
+ t.step(function () {
+ assert_array_equals(results, expectation);
+ });
+ t.done();
+ } else {
+ t.step(function () {
+ // TAB = '\ue004'
+ test_driver.send_keys(document.body, "\ue004");
+ });
+ }
+}, true);
+
+document.addEventListener("keydown", function (evt) {
+ t.step(function () {
+ assert_equals(evt.keyCode, 9, "Please press 'Tab' key.");
+ });
+}, true);
+
+t.step(function () {
+ // TAB = '\ue004'
+ test_driver.send_keys(document.body, "\ue004");
+});
+</script>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-1-iframe-1.html b/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-1-iframe-1.html
new file mode 100644
index 0000000000..6b3ab07f1a
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-1-iframe-1.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Unique Identifier (iframe)</title>
+</head>
+<body>
+
+ <div style="width: 100px; height: 500px;">
+ <math><mtext style="background: red; color: white;">FAIL</mtext></math>
+ </div>
+ <div style="width: 100px; height: 500px;">
+ <math><mtext style="background: green; color: white;"
+ id="PASS">PASS</mtext></math>
+ </div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-1-iframe-2.html b/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-1-iframe-2.html
new file mode 100644
index 0000000000..ade0110a27
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-1-iframe-2.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Unique Identifier (iframe reference)</title>
+</head>
+<body>
+
+ <div style="width: 100px; height: 500px;">
+ <math><mtext style="background: green; color: white;"
+ id="PASS" class="pass">PASS</mtext></math>
+ </div>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-1-ref.html b/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-1-ref.html
new file mode 100644
index 0000000000..a219b2c870
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-1-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Unique identifier (reference)</title>
+</head>
+<body>
+
+ <p>Test passes if you see the text "PASS".</p>
+
+ <iframe width="100" height="100" frameborder="0" scrolling="no"
+ marginheight="0" marginwidth="0"
+ src="unique-identifier-1-iframe-2.html#PASS"></iframe>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-1.html b/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-1.html
new file mode 100644
index 0000000000..f5de2757c3
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-1.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Unique identifier</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+<link rel="match" href="unique-identifier-1-ref.html"/>
+<meta name="assert" content="Verify that the id on a MathML element can be used as a fragment identifier in order to force initial scrolling.">
+</head>
+<body>
+
+ <p>Test passes if you see the text "PASS".</p>
+
+ <iframe width="100" height="100" frameborder="0" scrolling="no"
+ marginheight="0" marginwidth="0"
+ src="unique-identifier-1-iframe-1.html#PASS"></iframe>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-2.html b/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-2.html
new file mode 100644
index 0000000000..d4e69df324
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-2.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Unique Identifier</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript">
+<meta name="assert" content="Verify whether the getElementById() works for MathML elements.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setup({ explicit_done: true });
+ window.addEventListener("DOMContentLoaded", function() {
+ var mtext = document.getElementById("MTEXT");
+ test(function() {
+ assert_equals(mtext, document.body.lastElementChild.lastElementChild);
+ }, "getElementById()");
+ done();
+ });
+</script>
+</head>
+<body>
+ <div id="log"></div>
+ <math>
+ <mtext id="MTEXT_"></mtext>
+ <mtext id="MTEX"></mtext>
+ <mtext id="MTEXT"></mtext>
+ </math>
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-3-ref.html b/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-3-ref.html
new file mode 100644
index 0000000000..ef056e0082
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-3-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Unique identifier 3 (reference)</title>
+</head>
+<body>
+
+ <p>Test passes if you see the text "PASS".</p>
+ <math>
+ <mtext style="background: green; color: white;">PASS</mtext>
+ </math>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-3.html b/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-3.html
new file mode 100644
index 0000000000..306ce41e25
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/html5-tree/unique-identifier-3.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8"/>
+<title>Unique Identifier</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#attributes-common-to-html-and-mathml-elements">
+<link rel="help" href="https://w3c.github.io/mathml-core/#css-styling">
+<link rel="match" href="unique-identifier-3-ref.html"/>
+<meta name="assert" content="Verify that the id attribute affects CSS selectors.">
+<style>
+ #fail { display: none; }
+ #pass { background: green; }
+</style>
+</head>
+<body>
+
+ <p>Test passes if you see the text "PASS".</p>
+ <math>
+ <mtext id="fail" style="background: red; color: white;">FAIL</mtext>
+ <mtext id="pass" style="color: white;">PASS</mtext>
+ </math>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/text-and-math/basic-mathematical-alphanumeric-symbols-with-default-font.html b/testing/web-platform/tests/mathml/relations/text-and-math/basic-mathematical-alphanumeric-symbols-with-default-font.html
new file mode 100644
index 0000000000..c1e8d409b9
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/text-and-math/basic-mathematical-alphanumeric-symbols-with-default-font.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8"/>
+ <title>Basic mathematical alphanumeric symbols with default font</title>
+ <meta name="assert" content="Verify whether the default font contains italic/bold/bold-italic characters from the Mathematical Alphanumeric Symbols block.">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <style>
+ span[data-name] {
+ font-size: 100px;
+ background: lightblue;
+ display: inline-block;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="log"></div>
+ <p><span id="frakturL" data-name="U+1D529 MATHEMATICAL FRAKTUR SMALL L">𝔩</span></p>
+ <p><span id="emSpace" data-name="U+2003 EM SPACE">&#x2003;</span></p>
+ <p><span data-test="Bold" data-name="U+1D416 MATHEMATICAL BOLD CAPITAL W">𝐖</span></p>
+ <p><span data-test="Italic" data-name="U+1D44A MATHEMATICAL ITALIC CAPITAL W">𝑊</span></p>
+ <p><span data-test="Bold-italic" data-name="U+1D47E MATHEMATICAL BOLD ITALIC CAPITAL">𝑾</span></p>
+ <script>
+ const frakturLWidth = document.getElementById("frakturL").getBoundingClientRect().width;
+ const emSpaceWidth = document.getElementById("emSpace").getBoundingClientRect().width;
+ Array.from(document.querySelectorAll('span[data-test]')).forEach(span => {
+ test(function() {
+ let spanWidth = span.getBoundingClientRect().width;
+ // This test expects the default font to provide a fraktur l than is much thiner than a bold/italic/bold-italic W.
+ // If the font lacks bold/italic/bold-italic W then a fortiori it is likely that its lacks fraktur l, so browsers
+ // will display "Tofu characters" for all of them (e.g. gray boxes or boxes containing the Unicode code points)
+ // with very similar widths, so the test is likely to fail.
+ assert_greater_than(spanWidth, frakturLWidth + emSpaceWidth / 4, `Width of '${span.dataset.name}' is much larger than '${frakturL.dataset.name}'`);
+ }, `${span.dataset.test} mathematical alphanumeric symbol with the default font`);
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/mathml/relations/text-and-math/use-typo-metrics-1-ref.html b/testing/web-platform/tests/mathml/relations/text-and-math/use-typo-metrics-1-ref.html
new file mode 100644
index 0000000000..3f7f764045
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/text-and-math/use-typo-metrics-1-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset="utf-8"/>
+<title>Open Font Format: USE_TYPO_METRICS (reference)</title>
+<style>
+ #green {
+ position: absolute;
+ background: green;
+ left: 10px;
+ width: 230px;
+ height: 230px;
+ }
+</style>
+<body>
+ <p>Test passes if there is a green square and no red.</p>
+
+ <div>
+ <div id="green"></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/mathml/relations/text-and-math/use-typo-metrics-1.html b/testing/web-platform/tests/mathml/relations/text-and-math/use-typo-metrics-1.html
new file mode 100644
index 0000000000..1af8fdfde1
--- /dev/null
+++ b/testing/web-platform/tests/mathml/relations/text-and-math/use-typo-metrics-1.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<meta charset="utf-8"/>
+<title>Open Font Format: USE_TYPO_METRICS</title>
+<link rel="help" href="https://w3c.github.io/mathml-core/#text-layout"/>
+<link rel="match" href="use-typo-metrics-1-ref.html"/>
+<meta name="assert" content="Verify that the USE_TYPO_METRICS flag from the OS/2 table is taken into account to calculate line height.">
+<style>
+ @font-face {
+ font-family: TestFont;
+ src: url("/fonts/math/lineheight5000-typolineheight2300.woff");
+ }
+ .green {
+ position: absolute;
+ background: green;
+ width: 115px;
+ }
+ .red {
+ position: absolute;
+ background: red;
+ width: 115px;
+ }
+ .forceHeight {
+ height: 230px;
+ }
+ .leftSide {
+ left: 10px;
+ }
+ .rightSide {
+ left: 125px;
+ }
+ span {
+ /* em=1000, lineHeight=5000, typoLineHeight=2300 and font-size=100px
+ implies typoLineHeightPx = 230px < 500px = lineHeightPx */
+ font-family: TestFont;
+ font-size: 100px;
+ color: transparent;
+ }
+</style>
+<body>
+ <p>Test passes if there is a green square and no red.</p>
+
+ <div>
+ <!-- Left side verifies that typoLineHeightPx <= 230px -->
+ <div class="leftSide red"><span>O</span></div>
+ <div class="leftSide green forceHeight"></div>
+
+ <!-- Right side verifies that typoLineHeightPx => 230px -->
+ <div class="rightSide red forceHeight"></div>
+ <div class="rightSide green"><span>O</span></div>
+ </div>
+</body>
diff --git a/testing/web-platform/tests/mathml/support/attribute-values.js b/testing/web-platform/tests/mathml/support/attribute-values.js
new file mode 100644
index 0000000000..8408124f49
--- /dev/null
+++ b/testing/web-platform/tests/mathml/support/attribute-values.js
@@ -0,0 +1,31 @@
+AttributeValueTransforms = {
+ lowercase: function(value) { return value.toLowerCase(); },
+ uppercase: function(value) { return value.toUpperCase(); },
+ alternate_case: function(value) {
+ var transformedValue = "";
+ for (var i = 0; i < value.length; i++) {
+ transformedValue += i % 2 ?
+ value.charAt(i).toLowerCase() :
+ value.charAt(i).toUpperCase();
+ }
+ return transformedValue;
+ },
+ // TODO: Should we perform this transform too?
+ // https://github.com/mathml-refresh/mathml/issues/122
+ // add_leading_and_trimming_whitespace: function(value) {
+ // var space = "\0020\0009\000A\000D";
+ // return `${space}${space}${value}${space}${space}`;
+ // },
+};
+
+function TransformAttributeValues(transform, attributeNames) {
+ if (typeof attributeNames === "string")
+ attributeNames = [attributeNames];
+ attributeNames.forEach(name => {
+ Array.from(document.querySelectorAll(`[${name}]`)).forEach(element => {
+ var value = element.getAttribute(name);
+ var transformedValue = AttributeValueTransforms[transform](value);
+ element.setAttribute(name, transformedValue);
+ });
+ });
+}
diff --git a/testing/web-platform/tests/mathml/support/box-comparison.js b/testing/web-platform/tests/mathml/support/box-comparison.js
new file mode 100644
index 0000000000..b30ad279df
--- /dev/null
+++ b/testing/web-platform/tests/mathml/support/box-comparison.js
@@ -0,0 +1,107 @@
+function spaceBetween(childBox, parentBox) {
+ return {
+ left: childBox.left - parentBox.left,
+ right: parentBox.right - childBox.right,
+ top: childBox.top - parentBox.top,
+ bottom: parentBox.bottom - childBox.bottom
+ };
+}
+
+function measureSpaceAround(id) {
+ var mrow = document.getElementById(id);
+ var mrowBox = mrow.getBoundingClientRect();
+ var parentBox = mrow.parentNode.getBoundingClientRect();
+ var childBox = mrow.firstElementChild.getBoundingClientRect();
+ return spaceBetween(childBox, parentBox);
+}
+
+function compareSpaceWithAndWithoutStyle(tag, style, parentStyle, direction) {
+ if (!FragmentHelper.isValidChildOfMrow(tag) ||
+ FragmentHelper.isEmpty(tag))
+ throw `Invalid argument: ${tag}`;
+
+ if (!direction)
+ direction = "ltr";
+ document.body.insertAdjacentHTML("beforeend", `<div style="position: absolute;">\
+<div style="display: inline-block"><math><mrow dir="${direction}">${MathMLFragments[tag]}</mrow></math></div>\
+<div style="display: inline-block"><math><mrow dir="${direction}">${MathMLFragments[tag]}</mrow></math></div>\
+</div>`);
+ var div = document.body.lastElementChild;
+
+ var styleDiv = div.firstElementChild;
+ var styleMath = styleDiv.firstElementChild;
+ var styleParent = styleMath.firstElementChild;
+ if (parentStyle)
+ styleParent.setAttribute("style", parentStyle);
+ var styleElement = FragmentHelper.element(styleMath);
+ styleElement.setAttribute("style", style);
+ var styleChild = FragmentHelper.forceNonEmptyElement(styleElement);
+ var styleMathBox = styleMath.getBoundingClientRect();
+ var styleElementBox = styleElement.getBoundingClientRect();
+ var styleChildBox = styleChild.getBoundingClientRect();
+ var styleSpace = spaceBetween(styleChildBox, styleMathBox);
+
+ var noStyleDiv = div.lastElementChild;
+ var noStyleMath = noStyleDiv.firstElementChild;
+ var noStyleElement = FragmentHelper.element(noStyleMath);
+ var noStyleChild = FragmentHelper.forceNonEmptyElement(noStyleElement);
+ var noStyleMathBox = noStyleMath.getBoundingClientRect();
+ var noStyleElementBox = noStyleElement.getBoundingClientRect();
+ var noStyleChildBox = noStyleChild.getBoundingClientRect();
+ var noStyleSpace = spaceBetween(noStyleChildBox, noStyleMathBox);
+
+ var preferredWidthDelta =
+ styleDiv.getBoundingClientRect().width -
+ noStyleDiv.getBoundingClientRect().width;
+
+ div.style = "display: none;"; // Hide the div after measurement.
+
+ return {
+ preferred_width_delta: preferredWidthDelta,
+ left_delta: styleSpace.left - noStyleSpace.left,
+ right_delta: styleSpace.right - noStyleSpace.right,
+ top_delta: styleSpace.top - noStyleSpace.top,
+ bottom_delta: styleSpace.bottom - noStyleSpace.bottom,
+ element_width_delta: styleElementBox.width - noStyleElementBox.width,
+ element_height_delta: styleElementBox.height - noStyleElementBox.height
+ };
+}
+
+function compareSizeWithAndWithoutStyle(tag, style) {
+ if (!FragmentHelper.isValidChildOfMrow(tag))
+ throw `Invalid argument: ${tag}`;
+
+ // FIXME <mrow> only needed as workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1658135
+ document.body.insertAdjacentHTML("beforeend", `<div style="position: absolute;">\
+<div style="display: inline-block"><math><mrow>${MathMLFragments[tag]}</mrow></math></div>\
+<div style="display: inline-block"><math><mrow>${MathMLFragments[tag]}</mrow></math></div>\
+</div>`);
+ var div = document.body.lastElementChild;
+
+ var styleDiv = div.firstElementChild;
+ var styleParent = styleDiv.firstElementChild.firstElementChild;
+ var styleElement = FragmentHelper.element(styleParent);
+ styleElement.setAttribute("style", style);
+ var styleParentBox = styleParent.getBoundingClientRect();
+ var styleElementBox = styleElement.getBoundingClientRect();
+
+ var noStyleDiv = div.lastElementChild;
+ var noStyleParent = noStyleDiv.firstElementChild.firstElementChild;
+ var noStyleElement = FragmentHelper.element(noStyleParent);
+ var noStyleParentBox = noStyleParent.getBoundingClientRect();
+ var noStyleElementBox = noStyleElement.getBoundingClientRect();
+
+ var preferredWidthDelta =
+ styleDiv.getBoundingClientRect().width -
+ noStyleDiv.getBoundingClientRect().width;
+
+ div.style = "display: none;"; // Hide the div after measurement.
+
+ return {
+ preferred_width_delta: preferredWidthDelta,
+ width_delta: styleParentBox.width - noStyleParentBox.width,
+ height_delta: styleParentBox.height - noStyleParentBox.height,
+ element_width_delta: styleElementBox.width - noStyleElementBox.width,
+ element_height_delta: styleElementBox.height - noStyleElementBox.height
+ };
+};
diff --git a/testing/web-platform/tests/mathml/support/box-navigation.js b/testing/web-platform/tests/mathml/support/box-navigation.js
new file mode 100644
index 0000000000..f4897cfe99
--- /dev/null
+++ b/testing/web-platform/tests/mathml/support/box-navigation.js
@@ -0,0 +1,29 @@
+function IsInFlow(element) {
+ var style = window.getComputedStyle(element);
+ return style.getPropertyValue("display") !== "none" &&
+ style.getPropertyValue("position") !== "absolute" &&
+ style.getPropertyValue("position") !== "fixed";
+}
+
+function firstInFlowChild(element) {
+ var child = element.firstElementChild;
+ if (!child || IsInFlow(child))
+ return child;
+ return nextInFlowSibling(child);
+}
+
+function nextInFlowSibling(element) {
+ var child = element;
+ do {
+ child = child.nextElementSibling;
+ } while (child && !IsInFlow(child));
+ return child;
+}
+
+function previousInFlowSibling(element) {
+ var child = element;
+ do {
+ child = child.previousElementSibling;
+ } while (child && !IsInFlow(child));
+ return child;
+}
diff --git a/testing/web-platform/tests/mathml/support/feature-detection-operators.js b/testing/web-platform/tests/mathml/support/feature-detection-operators.js
new file mode 100644
index 0000000000..25dae40258
--- /dev/null
+++ b/testing/web-platform/tests/mathml/support/feature-detection-operators.js
@@ -0,0 +1,86 @@
+// This is a helper for MathML feature detection.
+// It is indented to be used to prevent false negative test results.
+// This adds operator-specific feature detections.
+
+Object.assign(MathMLFeatureDetection, {
+ "has_operator_lspace/rspace": async function() {
+ return this.has_operator_spacing();
+ },
+
+ "has_operator_movablelimits": async function() {
+ return this.has_movablelimits();
+ },
+
+ "has_operator_largeop": async function() {
+ if (!this.hasOwnProperty("_has_operator_largeop")) {
+ document.body.insertAdjacentHTML("beforeend", "\
+<math style='font: 10px HasOperatorLargeopTestFont;'\
+ displaystyle='true'>\
+ <mo largeop='false' stretchy='false' symmetric='false'>&#x2AFF;</mo>\
+ <mo largeop='true' stretchy='false' symmetric='false'>&#x2AFF;</mo>\
+</math>");
+ let font_face = new FontFace('HasOperatorLargeopTestFont',
+ 'url(/fonts/math/largeop-displayoperatorminheight5000.woff)');
+ document.fonts.add(font_face);
+ await font_face.load();
+ var math = document.body.lastElementChild;
+ var mo = math.getElementsByTagName("mo");
+ this._has_operator_largeop =
+ (mo[1].getBoundingClientRect().height >
+ mo[0].getBoundingClientRect().height);
+ document.body.removeChild(math);
+ document.fonts.delete(font_face);
+ }
+ return this._has_operator_largeop;
+ },
+
+ "has_operator_stretchy": async function() {
+ if (!this.hasOwnProperty("_has_operator_stretchy")) {
+ document.body.insertAdjacentHTML("beforeend", "\
+<math style='font: 10px HasOperatorStretchyTestFont;'>\
+ <mrow>\
+ <mo stretchy='false' largeop='false' symmetric='false'>&#x2AFF;</mo>\
+ <mo stretchy='true' largeop='false' symmetric='false'>&#x2AFF;</mo>\
+ <mspace style='background: black;' width='1px' height='2em'></mspace>\
+ </mrow>\
+</math>");
+ let font_face = new FontFace('HasOperatorLargeopTestFont',
+ 'url(/fonts/math/largeop-displayoperatorminheight5000.woff)');
+ document.fonts.add(font_face);
+ await font_face.load();
+ var math = document.body.lastElementChild;
+ var mo = math.getElementsByTagName("mo");
+ this._has_operator_stretchy =
+ (mo[1].getBoundingClientRect().height >
+ mo[0].getBoundingClientRect().height);
+ document.body.removeChild(math);
+ document.fonts.delete(font_face);
+ }
+ return this._has_operator_stretchy;
+ },
+
+ "has_operator_symmetric": async function() {
+ if (!this.hasOwnProperty("_has_operator_symmetric")) {
+ document.body.insertAdjacentHTML("beforeend", "\
+<math style='font: 10px HasOperatorSymmetricTestFont;'>\
+ <mrow>\
+ <mo stretchy='true' largeop='false' symmetric='false'>&#x2AFF;</mo>\
+ <mo stretchy='true' largeop='false' symmetric='true'>&#x2AFF;</mo>\
+ <mspace style='background: black;' width='1px' height='2em'></mspace>\
+ </mrow>\
+</math>");
+ let font_face = new FontFace('HasOperatorLargeopTestFont',
+ 'url(/fonts/math/largeop-displayoperatorminheight5000.woff)');
+ document.fonts.add(font_face);
+ await font_face.load();
+ var math = document.body.lastElementChild;
+ var mo = math.getElementsByTagName("mo");
+ this._has_operator_symmetric =
+ (mo[1].getBoundingClientRect().height >
+ mo[0].getBoundingClientRect().height);
+ document.body.removeChild(math);
+ document.fonts.delete(font_face);
+ }
+ return this._has_operator_symmetric;
+ },
+});
diff --git a/testing/web-platform/tests/mathml/support/feature-detection.js b/testing/web-platform/tests/mathml/support/feature-detection.js
new file mode 100644
index 0000000000..8b3f227d44
--- /dev/null
+++ b/testing/web-platform/tests/mathml/support/feature-detection.js
@@ -0,0 +1,325 @@
+// This is a helper for MathML feature detection.
+// It is indented to be used to prevent false negative test results.
+
+var MathMLFeatureDetection = {
+
+ "has_annotation": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_annotation-xml": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_maction": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_math": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_menclose": function() {
+ // Just check whether <mrow> is supported because discussion on this is
+ // still open ( https://github.com/mathml-refresh/mathml/issues/105 )
+ // and it would have to behave at least like an mrow, even if it becomes
+ // an unknown element at the end.
+ return this.has_mrow();
+ },
+
+ "has_merror": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_mfrac": function() {
+ if (!this.hasOwnProperty("_has_mfrac")) {
+ // Use tall enough fraction to avoid side effect of min num/denum shifts.
+ document.body.insertAdjacentHTML("beforeend", "<math>\
+<mfrac>\
+ <mspace height='50px' depth='50px'></mspace>\
+ <mspace height='50px' depth='50px'></mspace>\
+</mfrac>\
+<mfrac>\
+ <mspace height='60px' depth='60px'></mspace>\
+ <mspace height='60px' depth='60px'></mspace>\
+</mfrac>\
+</math>");
+ var math = document.body.lastElementChild;
+ var mfrac = math.getElementsByTagName("mfrac");
+ // height/depth will add 40px per MathML, 20px if mfrac does not stack its children and none if mspace is not supported.
+ this._has_mfrac =
+ mfrac[1].getBoundingClientRect().height -
+ mfrac[0].getBoundingClientRect().height > 30;
+ document.body.removeChild(math);
+ }
+ return this._has_mfrac;
+ },
+
+ "has_mi": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_mmultiscripts": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_mn": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_mo": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_mover": function() {
+ // FIXME: Improve feature detection.
+ return this.has_munderover();
+ },
+
+ "has_mpadded": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_mphantom": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_mprescripts": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_mroot": function() {
+ // FIXME: Improve feature detection.
+ return this.has_msqrt();
+ },
+
+ "has_mrow": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_ms": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_mspace": function() {
+ // https://w3c.github.io/mathml-core/#space-mspace
+ if (!this.hasOwnProperty("_has_mspace")) {
+ document.body.insertAdjacentHTML("beforeend", "<math>\
+<mspace></mspace>\
+<mspace width='20px'></mspace>\
+</math>");
+ var math = document.body.lastElementChild;
+ // The width attribute will add 20px per MathML and none if not supported.
+ this._has_mspace =
+ math.lastChild.getBoundingClientRect().width -
+ math.firstChild.getBoundingClientRect().width > 10;
+ document.body.removeChild(math);
+ }
+ return this._has_mspace;
+ },
+
+ "has_msqrt": function() {
+ if (!this.hasOwnProperty("_has_msqrt")) {
+ document.body.insertAdjacentHTML("beforeend", "<math>\
+<mrow style='font-size: 20px !important'>\
+ <mtext>A</mtext>\
+</mrow>\
+<msqrt style='font-size: 20px !important'>\
+ <mtext>A</mtext>\
+</msqrt>\
+</math>");
+ var math = document.body.lastElementChild;
+ // The radical symbol will make msqrt wider than mrow, if the former is supported.
+ this._has_msqrt =
+ math.lastElementChild.getBoundingClientRect().width -
+ math.firstElementChild.getBoundingClientRect().width > 5;
+ document.body.removeChild(math);
+ }
+ return this._has_msqrt;
+ },
+
+ "has_mstyle": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_msub": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_msubsup": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_msup": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_mtable": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_mtd": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_mtext": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_mtr": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_munder": function() {
+ // FIXME: Improve feature detection.
+ return this.has_munderover();
+ },
+
+ "has_munderover": function() {
+ if (!this.hasOwnProperty("_has_munderover")) {
+ document.body.insertAdjacentHTML("beforeend", "<math>\
+<munderover>\
+ <mspace width='20px'></mspace>\
+ <mspace width='20px'></mspace>\
+ <mspace width='20px'></mspace>\
+</munderover>\
+<munderover>\
+ <mspace width='40px'></mspace>\
+ <mspace width='40px'></mspace>\
+ <mspace width='40px'></mspace>\
+</munderover>\
+</math>");
+ var math = document.body.lastElementChild;
+ var munderover = math.getElementsByTagName("munderover");
+ // width_delta will be 20px per MathML, 3 * 20 = 60px if mundeover does not stack its children and 0px if mspace is not supported.
+ var width_delta =
+ munderover[1].getBoundingClientRect().width -
+ munderover[0].getBoundingClientRect().width;
+ this._has_munderover = width_delta > 10 && width_delta < 30;
+ document.body.removeChild(math);
+ }
+ return this._has_munderover;
+ },
+
+ "has_none": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_semantics": function() {
+ // FIXME: Improve feature detection.
+ return this.has_mspace();
+ },
+
+ "has_dir": function() {
+ if (!this.hasOwnProperty("_has_dir")) {
+ document.body.insertAdjacentHTML("beforeend", "<math style='direction: ltr !important;'>\
+<mtext dir='rtl'></mtext>\
+</math>");
+ var math = document.body.lastElementChild;
+ this._has_dir =
+ window.getComputedStyle(math.firstElementChild).
+ getPropertyValue('direction') === 'rtl';
+ document.body.removeChild(math);
+ }
+ return this._has_dir;
+ },
+
+ "has_mathsize": function() {
+ if (!this.hasOwnProperty("_has_mathsize")) {
+ document.body.insertAdjacentHTML("beforeend", "<math style='font-size: 64px !important;'>\
+<mtext mathsize='32px'></mtext>\
+</math>");
+ var math = document.body.lastElementChild;
+ this._has_mathsize =
+ window.getComputedStyle(math.firstElementChild).
+ getPropertyValue('font-size') === '32px';
+ document.body.removeChild(math);
+ }
+ return this._has_mathsize;
+ },
+
+ "has_movablelimits": function() {
+ if (!this.hasOwnProperty("_has_movablelimits")) {
+ document.body.insertAdjacentHTML("beforeend", "<math>\
+<munder>\
+ <mo style='font-size: 30px !important' movablelimits='false'>A</mo>\
+ <mspace width='100px'></mspace>\
+</munder>\
+<munder>\
+ <mo style='font-size: 30px !important' movablelimits='true'>A</mo>\
+ <mspace width='100px'></mspace>\
+</munder>\
+</math>");
+ var math = document.body.lastElementChild;
+ var munder = math.getElementsByTagName("munder");
+ // If movablelimits is supported, the <mspace> will be placed next
+ // to <mo> rather than below it, so width_delta is about the width
+ // of the <mo>.
+ var width_delta =
+ munder[1].getBoundingClientRect().width -
+ munder[0].getBoundingClientRect().width;
+ this._has_movablelimits = this.has_munder() && width_delta > 20;
+ document.body.removeChild(math);
+ }
+ return this._has_movablelimits;
+ },
+
+ "has_operator_spacing": function() {
+ // https://w3c.github.io/mathml-core/#dfn-lspace
+ // https://w3c.github.io/mathml-core/#layout-of-mrow
+ if (!this.hasOwnProperty("_has_operator_spacing")) {
+ document.body.insertAdjacentHTML("beforeend", "<math>\
+<mrow>\
+ <mn>1</mn><mo lspace='0px' rspace='0px'>+</mo><mn>2</mn>\
+</mrow>\
+<mrow>\
+ <mn>1</mn><mo lspace='20px' rspace='20px'>+</mo><mn>2</mn>\
+</mrow>\
+</math>");
+ var math = document.body.lastElementChild;
+ var mrow = math.getElementsByTagName("mrow");
+ // lspace/rspace will add 40px per MathML and none if not supported.
+ this._has_operator_spacing =
+ mrow[1].getBoundingClientRect().width -
+ mrow[0].getBoundingClientRect().width > 30;
+ document.body.removeChild(math);
+ }
+ return this._has_operator_spacing;
+ },
+
+ ensure_for_match_reftest: function(has_function) {
+ if (!document.querySelector("link[rel='match']"))
+ throw "This function must only be used for match reftest";
+ // Add a little red square at the top left corner if the feature is not supported in order to make match reftest fail.
+ if (!this[has_function]()) {
+ document.body.insertAdjacentHTML("beforeend", "\
+<div style='width: 10px !important; height: 10px !important;\
+ position: absolute !important;\
+ left: 0 !important; top: 0 !important;\
+ background: red !important; z-index: 1000 !important;'></div>");
+ }
+ }
+};
diff --git a/testing/web-platform/tests/mathml/support/fonts.js b/testing/web-platform/tests/mathml/support/fonts.js
new file mode 100644
index 0000000000..f05d7278ad
--- /dev/null
+++ b/testing/web-platform/tests/mathml/support/fonts.js
@@ -0,0 +1,9 @@
+function loadAllFonts() {
+ // Use this to wait for all fonts in a testcase to load rather than just using
+ // `document.fonts.ready.then(...)` in the load event, since there are compat
+ // issues between browsers as to whether content initiated font loads are
+ // guaranteed to have been started by this point.
+
+ // FIXME: Use Promise.all() to cause an obvious failure when a font fails to load.
+ return Promise.allSettled([...document.fonts].map(f => f.load()));
+}
diff --git a/testing/web-platform/tests/mathml/support/layout-comparison.js b/testing/web-platform/tests/mathml/support/layout-comparison.js
new file mode 100644
index 0000000000..452b45006e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/support/layout-comparison.js
@@ -0,0 +1,112 @@
+function getWritingMode(element, reference) {
+ var style = window.getComputedStyle(reference);
+ if (style.getPropertyValue("writing-mode") !== "horizontal-tb" ||
+ style.getPropertyValue("direction") !== "ltr")
+ throw "Reference should have writing mode horizontal-tb and ltr";
+
+ style = window.getComputedStyle(element);
+ var param = {
+ rtl: style.getPropertyValue("direction") === "rtl",
+ mode: style.getPropertyValue("writing-mode")
+ };
+
+ return param;
+}
+
+function compareSize(element, reference, epsilon) {
+ var param = getWritingMode(element, reference);
+ var elementBox = element.getBoundingClientRect();
+ var referenceBox = reference.getBoundingClientRect();
+
+ switch(param.mode) {
+ case "horizontal-tb":
+ assert_approx_equals(elementBox.width, referenceBox.width, epsilon,
+ "inline size");
+ assert_approx_equals(elementBox.height, referenceBox.height, epsilon,
+ "block size");
+ break;
+ case "vertical-lr":
+ case "vertical-rl":
+ assert_approx_equals(elementBox.width, referenceBox.height, epsilon,
+ "inline size");
+ assert_approx_equals(elementBox.height, referenceBox.width, epsilon,
+ "block size");
+ break;
+ default:
+ throw "compareSize: Unrecognized writing-mode value";
+ }
+}
+
+function childrenHaveEmptyBoundingClientRects(element) {
+ Array.from(element.children).forEach(child => {
+ var childBox = child.getBoundingClientRect();
+ assert_true(childBox.left == 0 && childBox.right == 0 && childBox.top == 0 && childBox.bottom == 0);
+ })
+}
+
+function participateToParentLayout(child) {
+ var style = window.getComputedStyle(child);
+ return style.getPropertyValue("display") !== "none" &&
+ style.getPropertyValue("position") !== "absolute" &&
+ style.getPropertyValue("position") !== "fixed";
+}
+
+function childrenParticipatingToLayout(element) {
+ var children = [];
+ Array.from(element.children).forEach(child => {
+ if (participateToParentLayout(child))
+ children.push(child);
+ })
+ return children;
+}
+
+function compareLayout(element, reference, epsilon) {
+ // Compare sizes of elements and children.
+ var param = getWritingMode(element, reference);
+
+ compareSize(element, reference, epsilon);
+ var elementBox = element.getBoundingClientRect();
+ var referenceBox = reference.getBoundingClientRect();
+
+ var elementChildren = childrenParticipatingToLayout(element);
+ var referenceChildren = childrenParticipatingToLayout(reference);
+ if (elementChildren.length != referenceChildren.length)
+ throw "Reference should have the same number of children participating to layout."
+
+ for (var i = 0; i < elementChildren.length; i++) {
+ compareSize(elementChildren[i], referenceChildren[i], epsilon);
+
+ var childBox = elementChildren[i].getBoundingClientRect();
+ var referenceChildBox = referenceChildren[i].getBoundingClientRect();
+
+ switch(param.mode) {
+ case "horizontal-tb":
+ assert_approx_equals(param.rtl ?
+ elementBox.right - childBox.right :
+ childBox.left - elementBox.left,
+ referenceChildBox.left - referenceBox.left,
+ epsilon,
+ `inline position (child ${i})`);
+ assert_approx_equals(childBox.top - elementBox.top,
+ referenceChildBox.top - referenceBox.top,
+ epsilon,
+ `block position (child ${i})`);
+ break;
+ case "vertical-lr":
+ case "vertical-rl":
+ assert_approx_equals(param.rtl ?
+ elementBox.bottom - childBox.bottom :
+ childBox.top - elementBox.top,
+ referenceChildBox.left - referenceBox.left,
+ epsilon,
+ `inline position (child ${i})`);
+ assert_approx_equals(elementBox.right - childBox.right,
+ referenceChildBox.top - referenceBox.top,
+ epsilon,
+ `block position (child ${i})`);
+ break;
+ default:
+ throw "compareLayout: Unrecognized writing-mode value";
+ }
+ }
+}
diff --git a/testing/web-platform/tests/mathml/support/mathml-fragments.js b/testing/web-platform/tests/mathml/support/mathml-fragments.js
new file mode 100644
index 0000000000..7e2113e95b
--- /dev/null
+++ b/testing/web-platform/tests/mathml/support/mathml-fragments.js
@@ -0,0 +1,189 @@
+var MathMLFragments = {
+ "annotation": "\
+<semantics>\
+ <mrow></mrow>\
+ <annotation class='element text-container'></annotation>\
+</semantics>",
+ "annotation-xml": "\
+<semantics>\
+ <mrow></mrow>\
+ <annotation-xml class='element text-container foreign-container'></annotation-xml>\
+</semantics>",
+ "maction": "\
+<maction class='element' actiontype='statusline'>\
+ <mrow class='mathml-container'></mrow>\
+ <mtext class='text-container'></mtext>\
+</maction>",
+ "menclose": "<menclose class='element mathml-container'></menclose>",
+ "merror": "<merror class='element mathml-container'></merror>",
+ "mfrac": "\
+<mfrac class='element'>\
+ <mrow class='mathml-container'></mrow>\
+ <mrow class='mathml-container'></mrow>\
+</mfrac>",
+ "mi": "<mi class='element text-container foreign-container'></mi>",
+ "mmultiscripts": "\
+<mmultiscripts class='element'>\
+ <mrow class='mathml-container'></mrow>\
+ <mrow class='mathml-container'></mrow>\
+ <mrow class='mathml-container'></mrow>\
+</mmultiscripts>",
+ "mn": "<mn class='element text-container foreign-container'></mn>",
+ "mo": "<mo class='element text-container foreign-container'></mo>",
+ "mover": "\
+<mover class='element'>\
+ <mrow class='mathml-container'></mrow>\
+ <mrow class='mathml-container'></mrow>\
+</mover>",
+ "mpadded": "<mpadded class='element mathml-container'></mpadded>",
+ "mphantom": "<mphantom class='element mathml-container'></mphantom>",
+ "mprescripts": "\
+<mmultiscripts>\
+ <mrow class='mathml-container'></mrow>\
+ <mprescripts class='element'/>\
+ <mrow class='mathml-container'></mrow>\
+ <mrow class='mathml-container'></mrow>\
+</mmultiscripts>",
+ "mroot": "\
+<mroot class='element'>\
+ <mrow class='mathml-container'></mrow>\
+ <mrow class='mathml-container'></mrow>\
+</mroot>",
+ "mrow": "<mrow class='element mathml-container'></mrow>",
+ "ms": "<ms class='element text-container foreign-container'></ms>",
+ "mspace": "<mspace class='element'></mspace>",
+ "msqrt": "<msqrt class='element mathml-container'></msqrt>",
+ "mstyle": "<mstyle class='element mathml-container'></mstyle>",
+ "msub": "\
+<msub class='element'>\
+ <mrow class='mathml-container'></mrow>\
+ <mrow class='mathml-container'></mrow>\
+</msub>",
+ "msubsup": "\
+<msubsup class='element'>\
+ <mrow class='mathml-container'></mrow>\
+ <mrow class='mathml-container'></mrow>\
+ <mrow class='mathml-container'></mrow>\
+</msubsup>",
+ "msup": "\
+<msup class='element'>\
+ <mrow class='mathml-container'></mrow>\
+ <mrow class='mathml-container'></mrow>\
+</msup>",
+ "mtable": "\
+<mtable class='element'>\
+ <mtr>\
+ <mtd class='mathml-container'>\
+ </mtd>\
+ </mtr>\
+</mtable>",
+ "mtd": "\
+<mtable>\
+ <mtr>\
+ <mtd class='element mathml-container'>\
+ </mtd>\
+ </mtr>\
+</mtable>",
+ "mtext": "<mtext class='element text-container foreign-container'></mtext>",
+ "mtr": "\
+<mtable>\
+ <mtr class='element'>\
+ <mtd class='mathml-container'>\
+ </mtd>\
+ </mtr>\
+</mtable>",
+ "munder": "\
+<munder class='element'>\
+ <mrow class='mathml-container'></mrow>\
+ <mrow class='mathml-container'></mrow>\
+</munder>",
+ "munderover": "\
+<munderover class='element'>\
+ <mrow class='mathml-container'></mrow>\
+ <mrow class='mathml-container'></mrow>\
+ <mrow class='mathml-container'></mrow>\
+</munderover>",
+ "none": "\
+<mmultiscripts>\
+ <mrow class='mathml-container'></mrow>\
+ <none class='element'/>\
+ <mrow class='mathml-container'></mrow>\
+</mmultiscripts>",
+ "semantics": "\
+<semantics class='element'>\
+ <mrow class='mathml-container'></mrow>\
+ <annotation class='text-container'></annotation>\
+</semantics>"
+};
+
+var FragmentHelper = {
+ mathml_namespace: "http://www.w3.org/1998/Math/MathML",
+
+ createElement: function(tag) {
+ return document.createElementNS(this.mathml_namespace, tag);
+ },
+
+ isValidChildOfMrow: function(tag) {
+ return !(tag == "annotation" ||
+ tag == "annotation-xml" ||
+ tag == "mprescripts" ||
+ tag == "none" ||
+ tag == "mtr" ||
+ tag == "mtd");
+ },
+
+ isTokenElement: function(tag) {
+ return (tag == "mi" ||
+ tag == "mtext" ||
+ tag == "mo" ||
+ tag == "mn" ||
+ tag == "ms")
+ },
+
+ isEmpty: function(tag) {
+ return tag === "mspace" || tag == "mprescripts" || tag == "none";
+ },
+
+ element: function(fragment) {
+ return fragment.getElementsByClassName('element')[0];
+ },
+
+ appendChild: function(fragment, allowInvalid) {
+ var element = this.element(fragment) || fragment;
+ if (element.classList.contains("foreign-container")) {
+ var el = document.createElement("span");
+ el.textContent = "a";
+ return element.appendChild(el);
+ }
+ if (element.classList.contains("mathml-container") || allowInvalid) {
+ var el = this.createElement("mi");
+ el.textContent = "a";
+ return element.appendChild(el);
+ }
+ throw "Cannot append child to the element";
+ },
+
+ forceNonEmptyElement: function(fragment) {
+ var element = this.element(fragment) || fragment;
+ if (element.firstElementChild)
+ return element.firstElementChild;
+ return this.appendChild(fragment);
+ },
+
+ forceNonEmptyDescendants: function(fragment) {
+ var element = this.element(fragment) || fragment;
+ if (element.classList.contains("mathml-container") ||
+ element.classList.contains("foreign-container")) {
+ for (var i = 0; i < 10; i++)
+ this.appendChild(element);
+ return;
+ }
+ var child = element.firstElementChild;
+ if (child) {
+ for (; child; child = child.nextElementSibling) {
+ this.forceNonEmptyDescendants(child);
+ }
+ return;
+ }
+ },
+}
diff --git a/testing/web-platform/tests/mathml/support/operator-dictionary.js b/testing/web-platform/tests/mathml/support/operator-dictionary.js
new file mode 100644
index 0000000000..ee1de102fe
--- /dev/null
+++ b/testing/web-platform/tests/mathml/support/operator-dictionary.js
@@ -0,0 +1,42 @@
+async function fetchOperatorDictionary() {
+ let response = await fetch(`/mathml/support/operator-dictionary.json`);
+ return response.json();
+}
+
+function splitKey(key) {
+ var value = key.split(" ")
+ return {
+ characters: value[0],
+ form: value[1]
+ };
+}
+
+function spaceIndexToLength(index) {
+ // See https://w3c.github.io/mathml-core/#operator-dictionary
+ return ["0",
+ "0.05555555555555555em",
+ "0.1111111111111111em",
+ "0.16666666666666666em",
+ "0.2222222222222222em",
+ "0.2777777777777778em",
+ "0.3333333333333333em",
+ "0.3888888888888889em"
+ ][index];
+}
+
+function defaultPropertyValue(entry, name) {
+ switch (name) {
+ case "lspace":
+ case "rspace":
+ return spaceIndexToLength(entry.hasOwnProperty(name) ? entry[name] : 5);
+ break
+ case "largeop":
+ case "movablelimits":
+ case "stretchy":
+ case "symmetric":
+ case "accent":
+ return entry[name];
+ default:
+ throw `Unknown property ${name}`;
+ }
+}
diff --git a/testing/web-platform/tests/mathml/support/operator-dictionary.json b/testing/web-platform/tests/mathml/support/operator-dictionary.json
new file mode 100644
index 0000000000..0008f5114e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/support/operator-dictionary.json
@@ -0,0 +1 @@
+{"comment": "This file was automatically generated by operator-dictionary.py. Do not edit.", "dictionary": {"! postfix": {"lspace": 0, "rspace": 0}, "! prefix": {"lspace": 0, "rspace": 0}, "!! postfix": {"lspace": 0, "rspace": 0}, "!= infix": {"lspace": 5, "rspace": 5}, "\" postfix": {"lspace": 0, "rspace": 0}, "% infix": {"lspace": 3, "rspace": 3}, "% postfix": {"lspace": 0, "rspace": 0}, "& postfix": {"lspace": 0, "rspace": 0}, "&& infix": {"lspace": 4, "rspace": 4}, "' postfix": {"lspace": 0, "rspace": 0}, "( prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, ") postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "* infix": {"lspace": 3, "rspace": 3}, "** infix": {"lspace": 3, "rspace": 3}, "*= infix": {"lspace": 5, "rspace": 5}, "+ infix": {"lspace": 4, "rspace": 4}, "+ prefix": {"lspace": 0, "rspace": 0}, "++ postfix": {"lspace": 0, "rspace": 0}, "+= infix": {"lspace": 5, "rspace": 5}, ", infix": {"lspace": 0, "rspace": 3}, "- infix": {"lspace": 4, "rspace": 4}, "- prefix": {"lspace": 0, "rspace": 0}, "-- postfix": {"lspace": 0, "rspace": 0}, "-= infix": {"lspace": 5, "rspace": 5}, "-> infix": {"lspace": 5, "rspace": 5}, ". infix": {"lspace": 3, "rspace": 3}, "/ infix": {"lspace": 4, "rspace": 4}, "// infix": {"lspace": 5, "rspace": 5}, "/= infix": {"lspace": 5, "rspace": 5}, ": infix": {"lspace": 0, "rspace": 3}, ":= infix": {"lspace": 5, "rspace": 5}, "; infix": {"lspace": 0, "rspace": 3}, "< infix": {"lspace": 5, "rspace": 5}, "<= infix": {"lspace": 5, "rspace": 5}, "<> infix": {"lspace": 3, "rspace": 3}, "= infix": {"horizontal": true, "lspace": 5, "rspace": 5}, "== infix": {"lspace": 5, "rspace": 5}, "> infix": {"lspace": 5, "rspace": 5}, ">= infix": {"lspace": 5, "rspace": 5}, "? infix": {"lspace": 3, "rspace": 3}, "@ infix": {"lspace": 3, "rspace": 3}, "[ prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\\ infix": {"lspace": 0, "rspace": 0}, "] postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "^ infix": {"horizontal": true, "lspace": 3, "rspace": 3}, "^ postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "_ infix": {"horizontal": true, "lspace": 0, "rspace": 0}, "_ postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "` postfix": {"lspace": 0, "rspace": 0}, "{ prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "| infix": {"lspace": 5, "rspace": 5}, "| postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "| prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "|| infix": {"lspace": 5, "rspace": 5}, "|| postfix": {"lspace": 0, "rspace": 0}, "|| prefix": {"lspace": 0, "rspace": 0}, "} postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "~ postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u00a0 infix": {}, "\u00a0 prefix": {}, "\u00a0 suffix": {}, "\u00a8 postfix": {"lspace": 0, "rspace": 0}, "\u00ac prefix": {"lspace": 0, "rspace": 0}, "\u00af postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u00b0 postfix": {"lspace": 0, "rspace": 0}, "\u00b1 infix": {"lspace": 4, "rspace": 4}, "\u00b1 prefix": {"lspace": 0, "rspace": 0}, "\u00b2 postfix": {"lspace": 0, "rspace": 0}, "\u00b3 postfix": {"lspace": 0, "rspace": 0}, "\u00b4 postfix": {"lspace": 0, "rspace": 0}, "\u00b7 infix": {"lspace": 3, "rspace": 3}, "\u00b8 postfix": {"lspace": 0, "rspace": 0}, "\u00b9 postfix": {"lspace": 0, "rspace": 0}, "\u00d7 infix": {"lspace": 3, "rspace": 3}, "\u00f7 infix": {"lspace": 4, "rspace": 4}, "\u02c6 postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u02c7 postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u02c9 postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u02ca postfix": {"lspace": 0, "rspace": 0}, "\u02cb postfix": {"lspace": 0, "rspace": 0}, "\u02cd postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u02d8 postfix": {"lspace": 0, "rspace": 0}, "\u02d9 postfix": {"lspace": 0, "rspace": 0}, "\u02da postfix": {"lspace": 0, "rspace": 0}, "\u02dc postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u02dd postfix": {"lspace": 0, "rspace": 0}, "\u02f7 postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u0302 postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u0311 postfix": {"lspace": 0, "rspace": 0}, "\u2016 postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2016 prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2018 prefix": {"lspace": 0, "rspace": 0}, "\u2019 postfix": {"lspace": 0, "rspace": 0}, "\u201a postfix": {"lspace": 0, "rspace": 0}, "\u201b postfix": {"lspace": 0, "rspace": 0}, "\u201c prefix": {"lspace": 0, "rspace": 0}, "\u201d postfix": {"lspace": 0, "rspace": 0}, "\u201e postfix": {"lspace": 0, "rspace": 0}, "\u201f postfix": {"lspace": 0, "rspace": 0}, "\u2022 infix": {"lspace": 3, "rspace": 3}, "\u2032 postfix": {"lspace": 0, "rspace": 0}, "\u2033 postfix": {"lspace": 0, "rspace": 0}, "\u2034 postfix": {"lspace": 0, "rspace": 0}, "\u2035 postfix": {"lspace": 0, "rspace": 0}, "\u2036 postfix": {"lspace": 0, "rspace": 0}, "\u2037 postfix": {"lspace": 0, "rspace": 0}, "\u203e postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u2043 infix": {"lspace": 3, "rspace": 3}, "\u2044 infix": {"lspace": 4, "rspace": 4}, "\u2057 postfix": {"lspace": 0, "rspace": 0}, "\u2061 infix": {"lspace": 0, "rspace": 0}, "\u2062 infix": {"lspace": 0, "rspace": 0}, "\u2063 infix": {"lspace": 0, "rspace": 0}, "\u2064 infix": {"lspace": 0, "rspace": 0}, "\u20db postfix": {"lspace": 0, "rspace": 0}, "\u20dc postfix": {"lspace": 0, "rspace": 0}, "\u2145 prefix": {"lspace": 3, "rspace": 0}, "\u2146 prefix": {"lspace": 3, "rspace": 0}, "\u2190 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2191 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2192 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2193 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2194 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2195 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2196 infix": {"lspace": 5, "rspace": 5}, "\u2197 infix": {"lspace": 5, "rspace": 5}, "\u2198 infix": {"horizontal": true, "lspace": 5, "rspace": 5}, "\u2199 infix": {"horizontal": true, "lspace": 5, "rspace": 5}, "\u219a infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u219b infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u219c infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u219d infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u219e infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u219f infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21a0 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21a1 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21a2 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21a3 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21a4 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21a5 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21a6 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21a7 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21a8 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21a9 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21aa infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21ab infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21ac infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21ad infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21ae infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21af infix": {"lspace": 5, "rspace": 5}, "\u21b0 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21b1 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21b2 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21b3 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21b4 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21b5 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21b6 infix": {"lspace": 5, "rspace": 5}, "\u21b7 infix": {"lspace": 5, "rspace": 5}, "\u21b8 infix": {"lspace": 5, "rspace": 5}, "\u21b9 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21ba infix": {"lspace": 5, "rspace": 5}, "\u21bb infix": {"lspace": 5, "rspace": 5}, "\u21bc infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21bd infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21be infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21bf infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21c0 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21c1 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21c2 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21c3 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21c4 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21c5 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21c6 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21c7 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21c8 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21c9 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21ca infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21cb infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21cc infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21cd infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21ce infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21cf infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21d0 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21d1 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21d2 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21d3 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21d4 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21d5 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21d6 infix": {"lspace": 5, "rspace": 5}, "\u21d7 infix": {"lspace": 5, "rspace": 5}, "\u21d8 infix": {"lspace": 5, "rspace": 5}, "\u21d9 infix": {"lspace": 5, "rspace": 5}, "\u21da infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21db infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21dc infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21dd infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21de infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21df infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21e0 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21e1 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21e2 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21e3 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21e4 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21e5 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21e6 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21e7 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21e8 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21e9 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21ea infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21eb infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21ec infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21ed infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21ee infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21ef infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21f0 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21f1 infix": {"lspace": 5, "rspace": 5}, "\u21f2 infix": {"lspace": 5, "rspace": 5}, "\u21f3 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21f4 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21f5 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u21f6 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21f7 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21f8 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21f9 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21fa infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21fb infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21fc infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21fd infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21fe infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u21ff infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2200 prefix": {"lspace": 0, "rspace": 0}, "\u2201 prefix": {"lspace": 0, "rspace": 0}, "\u2202 prefix": {"lspace": 3, "rspace": 0}, "\u2203 prefix": {"lspace": 0, "rspace": 0}, "\u2204 prefix": {"lspace": 0, "rspace": 0}, "\u2206 infix": {"lspace": 0, "rspace": 0}, "\u2207 prefix": {"lspace": 0, "rspace": 0}, "\u2208 infix": {"lspace": 5, "rspace": 5}, "\u2209 infix": {"lspace": 5, "rspace": 5}, "\u220a infix": {"lspace": 5, "rspace": 5}, "\u220b infix": {"lspace": 5, "rspace": 5}, "\u220c infix": {"lspace": 5, "rspace": 5}, "\u220d infix": {"lspace": 5, "rspace": 5}, "\u220f prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2210 prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2211 prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2212 infix": {"lspace": 4, "rspace": 4}, "\u2212 prefix": {"lspace": 0, "rspace": 0}, "\u2213 infix": {"lspace": 4, "rspace": 4}, "\u2213 prefix": {"lspace": 0, "rspace": 0}, "\u2214 infix": {"lspace": 4, "rspace": 4}, "\u2215 infix": {"lspace": 4, "rspace": 4}, "\u2216 infix": {"lspace": 4, "rspace": 4}, "\u2217 infix": {"lspace": 3, "rspace": 3}, "\u2218 infix": {"lspace": 3, "rspace": 3}, "\u2219 infix": {"lspace": 3, "rspace": 3}, "\u221a prefix": {"lspace": 3, "rspace": 0}, "\u221b prefix": {"lspace": 3, "rspace": 0}, "\u221c prefix": {"lspace": 3, "rspace": 0}, "\u221d infix": {"lspace": 5, "rspace": 5}, "\u221f prefix": {"lspace": 0, "rspace": 0}, "\u2220 prefix": {"lspace": 0, "rspace": 0}, "\u2221 prefix": {"lspace": 0, "rspace": 0}, "\u2222 prefix": {"lspace": 0, "rspace": 0}, "\u2223 infix": {"lspace": 5, "rspace": 5}, "\u2224 infix": {"lspace": 5, "rspace": 5}, "\u2225 infix": {"lspace": 5, "rspace": 5}, "\u2226 infix": {"lspace": 5, "rspace": 5}, "\u2227 infix": {"lspace": 4, "rspace": 4}, "\u2228 infix": {"lspace": 4, "rspace": 4}, "\u2229 infix": {"lspace": 4, "rspace": 4}, "\u222a infix": {"lspace": 4, "rspace": 4}, "\u222b prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u222c prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u222d prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u222e prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u222f prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2230 prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2231 prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2232 prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2233 prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2234 prefix": {"lspace": 0, "rspace": 0}, "\u2235 prefix": {"lspace": 0, "rspace": 0}, "\u2236 infix": {"lspace": 4, "rspace": 4}, "\u2237 infix": {"lspace": 5, "rspace": 5}, "\u2238 infix": {"lspace": 4, "rspace": 4}, "\u2239 infix": {"lspace": 5, "rspace": 5}, "\u223a infix": {"lspace": 5, "rspace": 5}, "\u223b infix": {"lspace": 5, "rspace": 5}, "\u223c infix": {"lspace": 5, "rspace": 5}, "\u223c prefix": {"lspace": 0, "rspace": 0}, "\u223d infix": {"lspace": 5, "rspace": 5}, "\u223e infix": {"lspace": 5, "rspace": 5}, "\u2240 infix": {"lspace": 3, "rspace": 3}, "\u2241 infix": {"lspace": 5, "rspace": 5}, "\u2242 infix": {"lspace": 5, "rspace": 5}, "\u2243 infix": {"lspace": 5, "rspace": 5}, "\u2244 infix": {"lspace": 5, "rspace": 5}, "\u2245 infix": {"lspace": 5, "rspace": 5}, "\u2246 infix": {"lspace": 5, "rspace": 5}, "\u2247 infix": {"lspace": 5, "rspace": 5}, "\u2248 infix": {"lspace": 5, "rspace": 5}, "\u2249 infix": {"lspace": 5, "rspace": 5}, "\u224a infix": {"lspace": 5, "rspace": 5}, "\u224b infix": {"lspace": 5, "rspace": 5}, "\u224c infix": {"lspace": 5, "rspace": 5}, "\u224d infix": {"lspace": 5, "rspace": 5}, "\u224e infix": {"lspace": 5, "rspace": 5}, "\u224f infix": {"lspace": 5, "rspace": 5}, "\u2250 infix": {"lspace": 5, "rspace": 5}, "\u2251 infix": {"lspace": 5, "rspace": 5}, "\u2252 infix": {"lspace": 5, "rspace": 5}, "\u2253 infix": {"lspace": 5, "rspace": 5}, "\u2254 infix": {"lspace": 5, "rspace": 5}, "\u2255 infix": {"lspace": 5, "rspace": 5}, "\u2256 infix": {"lspace": 5, "rspace": 5}, "\u2257 infix": {"lspace": 5, "rspace": 5}, "\u2258 infix": {"lspace": 5, "rspace": 5}, "\u2259 infix": {"lspace": 5, "rspace": 5}, "\u225a infix": {"lspace": 5, "rspace": 5}, "\u225b infix": {"lspace": 5, "rspace": 5}, "\u225c infix": {"lspace": 5, "rspace": 5}, "\u225d infix": {"lspace": 5, "rspace": 5}, "\u225e infix": {"lspace": 5, "rspace": 5}, "\u225f infix": {"lspace": 5, "rspace": 5}, "\u2260 infix": {"lspace": 5, "rspace": 5}, "\u2261 infix": {"lspace": 5, "rspace": 5}, "\u2262 infix": {"lspace": 5, "rspace": 5}, "\u2263 infix": {"lspace": 5, "rspace": 5}, "\u2264 infix": {"lspace": 5, "rspace": 5}, "\u2265 infix": {"lspace": 5, "rspace": 5}, "\u2266 infix": {"lspace": 5, "rspace": 5}, "\u2267 infix": {"lspace": 5, "rspace": 5}, "\u2268 infix": {"lspace": 5, "rspace": 5}, "\u2269 infix": {"lspace": 5, "rspace": 5}, "\u226a infix": {"lspace": 5, "rspace": 5}, "\u226b infix": {"lspace": 5, "rspace": 5}, "\u226c infix": {"lspace": 5, "rspace": 5}, "\u226d infix": {"lspace": 5, "rspace": 5}, "\u226e infix": {"lspace": 5, "rspace": 5}, "\u226f infix": {"lspace": 5, "rspace": 5}, "\u2270 infix": {"lspace": 5, "rspace": 5}, "\u2271 infix": {"lspace": 5, "rspace": 5}, "\u2272 infix": {"lspace": 5, "rspace": 5}, "\u2273 infix": {"lspace": 5, "rspace": 5}, "\u2274 infix": {"lspace": 5, "rspace": 5}, "\u2275 infix": {"lspace": 5, "rspace": 5}, "\u2276 infix": {"lspace": 5, "rspace": 5}, "\u2277 infix": {"lspace": 5, "rspace": 5}, "\u2278 infix": {"lspace": 5, "rspace": 5}, "\u2279 infix": {"lspace": 5, "rspace": 5}, "\u227a infix": {"lspace": 5, "rspace": 5}, "\u227b infix": {"lspace": 5, "rspace": 5}, "\u227c infix": {"lspace": 5, "rspace": 5}, "\u227d infix": {"lspace": 5, "rspace": 5}, "\u227e infix": {"lspace": 5, "rspace": 5}, "\u227f infix": {"lspace": 5, "rspace": 5}, "\u2280 infix": {"lspace": 5, "rspace": 5}, "\u2281 infix": {"lspace": 5, "rspace": 5}, "\u2282 infix": {"lspace": 5, "rspace": 5}, "\u2283 infix": {"lspace": 5, "rspace": 5}, "\u2284 infix": {"lspace": 5, "rspace": 5}, "\u2285 infix": {"lspace": 5, "rspace": 5}, "\u2286 infix": {"lspace": 5, "rspace": 5}, "\u2287 infix": {"lspace": 5, "rspace": 5}, "\u2288 infix": {"lspace": 5, "rspace": 5}, "\u2289 infix": {"lspace": 5, "rspace": 5}, "\u228a infix": {"lspace": 5, "rspace": 5}, "\u228b infix": {"lspace": 5, "rspace": 5}, "\u228c infix": {"lspace": 4, "rspace": 4}, "\u228d infix": {"lspace": 4, "rspace": 4}, "\u228e infix": {"lspace": 4, "rspace": 4}, "\u228f infix": {"lspace": 5, "rspace": 5}, "\u2290 infix": {"lspace": 5, "rspace": 5}, "\u2291 infix": {"lspace": 5, "rspace": 5}, "\u2292 infix": {"lspace": 5, "rspace": 5}, "\u2293 infix": {"lspace": 4, "rspace": 4}, "\u2294 infix": {"lspace": 4, "rspace": 4}, "\u2295 infix": {"lspace": 4, "rspace": 4}, "\u2296 infix": {"lspace": 4, "rspace": 4}, "\u2297 infix": {"lspace": 3, "rspace": 3}, "\u2298 infix": {"lspace": 4, "rspace": 4}, "\u2299 infix": {"lspace": 3, "rspace": 3}, "\u229a infix": {"lspace": 3, "rspace": 3}, "\u229b infix": {"lspace": 3, "rspace": 3}, "\u229c infix": {"lspace": 5, "rspace": 5}, "\u229d infix": {"lspace": 4, "rspace": 4}, "\u229e infix": {"lspace": 4, "rspace": 4}, "\u229f infix": {"lspace": 4, "rspace": 4}, "\u22a0 infix": {"lspace": 3, "rspace": 3}, "\u22a1 infix": {"lspace": 3, "rspace": 3}, "\u22a2 infix": {"lspace": 5, "rspace": 5}, "\u22a3 infix": {"lspace": 5, "rspace": 5}, "\u22a6 infix": {"lspace": 5, "rspace": 5}, "\u22a7 infix": {"lspace": 5, "rspace": 5}, "\u22a8 infix": {"lspace": 5, "rspace": 5}, "\u22a9 infix": {"lspace": 5, "rspace": 5}, "\u22aa infix": {"lspace": 5, "rspace": 5}, "\u22ab infix": {"lspace": 5, "rspace": 5}, "\u22ac infix": {"lspace": 5, "rspace": 5}, "\u22ad infix": {"lspace": 5, "rspace": 5}, "\u22ae infix": {"lspace": 5, "rspace": 5}, "\u22af infix": {"lspace": 5, "rspace": 5}, "\u22b0 infix": {"lspace": 5, "rspace": 5}, "\u22b1 infix": {"lspace": 5, "rspace": 5}, "\u22b2 infix": {"lspace": 5, "rspace": 5}, "\u22b3 infix": {"lspace": 5, "rspace": 5}, "\u22b4 infix": {"lspace": 5, "rspace": 5}, "\u22b5 infix": {"lspace": 5, "rspace": 5}, "\u22b6 infix": {"lspace": 5, "rspace": 5}, "\u22b7 infix": {"lspace": 5, "rspace": 5}, "\u22b8 infix": {"lspace": 5, "rspace": 5}, "\u22ba infix": {"lspace": 3, "rspace": 3}, "\u22bb infix": {"lspace": 4, "rspace": 4}, "\u22bc infix": {"lspace": 4, "rspace": 4}, "\u22bd infix": {"lspace": 4, "rspace": 4}, "\u22be prefix": {"lspace": 0, "rspace": 0}, "\u22bf prefix": {"lspace": 0, "rspace": 0}, "\u22c0 prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u22c1 prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u22c2 prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u22c3 prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u22c4 infix": {"lspace": 3, "rspace": 3}, "\u22c5 infix": {"lspace": 3, "rspace": 3}, "\u22c6 infix": {"lspace": 3, "rspace": 3}, "\u22c7 infix": {"lspace": 3, "rspace": 3}, "\u22c8 infix": {"lspace": 5, "rspace": 5}, "\u22c9 infix": {"lspace": 3, "rspace": 3}, "\u22ca infix": {"lspace": 3, "rspace": 3}, "\u22cb infix": {"lspace": 3, "rspace": 3}, "\u22cc infix": {"lspace": 3, "rspace": 3}, "\u22cd infix": {"lspace": 5, "rspace": 5}, "\u22ce infix": {"lspace": 4, "rspace": 4}, "\u22cf infix": {"lspace": 4, "rspace": 4}, "\u22d0 infix": {"lspace": 5, "rspace": 5}, "\u22d1 infix": {"lspace": 5, "rspace": 5}, "\u22d2 infix": {"lspace": 4, "rspace": 4}, "\u22d3 infix": {"lspace": 4, "rspace": 4}, "\u22d4 infix": {"lspace": 5, "rspace": 5}, "\u22d5 infix": {"lspace": 5, "rspace": 5}, "\u22d6 infix": {"lspace": 5, "rspace": 5}, "\u22d7 infix": {"lspace": 5, "rspace": 5}, "\u22d8 infix": {"lspace": 5, "rspace": 5}, "\u22d9 infix": {"lspace": 5, "rspace": 5}, "\u22da infix": {"lspace": 5, "rspace": 5}, "\u22db infix": {"lspace": 5, "rspace": 5}, "\u22dc infix": {"lspace": 5, "rspace": 5}, "\u22dd infix": {"lspace": 5, "rspace": 5}, "\u22de infix": {"lspace": 5, "rspace": 5}, "\u22df infix": {"lspace": 5, "rspace": 5}, "\u22e0 infix": {"lspace": 5, "rspace": 5}, "\u22e1 infix": {"lspace": 5, "rspace": 5}, "\u22e2 infix": {"lspace": 5, "rspace": 5}, "\u22e3 infix": {"lspace": 5, "rspace": 5}, "\u22e4 infix": {"lspace": 5, "rspace": 5}, "\u22e5 infix": {"lspace": 5, "rspace": 5}, "\u22e6 infix": {"lspace": 5, "rspace": 5}, "\u22e7 infix": {"lspace": 5, "rspace": 5}, "\u22e8 infix": {"lspace": 5, "rspace": 5}, "\u22e9 infix": {"lspace": 5, "rspace": 5}, "\u22ea infix": {"lspace": 5, "rspace": 5}, "\u22eb infix": {"lspace": 5, "rspace": 5}, "\u22ec infix": {"lspace": 5, "rspace": 5}, "\u22ed infix": {"lspace": 5, "rspace": 5}, "\u22f2 infix": {"lspace": 5, "rspace": 5}, "\u22f3 infix": {"lspace": 5, "rspace": 5}, "\u22f4 infix": {"lspace": 5, "rspace": 5}, "\u22f5 infix": {"lspace": 5, "rspace": 5}, "\u22f6 infix": {"lspace": 5, "rspace": 5}, "\u22f7 infix": {"lspace": 5, "rspace": 5}, "\u22f8 infix": {"lspace": 5, "rspace": 5}, "\u22f9 infix": {"lspace": 5, "rspace": 5}, "\u22fa infix": {"lspace": 5, "rspace": 5}, "\u22fb infix": {"lspace": 5, "rspace": 5}, "\u22fc infix": {"lspace": 5, "rspace": 5}, "\u22fd infix": {"lspace": 5, "rspace": 5}, "\u22fe infix": {"lspace": 5, "rspace": 5}, "\u22ff infix": {"lspace": 5, "rspace": 5}, "\u2301 infix": {"lspace": 5, "rspace": 5}, "\u2305 infix": {"lspace": 3, "rspace": 3}, "\u2306 infix": {"lspace": 3, "rspace": 3}, "\u2308 prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2309 postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u230a prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u230b postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2310 prefix": {"lspace": 0, "rspace": 0}, "\u2319 prefix": {"lspace": 0, "rspace": 0}, "\u2322 postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u2323 postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u2329 prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u232a postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u237c infix": {"lspace": 5, "rspace": 5}, "\u238b infix": {"lspace": 5, "rspace": 5}, "\u23b4 postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u23b5 postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u23cd postfix": {"lspace": 0, "rspace": 0}, "\u23dc postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u23dd postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u23de postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u23df postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u23e0 postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u23e1 postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\u2772 prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2773 postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2794 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2795 infix": {"lspace": 4, "rspace": 4}, "\u2795 prefix": {"lspace": 0, "rspace": 0}, "\u2796 infix": {"lspace": 4, "rspace": 4}, "\u2796 prefix": {"lspace": 0, "rspace": 0}, "\u2797 infix": {"lspace": 4, "rspace": 4}, "\u2798 infix": {"lspace": 5, "rspace": 5}, "\u2799 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u279a infix": {"lspace": 5, "rspace": 5}, "\u279b infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u279c infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u279d infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u279e infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u279f infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27a0 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27a1 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27a5 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27a6 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27a7 infix": {"lspace": 5, "rspace": 5}, "\u27a8 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27a9 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27aa infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27ab infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27ac infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27ad infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27ae infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27af infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27b1 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27b2 infix": {"lspace": 5, "rspace": 5}, "\u27b3 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27b4 infix": {"lspace": 5, "rspace": 5}, "\u27b5 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27b6 infix": {"lspace": 5, "rspace": 5}, "\u27b7 infix": {"lspace": 5, "rspace": 5}, "\u27b8 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27b9 infix": {"lspace": 5, "rspace": 5}, "\u27ba infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27bb infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27bc infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27bd infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27be infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27c0 prefix": {"lspace": 0, "rspace": 0}, "\u27c2 infix": {"lspace": 5, "rspace": 5}, "\u27cb infix": {"lspace": 3, "rspace": 3}, "\u27cd infix": {"lspace": 3, "rspace": 3}, "\u27e6 prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u27e7 postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u27e8 prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u27e9 postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u27ea prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u27eb postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u27ec prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u27ed postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u27ee prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u27ef postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u27f0 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u27f1 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u27f2 infix": {"lspace": 5, "rspace": 5}, "\u27f3 infix": {"lspace": 5, "rspace": 5}, "\u27f4 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27f5 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27f6 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27f7 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27f8 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27f9 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27fa infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27fb infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27fc infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27fd infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27fe infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u27ff infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2900 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2901 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2902 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2903 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2904 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2905 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2906 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2907 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2908 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2909 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u290a infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u290b infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u290c infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u290d infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u290e infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u290f infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2910 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2911 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2912 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2913 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2914 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2915 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2916 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2917 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2918 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2919 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u291a infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u291b infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u291c infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u291d infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u291e infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u291f infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2920 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2921 infix": {"lspace": 5, "rspace": 5}, "\u2922 infix": {"lspace": 5, "rspace": 5}, "\u2923 infix": {"lspace": 5, "rspace": 5}, "\u2924 infix": {"lspace": 5, "rspace": 5}, "\u2925 infix": {"lspace": 5, "rspace": 5}, "\u2926 infix": {"lspace": 5, "rspace": 5}, "\u2927 infix": {"lspace": 5, "rspace": 5}, "\u2928 infix": {"lspace": 5, "rspace": 5}, "\u2929 infix": {"lspace": 5, "rspace": 5}, "\u292a infix": {"lspace": 5, "rspace": 5}, "\u292b infix": {"lspace": 5, "rspace": 5}, "\u292c infix": {"lspace": 5, "rspace": 5}, "\u292d infix": {"lspace": 5, "rspace": 5}, "\u292e infix": {"lspace": 5, "rspace": 5}, "\u292f infix": {"lspace": 5, "rspace": 5}, "\u2930 infix": {"lspace": 5, "rspace": 5}, "\u2931 infix": {"lspace": 5, "rspace": 5}, "\u2932 infix": {"lspace": 5, "rspace": 5}, "\u2933 infix": {"lspace": 5, "rspace": 5}, "\u2934 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2935 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2936 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2937 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2938 infix": {"lspace": 5, "rspace": 5}, "\u2939 infix": {"lspace": 5, "rspace": 5}, "\u293a infix": {"lspace": 5, "rspace": 5}, "\u293b infix": {"lspace": 5, "rspace": 5}, "\u293c infix": {"lspace": 5, "rspace": 5}, "\u293d infix": {"lspace": 5, "rspace": 5}, "\u293e infix": {"lspace": 5, "rspace": 5}, "\u293f infix": {"lspace": 5, "rspace": 5}, "\u2940 infix": {"lspace": 5, "rspace": 5}, "\u2941 infix": {"lspace": 5, "rspace": 5}, "\u2942 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2943 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2944 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2945 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2946 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2947 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2948 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2949 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u294a infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u294b infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u294c infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u294d infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u294e infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u294f infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2950 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2951 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2952 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2953 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2954 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2955 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2956 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2957 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2958 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2959 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u295a infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u295b infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u295c infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u295d infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u295e infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u295f infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2960 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2961 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2962 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2963 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2964 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2965 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2966 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2967 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2968 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2969 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u296a infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u296b infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u296c infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u296d infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u296e infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u296f infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2970 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2971 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2972 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2973 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2974 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2975 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2976 infix": {"lspace": 5, "rspace": 5}, "\u2977 infix": {"lspace": 5, "rspace": 5}, "\u2978 infix": {"lspace": 5, "rspace": 5}, "\u2979 infix": {"lspace": 5, "rspace": 5}, "\u297a infix": {"lspace": 5, "rspace": 5}, "\u297b infix": {"lspace": 5, "rspace": 5}, "\u297c infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u297d infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u297e infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u297f infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2980 postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2980 prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2981 infix": {"lspace": 5, "rspace": 5}, "\u2982 infix": {"lspace": 5, "rspace": 5}, "\u2983 prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2984 postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2985 prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2986 postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2987 prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2988 postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2989 prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u298a postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u298b prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u298c postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u298d prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u298e postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u298f prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2990 postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2991 prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2992 postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2993 prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2994 postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2995 prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2996 postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2997 prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2998 postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2999 postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2999 prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u299b prefix": {"lspace": 0, "rspace": 0}, "\u299c prefix": {"lspace": 0, "rspace": 0}, "\u299d prefix": {"lspace": 0, "rspace": 0}, "\u299e prefix": {"lspace": 0, "rspace": 0}, "\u299f prefix": {"lspace": 0, "rspace": 0}, "\u29a0 prefix": {"lspace": 0, "rspace": 0}, "\u29a1 prefix": {"lspace": 0, "rspace": 0}, "\u29a2 prefix": {"lspace": 0, "rspace": 0}, "\u29a3 prefix": {"lspace": 0, "rspace": 0}, "\u29a4 prefix": {"lspace": 0, "rspace": 0}, "\u29a5 prefix": {"lspace": 0, "rspace": 0}, "\u29a6 prefix": {"lspace": 0, "rspace": 0}, "\u29a7 prefix": {"lspace": 0, "rspace": 0}, "\u29a8 prefix": {"lspace": 0, "rspace": 0}, "\u29a9 prefix": {"lspace": 0, "rspace": 0}, "\u29aa prefix": {"lspace": 0, "rspace": 0}, "\u29ab prefix": {"lspace": 0, "rspace": 0}, "\u29ac prefix": {"lspace": 0, "rspace": 0}, "\u29ad prefix": {"lspace": 0, "rspace": 0}, "\u29ae prefix": {"lspace": 0, "rspace": 0}, "\u29af prefix": {"lspace": 0, "rspace": 0}, "\u29b6 infix": {"lspace": 5, "rspace": 5}, "\u29b7 infix": {"lspace": 5, "rspace": 5}, "\u29b8 infix": {"lspace": 4, "rspace": 4}, "\u29b9 infix": {"lspace": 5, "rspace": 5}, "\u29bc infix": {"lspace": 4, "rspace": 4}, "\u29c0 infix": {"lspace": 5, "rspace": 5}, "\u29c1 infix": {"lspace": 5, "rspace": 5}, "\u29c4 infix": {"lspace": 4, "rspace": 4}, "\u29c5 infix": {"lspace": 4, "rspace": 4}, "\u29c6 infix": {"lspace": 3, "rspace": 3}, "\u29c7 infix": {"lspace": 3, "rspace": 3}, "\u29c8 infix": {"lspace": 3, "rspace": 3}, "\u29ce infix": {"lspace": 5, "rspace": 5}, "\u29cf infix": {"lspace": 5, "rspace": 5}, "\u29d0 infix": {"lspace": 5, "rspace": 5}, "\u29d1 infix": {"lspace": 5, "rspace": 5}, "\u29d2 infix": {"lspace": 5, "rspace": 5}, "\u29d3 infix": {"lspace": 5, "rspace": 5}, "\u29d4 infix": {"lspace": 3, "rspace": 3}, "\u29d5 infix": {"lspace": 3, "rspace": 3}, "\u29d6 infix": {"lspace": 3, "rspace": 3}, "\u29d7 infix": {"lspace": 3, "rspace": 3}, "\u29d8 prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u29d9 postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u29da prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u29db postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u29df infix": {"lspace": 5, "rspace": 5}, "\u29e1 infix": {"lspace": 5, "rspace": 5}, "\u29e2 infix": {"lspace": 3, "rspace": 3}, "\u29e3 infix": {"lspace": 5, "rspace": 5}, "\u29e4 infix": {"lspace": 5, "rspace": 5}, "\u29e5 infix": {"lspace": 5, "rspace": 5}, "\u29e6 infix": {"lspace": 5, "rspace": 5}, "\u29f4 infix": {"lspace": 5, "rspace": 5}, "\u29f5 infix": {"lspace": 4, "rspace": 4}, "\u29f6 infix": {"lspace": 4, "rspace": 4}, "\u29f7 infix": {"lspace": 4, "rspace": 4}, "\u29f8 infix": {"lspace": 4, "rspace": 4}, "\u29f9 infix": {"lspace": 4, "rspace": 4}, "\u29fa infix": {"lspace": 4, "rspace": 4}, "\u29fb infix": {"lspace": 4, "rspace": 4}, "\u29fc prefix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u29fd postfix": {"lspace": 0, "rspace": 0, "stretchy": true, "symmetric": true}, "\u2a00 prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2a01 prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2a02 prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2a03 prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2a04 prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2a05 prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2a06 prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2a07 prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2a08 prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2a09 prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2a0a prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2a0b prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a0c prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a0d prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a0e prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a0f prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a10 prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a11 prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a12 prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a13 prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a14 prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a15 prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a16 prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a17 prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a18 prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a19 prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a1a prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a1b prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a1c prefix": {"largeop": true, "lspace": 3, "rspace": 3, "symmetric": true}, "\u2a1d infix": {"lspace": 3, "rspace": 3}, "\u2a1d prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2a1e infix": {"lspace": 3, "rspace": 3}, "\u2a1e prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2a1f infix": {"lspace": 4, "rspace": 4}, "\u2a20 infix": {"lspace": 4, "rspace": 4}, "\u2a21 infix": {"lspace": 4, "rspace": 4}, "\u2a22 infix": {"lspace": 4, "rspace": 4}, "\u2a23 infix": {"lspace": 4, "rspace": 4}, "\u2a24 infix": {"lspace": 4, "rspace": 4}, "\u2a25 infix": {"lspace": 4, "rspace": 4}, "\u2a26 infix": {"lspace": 4, "rspace": 4}, "\u2a27 infix": {"lspace": 4, "rspace": 4}, "\u2a28 infix": {"lspace": 4, "rspace": 4}, "\u2a29 infix": {"lspace": 4, "rspace": 4}, "\u2a2a infix": {"lspace": 4, "rspace": 4}, "\u2a2b infix": {"lspace": 4, "rspace": 4}, "\u2a2c infix": {"lspace": 4, "rspace": 4}, "\u2a2d infix": {"lspace": 4, "rspace": 4}, "\u2a2e infix": {"lspace": 4, "rspace": 4}, "\u2a2f infix": {"lspace": 3, "rspace": 3}, "\u2a30 infix": {"lspace": 3, "rspace": 3}, "\u2a31 infix": {"lspace": 3, "rspace": 3}, "\u2a32 infix": {"lspace": 3, "rspace": 3}, "\u2a33 infix": {"lspace": 3, "rspace": 3}, "\u2a34 infix": {"lspace": 3, "rspace": 3}, "\u2a35 infix": {"lspace": 3, "rspace": 3}, "\u2a36 infix": {"lspace": 3, "rspace": 3}, "\u2a37 infix": {"lspace": 3, "rspace": 3}, "\u2a38 infix": {"lspace": 4, "rspace": 4}, "\u2a39 infix": {"lspace": 4, "rspace": 4}, "\u2a3a infix": {"lspace": 4, "rspace": 4}, "\u2a3b infix": {"lspace": 3, "rspace": 3}, "\u2a3c infix": {"lspace": 3, "rspace": 3}, "\u2a3d infix": {"lspace": 3, "rspace": 3}, "\u2a3e infix": {"lspace": 4, "rspace": 4}, "\u2a3f infix": {"lspace": 3, "rspace": 3}, "\u2a40 infix": {"lspace": 4, "rspace": 4}, "\u2a41 infix": {"lspace": 4, "rspace": 4}, "\u2a42 infix": {"lspace": 4, "rspace": 4}, "\u2a43 infix": {"lspace": 4, "rspace": 4}, "\u2a44 infix": {"lspace": 4, "rspace": 4}, "\u2a45 infix": {"lspace": 4, "rspace": 4}, "\u2a46 infix": {"lspace": 4, "rspace": 4}, "\u2a47 infix": {"lspace": 4, "rspace": 4}, "\u2a48 infix": {"lspace": 4, "rspace": 4}, "\u2a49 infix": {"lspace": 4, "rspace": 4}, "\u2a4a infix": {"lspace": 4, "rspace": 4}, "\u2a4b infix": {"lspace": 4, "rspace": 4}, "\u2a4c infix": {"lspace": 4, "rspace": 4}, "\u2a4d infix": {"lspace": 4, "rspace": 4}, "\u2a4e infix": {"lspace": 4, "rspace": 4}, "\u2a4f infix": {"lspace": 4, "rspace": 4}, "\u2a50 infix": {"lspace": 3, "rspace": 3}, "\u2a51 infix": {"lspace": 4, "rspace": 4}, "\u2a52 infix": {"lspace": 4, "rspace": 4}, "\u2a53 infix": {"lspace": 4, "rspace": 4}, "\u2a54 infix": {"lspace": 4, "rspace": 4}, "\u2a55 infix": {"lspace": 4, "rspace": 4}, "\u2a56 infix": {"lspace": 4, "rspace": 4}, "\u2a57 infix": {"lspace": 4, "rspace": 4}, "\u2a58 infix": {"lspace": 4, "rspace": 4}, "\u2a59 infix": {"lspace": 4, "rspace": 4}, "\u2a5a infix": {"lspace": 4, "rspace": 4}, "\u2a5b infix": {"lspace": 4, "rspace": 4}, "\u2a5c infix": {"lspace": 4, "rspace": 4}, "\u2a5d infix": {"lspace": 4, "rspace": 4}, "\u2a5e infix": {"lspace": 4, "rspace": 4}, "\u2a5f infix": {"lspace": 4, "rspace": 4}, "\u2a60 infix": {"lspace": 4, "rspace": 4}, "\u2a61 infix": {"lspace": 4, "rspace": 4}, "\u2a62 infix": {"lspace": 4, "rspace": 4}, "\u2a63 infix": {"lspace": 4, "rspace": 4}, "\u2a64 infix": {"lspace": 3, "rspace": 3}, "\u2a65 infix": {"lspace": 3, "rspace": 3}, "\u2a66 infix": {"lspace": 5, "rspace": 5}, "\u2a67 infix": {"lspace": 5, "rspace": 5}, "\u2a68 infix": {"lspace": 5, "rspace": 5}, "\u2a69 infix": {"lspace": 5, "rspace": 5}, "\u2a6a infix": {"lspace": 5, "rspace": 5}, "\u2a6b infix": {"lspace": 5, "rspace": 5}, "\u2a6c infix": {"lspace": 5, "rspace": 5}, "\u2a6d infix": {"lspace": 5, "rspace": 5}, "\u2a6e infix": {"lspace": 5, "rspace": 5}, "\u2a6f infix": {"lspace": 5, "rspace": 5}, "\u2a70 infix": {"lspace": 5, "rspace": 5}, "\u2a71 infix": {"lspace": 5, "rspace": 5}, "\u2a72 infix": {"lspace": 5, "rspace": 5}, "\u2a73 infix": {"lspace": 5, "rspace": 5}, "\u2a74 infix": {"lspace": 5, "rspace": 5}, "\u2a75 infix": {"lspace": 5, "rspace": 5}, "\u2a76 infix": {"lspace": 5, "rspace": 5}, "\u2a77 infix": {"lspace": 5, "rspace": 5}, "\u2a78 infix": {"lspace": 5, "rspace": 5}, "\u2a79 infix": {"lspace": 5, "rspace": 5}, "\u2a7a infix": {"lspace": 5, "rspace": 5}, "\u2a7b infix": {"lspace": 5, "rspace": 5}, "\u2a7c infix": {"lspace": 5, "rspace": 5}, "\u2a7d infix": {"lspace": 5, "rspace": 5}, "\u2a7e infix": {"lspace": 5, "rspace": 5}, "\u2a7f infix": {"lspace": 5, "rspace": 5}, "\u2a80 infix": {"lspace": 5, "rspace": 5}, "\u2a81 infix": {"lspace": 5, "rspace": 5}, "\u2a82 infix": {"lspace": 5, "rspace": 5}, "\u2a83 infix": {"lspace": 5, "rspace": 5}, "\u2a84 infix": {"lspace": 5, "rspace": 5}, "\u2a85 infix": {"lspace": 5, "rspace": 5}, "\u2a86 infix": {"lspace": 5, "rspace": 5}, "\u2a87 infix": {"lspace": 5, "rspace": 5}, "\u2a88 infix": {"lspace": 5, "rspace": 5}, "\u2a89 infix": {"lspace": 5, "rspace": 5}, "\u2a8a infix": {"lspace": 5, "rspace": 5}, "\u2a8b infix": {"lspace": 5, "rspace": 5}, "\u2a8c infix": {"lspace": 5, "rspace": 5}, "\u2a8d infix": {"lspace": 5, "rspace": 5}, "\u2a8e infix": {"lspace": 5, "rspace": 5}, "\u2a8f infix": {"lspace": 5, "rspace": 5}, "\u2a90 infix": {"lspace": 5, "rspace": 5}, "\u2a91 infix": {"lspace": 5, "rspace": 5}, "\u2a92 infix": {"lspace": 5, "rspace": 5}, "\u2a93 infix": {"lspace": 5, "rspace": 5}, "\u2a94 infix": {"lspace": 5, "rspace": 5}, "\u2a95 infix": {"lspace": 5, "rspace": 5}, "\u2a96 infix": {"lspace": 5, "rspace": 5}, "\u2a97 infix": {"lspace": 5, "rspace": 5}, "\u2a98 infix": {"lspace": 5, "rspace": 5}, "\u2a99 infix": {"lspace": 5, "rspace": 5}, "\u2a9a infix": {"lspace": 5, "rspace": 5}, "\u2a9b infix": {"lspace": 5, "rspace": 5}, "\u2a9c infix": {"lspace": 5, "rspace": 5}, "\u2a9d infix": {"lspace": 5, "rspace": 5}, "\u2a9e infix": {"lspace": 5, "rspace": 5}, "\u2a9f infix": {"lspace": 5, "rspace": 5}, "\u2aa0 infix": {"lspace": 5, "rspace": 5}, "\u2aa1 infix": {"lspace": 5, "rspace": 5}, "\u2aa2 infix": {"lspace": 5, "rspace": 5}, "\u2aa3 infix": {"lspace": 5, "rspace": 5}, "\u2aa4 infix": {"lspace": 5, "rspace": 5}, "\u2aa5 infix": {"lspace": 5, "rspace": 5}, "\u2aa6 infix": {"lspace": 5, "rspace": 5}, "\u2aa7 infix": {"lspace": 5, "rspace": 5}, "\u2aa8 infix": {"lspace": 5, "rspace": 5}, "\u2aa9 infix": {"lspace": 5, "rspace": 5}, "\u2aaa infix": {"lspace": 5, "rspace": 5}, "\u2aab infix": {"lspace": 5, "rspace": 5}, "\u2aac infix": {"lspace": 5, "rspace": 5}, "\u2aad infix": {"lspace": 5, "rspace": 5}, "\u2aae infix": {"lspace": 5, "rspace": 5}, "\u2aaf infix": {"lspace": 5, "rspace": 5}, "\u2ab0 infix": {"lspace": 5, "rspace": 5}, "\u2ab1 infix": {"lspace": 5, "rspace": 5}, "\u2ab2 infix": {"lspace": 5, "rspace": 5}, "\u2ab3 infix": {"lspace": 5, "rspace": 5}, "\u2ab4 infix": {"lspace": 5, "rspace": 5}, "\u2ab5 infix": {"lspace": 5, "rspace": 5}, "\u2ab6 infix": {"lspace": 5, "rspace": 5}, "\u2ab7 infix": {"lspace": 5, "rspace": 5}, "\u2ab8 infix": {"lspace": 5, "rspace": 5}, "\u2ab9 infix": {"lspace": 5, "rspace": 5}, "\u2aba infix": {"lspace": 5, "rspace": 5}, "\u2abb infix": {"lspace": 5, "rspace": 5}, "\u2abc infix": {"lspace": 5, "rspace": 5}, "\u2abd infix": {"lspace": 5, "rspace": 5}, "\u2abe infix": {"lspace": 5, "rspace": 5}, "\u2abf infix": {"lspace": 5, "rspace": 5}, "\u2ac0 infix": {"lspace": 5, "rspace": 5}, "\u2ac1 infix": {"lspace": 5, "rspace": 5}, "\u2ac2 infix": {"lspace": 5, "rspace": 5}, "\u2ac3 infix": {"lspace": 5, "rspace": 5}, "\u2ac4 infix": {"lspace": 5, "rspace": 5}, "\u2ac5 infix": {"lspace": 5, "rspace": 5}, "\u2ac6 infix": {"lspace": 5, "rspace": 5}, "\u2ac7 infix": {"lspace": 5, "rspace": 5}, "\u2ac8 infix": {"lspace": 5, "rspace": 5}, "\u2ac9 infix": {"lspace": 5, "rspace": 5}, "\u2aca infix": {"lspace": 5, "rspace": 5}, "\u2acb infix": {"lspace": 5, "rspace": 5}, "\u2acc infix": {"lspace": 5, "rspace": 5}, "\u2acd infix": {"lspace": 5, "rspace": 5}, "\u2ace infix": {"lspace": 5, "rspace": 5}, "\u2acf infix": {"lspace": 5, "rspace": 5}, "\u2ad0 infix": {"lspace": 5, "rspace": 5}, "\u2ad1 infix": {"lspace": 5, "rspace": 5}, "\u2ad2 infix": {"lspace": 5, "rspace": 5}, "\u2ad3 infix": {"lspace": 5, "rspace": 5}, "\u2ad4 infix": {"lspace": 5, "rspace": 5}, "\u2ad5 infix": {"lspace": 5, "rspace": 5}, "\u2ad6 infix": {"lspace": 5, "rspace": 5}, "\u2ad7 infix": {"lspace": 5, "rspace": 5}, "\u2ad8 infix": {"lspace": 5, "rspace": 5}, "\u2ad9 infix": {"lspace": 5, "rspace": 5}, "\u2ada infix": {"lspace": 5, "rspace": 5}, "\u2adb infix": {"lspace": 4, "rspace": 4}, "\u2adc infix": {"lspace": 3, "rspace": 3}, "\u2add infix": {"lspace": 3, "rspace": 3}, "\u2ade infix": {"lspace": 5, "rspace": 5}, "\u2adf infix": {"lspace": 5, "rspace": 5}, "\u2ae0 infix": {"lspace": 5, "rspace": 5}, "\u2ae1 infix": {"lspace": 5, "rspace": 5}, "\u2ae2 infix": {"lspace": 5, "rspace": 5}, "\u2ae3 infix": {"lspace": 5, "rspace": 5}, "\u2ae4 infix": {"lspace": 5, "rspace": 5}, "\u2ae5 infix": {"lspace": 5, "rspace": 5}, "\u2ae6 infix": {"lspace": 5, "rspace": 5}, "\u2ae7 infix": {"lspace": 5, "rspace": 5}, "\u2ae8 infix": {"lspace": 5, "rspace": 5}, "\u2ae9 infix": {"lspace": 5, "rspace": 5}, "\u2aea infix": {"lspace": 5, "rspace": 5}, "\u2aeb infix": {"lspace": 5, "rspace": 5}, "\u2aec prefix": {"lspace": 0, "rspace": 0}, "\u2aed prefix": {"lspace": 0, "rspace": 0}, "\u2aee infix": {"lspace": 5, "rspace": 5}, "\u2af2 infix": {"lspace": 5, "rspace": 5}, "\u2af3 infix": {"lspace": 5, "rspace": 5}, "\u2af4 infix": {"lspace": 5, "rspace": 5}, "\u2af5 infix": {"lspace": 5, "rspace": 5}, "\u2af6 infix": {"lspace": 4, "rspace": 4}, "\u2af7 infix": {"lspace": 5, "rspace": 5}, "\u2af8 infix": {"lspace": 5, "rspace": 5}, "\u2af9 infix": {"lspace": 5, "rspace": 5}, "\u2afa infix": {"lspace": 5, "rspace": 5}, "\u2afb infix": {"lspace": 4, "rspace": 4}, "\u2afc prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2afd infix": {"lspace": 4, "rspace": 4}, "\u2afe infix": {"lspace": 3, "rspace": 3}, "\u2aff prefix": {"largeop": true, "lspace": 3, "movablelimits": true, "rspace": 3, "symmetric": true}, "\u2b00 infix": {"lspace": 5, "rspace": 5}, "\u2b01 infix": {"lspace": 5, "rspace": 5}, "\u2b02 infix": {"lspace": 5, "rspace": 5}, "\u2b03 infix": {"lspace": 5, "rspace": 5}, "\u2b04 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b05 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b06 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b07 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b08 infix": {"lspace": 5, "rspace": 5}, "\u2b09 infix": {"lspace": 5, "rspace": 5}, "\u2b0a infix": {"lspace": 5, "rspace": 5}, "\u2b0b infix": {"lspace": 5, "rspace": 5}, "\u2b0c infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b0d infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b0e infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b0f infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b10 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b11 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b30 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b31 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b32 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b33 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b34 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b35 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b36 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b37 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b38 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b39 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b3a infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b3b infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b3c infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b3d infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b3e infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b3f infix": {"lspace": 5, "rspace": 5}, "\u2b40 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b41 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b42 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b43 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b44 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b45 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b46 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b47 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b48 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b49 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b4a infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b4b infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b4c infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b4d infix": {"lspace": 5, "rspace": 5}, "\u2b4e infix": {"lspace": 5, "rspace": 5}, "\u2b4f infix": {"lspace": 5, "rspace": 5}, "\u2b5a infix": {"lspace": 5, "rspace": 5}, "\u2b5b infix": {"lspace": 5, "rspace": 5}, "\u2b5c infix": {"lspace": 5, "rspace": 5}, "\u2b5d infix": {"lspace": 5, "rspace": 5}, "\u2b5e infix": {"lspace": 5, "rspace": 5}, "\u2b5f infix": {"lspace": 5, "rspace": 5}, "\u2b60 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b61 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b62 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b63 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b64 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b65 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b66 infix": {"lspace": 5, "rspace": 5}, "\u2b67 infix": {"lspace": 5, "rspace": 5}, "\u2b68 infix": {"lspace": 5, "rspace": 5}, "\u2b69 infix": {"lspace": 5, "rspace": 5}, "\u2b6a infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b6b infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b6c infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b6d infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b6e infix": {"lspace": 5, "rspace": 5}, "\u2b6f infix": {"lspace": 5, "rspace": 5}, "\u2b70 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b71 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b72 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b73 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b76 infix": {"lspace": 5, "rspace": 5}, "\u2b77 infix": {"lspace": 5, "rspace": 5}, "\u2b78 infix": {"lspace": 5, "rspace": 5}, "\u2b79 infix": {"lspace": 5, "rspace": 5}, "\u2b7a infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b7b infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b7c infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b7d infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b80 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b81 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b82 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b83 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b84 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b85 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b86 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2b87 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2b88 infix": {"lspace": 5, "rspace": 5}, "\u2b89 infix": {"lspace": 5, "rspace": 5}, "\u2b8a infix": {"lspace": 5, "rspace": 5}, "\u2b8b infix": {"lspace": 5, "rspace": 5}, "\u2b8c infix": {"lspace": 5, "rspace": 5}, "\u2b8d infix": {"lspace": 5, "rspace": 5}, "\u2b8e infix": {"lspace": 5, "rspace": 5}, "\u2b8f infix": {"lspace": 5, "rspace": 5}, "\u2b94 infix": {"lspace": 5, "rspace": 5}, "\u2b95 infix": {"horizontal": true, "lspace": 5, "rspace": 5, "stretchy": true}, "\u2ba0 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2ba1 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2ba2 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2ba3 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2ba4 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2ba5 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2ba6 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2ba7 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2ba8 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2ba9 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2baa infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2bab infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2bac infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2bad infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2bae infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2baf infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2bb0 infix": {"lspace": 5, "rspace": 5}, "\u2bb1 infix": {"lspace": 5, "rspace": 5}, "\u2bb2 infix": {"lspace": 5, "rspace": 5}, "\u2bb3 infix": {"lspace": 5, "rspace": 5}, "\u2bb4 infix": {"lspace": 5, "rspace": 5}, "\u2bb5 infix": {"lspace": 5, "rspace": 5}, "\u2bb6 infix": {"lspace": 5, "rspace": 5}, "\u2bb7 infix": {"lspace": 5, "rspace": 5}, "\u2bb8 infix": {"lspace": 5, "rspace": 5, "stretchy": true}, "\u2bd1 infix": {"lspace": 5, "rspace": 5}, "\ud83b\udef0 postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}, "\ud83b\udef1 postfix": {"horizontal": true, "lspace": 0, "rspace": 0, "stretchy": true}}} \ No newline at end of file
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..7640c4f789
--- /dev/null
+++ b/testing/web-platform/tests/mathml/tools/axisheight.py
@@ -0,0 +1,27 @@
+#!/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..9832ff0039
--- /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..db4437c1b0
--- /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..2c3e3257dc
--- /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..e4857d2a3e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/tools/mathvariant-transforms.py
@@ -0,0 +1,202 @@
+#!/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)
+
+# Common function to generate test for MathML mathvariant / CSS text-transform.
+
+
+def generateTestFor(mathvariant, mathml):
+ assert mathml or mathvariant == "auto", "These tests have been removed!"
+ print("Generating tests for %s..." % mathvariant, end="")
+ if mathml:
+ reftest = open(
+ "../relations/css-styling/mathvariant-%s.html" % mathvariant, "w")
+ reftestReference = open(
+ "../relations/css-styling/mathvariant-%s-ref.html" % mathvariant, "w")
+ else:
+ reftest = open(
+ "../../css/css-text/text-transform/math/text-transform-math-%s-001.html" % mathvariant, "w")
+ reftestReference = open(
+ "../../css/css-text/text-transform/math/text-transform-math-%s-001-ref.html" % mathvariant, "w")
+ source = '\
+<!DOCTYPE html>\n\
+<html>\n\
+<head>\n\
+<meta charset="utf-8"/>\n\
+<title>%s</title>\n'
+ if mathml:
+ reftest.write(source % ("mathvariant %s" % mathvariant))
+ reftestReference.write(
+ source % ("mathvariant %s (reference)" % mathvariant))
+ else:
+ reftest.write(source % ("text-transform math-%s" % mathvariant))
+ reftestReference.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
+ if mathml:
+ 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))
+ else:
+ 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-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'
+ reftest.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
+ if mathml:
+ reftest.write(source)
+ reftestReference.write(source)
+ else:
+ reftest.write(source)
+ reftestReference.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
+ if mathml:
+ 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))
+ else:
+ reftest.write(' <span><span class="testfont" style="text-transform: math-%s">&#x%0X;</span>=<span>%05X</span></span>' %
+ (mathvariant, baseChar, transformedChar))
+ reftestReference.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/>')
+ reftest.write('\n')
+ reftestReference.write('\n')
+ source = '</body>\n</html>\n'
+ reftest.write(source)
+ reftestReference.write(source)
+ reftest.close()
+ reftestReference.close()
+ print(" done.")
+
+
+# Generate css/css-text/text-transform/math/text-transform-math-auto-001.html
+generateTestFor(mathvariant="auto", mathml=False)
+generateTestFor(mathvariant="auto", mathml=True)
+
+# Other mathvariant tests can be generated by the following command. They are
+# still use internally by browsers implementing full mathvariant support.
+# See https://github.com/w3c/mathml-core/issues/182
+# for mathvariant in mathvariantTransforms:
+# generateTestFor(mathvariant, mathml=True)
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..8de654df15
--- /dev/null
+++ b/testing/web-platform/tests/mathml/tools/operator-dictionary.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python3
+
+from lxml import etree
+from utils.misc import downloadWithProgressBar, UnicodeXMLURL, InlineAxisOperatorsURL
+import json
+import 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(r"^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..c4d9ece813
--- /dev/null
+++ b/testing/web-platform/tests/mathml/tools/radicals.py
@@ -0,0 +1,133 @@
+#!/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..e6c0b8b4dd
--- /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-centered-on-baseline.py b/testing/web-platform/tests/mathml/tools/stretchy-centered-on-baseline.py
new file mode 100755
index 0000000000..5ccfca3f1e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/tools/stretchy-centered-on-baseline.py
@@ -0,0 +1,44 @@
+#!/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-centered-on-baseline",
+ "Copyright (c) 2023 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, aUsePUA=True, aCenterOnBaseline=True)
+
+# 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/stretchy.py b/testing/web-platform/tests/mathml/tools/stretchy.py
new file mode 100755
index 0000000000..34530f5792
--- /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, aUsePUA=True, aCenterOnBaseline=False)
+
+# 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..469829cba2
--- /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..6509a65175
--- /dev/null
+++ b/testing/web-platform/tests/mathml/tools/use-typo-lineheight.py
@@ -0,0 +1,53 @@
+#!/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..c1e4c6d32e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/tools/utils/__init__.py
@@ -0,0 +1 @@
+# This file is required for Python to search this directory for modules.
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..3eff0ac03d
--- /dev/null
+++ b/testing/web-platform/tests/mathml/tools/utils/mathfont.py
@@ -0,0 +1,232 @@
+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, aCenterOnBaseline=False):
+ if aUsePUA:
+ codePoint = PUA_startCodePoint
+ else:
+ codePoint = -1
+ for size in (0, 1, 2, 3):
+ g = aFont.createChar(codePoint, "v%d" % size)
+ if aCenterOnBaseline:
+ drawRectangleGlyph(g, em, (size + 1) * em / 2, (size + 1) * em / 2)
+ else:
+ drawRectangleGlyph(g, em, (size + 1) * em, 0)
+ if aUsePUA:
+ codePoint += 1
+ g = aFont.createChar(codePoint, "h%d" % size)
+ if aCenterOnBaseline:
+ drawRectangleGlyph(g, (size + 1) * em, em / 2, em / 2)
+ else:
+ 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..cc3b21906e
--- /dev/null
+++ b/testing/web-platform/tests/mathml/tools/utils/misc.py
@@ -0,0 +1,35 @@
+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)