summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/mathml/presentation-markup
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/mathml/presentation-markup')
-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-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/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/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/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
267 files changed, 21472 insertions, 0 deletions
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..657d048211
--- /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"> <mstyle mathvariant="bold"> <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> </mstyle> </math> מודגשים גם הם</p>
+
+ <p>שורשי משוואה מודגשת זו <math id="x2" dir="ltr"> <mstyle mathvariant="bold"> <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> </mstyle> </math> מודגשים גם הם</p>
+
+ <p>שורשי משוואה מודגשת זו <math id="x3" dir="invalid"> <mstyle mathvariant="bold"> <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> </mstyle> </math> מודגשים גם הם</p>
+
+ <p>שורשי משוואה מודגשת זו <math id="x4" dir="rtl"> <mstyle mathvariant="bold"> <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> </mstyle> </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-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/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/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/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>