From 7fd8e44b5afae79621c5aaf4489a61af303486f2 Mon Sep 17 00:00:00 2001 From: "Davide P. Cervone" Date: Thu, 24 Oct 2024 17:36:04 -0400 Subject: [PATCH 1/2] Make over/under braces and matrices be full size, as in actual TeX (mathjax/MathJax#3300) --- ts/core/MmlTree/MmlNode.ts | 10 ++-------- ts/core/MmlTree/MmlNodes/mtable.ts | 1 - ts/core/MmlTree/MmlVisitor.ts | 3 +-- ts/input/mathml/MathMLCompile.ts | 2 +- ts/input/tex.ts | 5 +++-- ts/input/tex/FilterUtil.ts | 28 ++++++++++++++++++++++++++++ ts/input/tex/ParseUtil.ts | 4 +++- ts/input/tex/ams/AmsMappings.ts | 4 ++-- ts/input/tex/base/BaseItems.ts | 5 ++++- ts/input/tex/base/BaseMethods.ts | 2 ++ 10 files changed, 46 insertions(+), 18 deletions(-) diff --git a/ts/core/MmlTree/MmlNode.ts b/ts/core/MmlTree/MmlNode.ts index 3575d6704..937fc88c1 100644 --- a/ts/core/MmlTree/MmlNode.ts +++ b/ts/core/MmlTree/MmlNode.ts @@ -771,14 +771,8 @@ export abstract class AbstractMmlNode delete attributes[key]; } } - const displaystyle = this.attributes.getExplicit('displaystyle'); - if (displaystyle === undefined) { - this.attributes.setInherited('displaystyle', display); - } - const scriptlevel = this.attributes.getExplicit('scriptlevel'); - if (scriptlevel === undefined) { - this.attributes.setInherited('scriptlevel', level); - } + this.attributes.setInherited('displaystyle', display); + this.attributes.setInherited('scriptlevel', level); if (prime) { this.setProperty('texprimestyle', prime); } diff --git a/ts/core/MmlTree/MmlNodes/mtable.ts b/ts/core/MmlTree/MmlNodes/mtable.ts index b50f26258..b803fcb6b 100644 --- a/ts/core/MmlTree/MmlNodes/mtable.ts +++ b/ts/core/MmlTree/MmlNodes/mtable.ts @@ -142,7 +142,6 @@ export class MmlMtable extends AbstractMmlNode { this.replaceChild(this.factory.create('mtr'), child).appendChild(child); } } - level = (this.getProperty('scriptlevel') as number) || level; display = !!( this.attributes.getExplicit('displaystyle') || this.attributes.getDefault('displaystyle') diff --git a/ts/core/MmlTree/MmlVisitor.ts b/ts/core/MmlTree/MmlVisitor.ts index de1bcfead..dcdef661c 100644 --- a/ts/core/MmlTree/MmlVisitor.ts +++ b/ts/core/MmlTree/MmlVisitor.ts @@ -201,8 +201,7 @@ export class MmlVisitor extends AbstractVisitor { texclass < 0 ? 'NONE' : TEXCLASSNAMES[texclass] ); } - node.getProperty('scriptlevel') && - node.getProperty('useHeight') === false && + node.getProperty('smallmatrix') && this.setDataAttribute(data, 'smallmatrix', 'true'); return data; } diff --git a/ts/input/mathml/MathMLCompile.ts b/ts/input/mathml/MathMLCompile.ts index 74464c4e1..bf7919157 100644 --- a/ts/input/mathml/MathMLCompile.ts +++ b/ts/input/mathml/MathMLCompile.ts @@ -215,7 +215,7 @@ export class MathMLCompile { ignoreVariant = true; break; case 'smallmatrix': - mml.setProperty('scriptlevel', 1); + mml.setProperty('smallmatrix', true); mml.setProperty('useHeight', false); break; case 'mathaccent': diff --git a/ts/input/tex.ts b/ts/input/tex.ts index f6dce8bad..1b19bafb3 100644 --- a/ts/input/tex.ts +++ b/ts/input/tex.ts @@ -157,8 +157,9 @@ export class TeX extends AbstractInputJax { userOptions(parseOptions.options, rest); configuration.config(this); TeX.tags(parseOptions, configuration); - this.postFilters.add(FilterUtil.cleanSubSup, -6); - this.postFilters.add(FilterUtil.setInherited, -5); + this.postFilters.add(FilterUtil.cleanSubSup, -7); + this.postFilters.add(FilterUtil.setInherited, -6); + this.postFilters.add(FilterUtil.checkScriptlevel, -5); this.postFilters.add(FilterUtil.moveLimits, -4); this.postFilters.add(FilterUtil.cleanStretchy, -3); this.postFilters.add(FilterUtil.cleanAttributes, -2); diff --git a/ts/input/tex/FilterUtil.ts b/ts/input/tex/FilterUtil.ts index 1d3959e7c..f748e3f49 100644 --- a/ts/input/tex/FilterUtil.ts +++ b/ts/input/tex/FilterUtil.ts @@ -333,6 +333,34 @@ namespace FilterUtil { }) { arg.data.root.setInheritedAttributes({}, arg.math['display'], 0, false); }; + + + /** + * Removes unneeded mstyle elements that just set the scriptlevel + */ + export const checkScriptlevel = function (arg: { data: ParseOptions }) { + const options = arg.data; + const remove: MmlNode[] = []; + for (const mml of options.getList('mstyle')) { + if (mml.childNodes?.[0]?.childNodes?.length !== 1) { + continue; + } + const attributes = mml.attributes; + for (const key of ['displaystyle', 'scriptlevel']) { + if (attributes.getExplicit(key) === attributes.getInherited(key)) { + attributes.unset(key); + } + } + const names = attributes.getExplicitNames(); + if (names.filter(key => key.substring(0, 10) !== 'data-latex').length === 0) { + const child = mml.childNodes[0].childNodes[0]; + names.forEach(key => child.attributes.set(key, attributes.get(key))); + mml.parent.replaceChild(child, mml); + remove.push(mml); + } + } + options.removeFromList('mstyle', remove); + } } export default FilterUtil; diff --git a/ts/input/tex/ParseUtil.ts b/ts/input/tex/ParseUtil.ts index 5443c1cc7..a901ad094 100644 --- a/ts/input/tex/ParseUtil.ts +++ b/ts/input/tex/ParseUtil.ts @@ -637,7 +637,9 @@ export const ParseUtil = { let node: MmlNode = mml; if (stack) { // @test Overbrace 1 2 3, Underbrace, Overbrace Op 1 2 - node = parser.create('node', 'TeXAtom', [mml], { + node = parser.create('node', 'TeXAtom', [ + parser.create('node', 'mstyle', [mml], { displaystyle: true, scriptlevel: 0 }) + ], { texClass: TEXCLASS.OP, movesupsub: true, }); diff --git a/ts/input/tex/ams/AmsMappings.ts b/ts/input/tex/ams/AmsMappings.ts index 14555e6bd..dcbe4d07a 100644 --- a/ts/input/tex/ams/AmsMappings.ts +++ b/ts/input/tex/ams/AmsMappings.ts @@ -205,7 +205,7 @@ new sm.EnvironmentMap('AMSmath-environment', ParseMethods.environment, { ParseUtil.cols(0), '0.1em', 'S', - 1, + true, ], smallmatrix: [ AmsMethods.Array, @@ -216,7 +216,7 @@ new sm.EnvironmentMap('AMSmath-environment', ParseMethods.environment, { ParseUtil.cols(1 / 3), '.2em', 'S', - 1, + true, ], matrix: [AmsMethods.Array, null, null, null, 'c'], pmatrix: [AmsMethods.Array, null, '(', ')', 'c'], diff --git a/ts/input/tex/base/BaseItems.ts b/ts/input/tex/base/BaseItems.ts index 5b5ccd0bd..2d16efdb2 100644 --- a/ts/input/tex/base/BaseItems.ts +++ b/ts/input/tex/base/BaseItems.ts @@ -1092,7 +1092,7 @@ export class ArrayItem extends BaseItem { delete this.arraydef['scriptlevel']; let mml = this.create('node', 'mtable', this.table, this.arraydef); if (scriptlevel) { - mml.setProperty('scriptlevel', scriptlevel); + mml.setProperty('smallmatrix', true); } if (this.breakAlign.table) { NodeUtil.setAttribute(mml, 'data-break-align', this.breakAlign.table); @@ -1106,6 +1106,9 @@ export class ArrayItem extends BaseItem { ); } mml = this.handleFrame(mml); + if (scriptlevel !== undefined) { + mml = this.create('node', 'mstyle', [mml], { scriptlevel }); + } if (this.getProperty('open') || this.getProperty('close')) { // @test Cross Product Formula mml = ParseUtil.fenced( diff --git a/ts/input/tex/base/BaseMethods.ts b/ts/input/tex/base/BaseMethods.ts index 9e31d28ee..198c0ff4d 100644 --- a/ts/input/tex/base/BaseMethods.ts +++ b/ts/input/tex/base/BaseMethods.ts @@ -1961,6 +1961,8 @@ const BaseMethods: { [key: string]: ParseMethod } = { if (style === 'S') { // @test Subarray, Small Matrix array.arraydef['scriptlevel'] = 1; + } else { + array.arraydef['scriptlevel'] = 0; } if (raggedHeight) { // @test Subarray, Small Matrix From bf5fc52544e5db00248ee2aa675dfe234ecab52c Mon Sep 17 00:00:00 2001 From: "Davide P. Cervone" Date: Thu, 24 Oct 2024 17:54:54 -0400 Subject: [PATCH 2/2] Make prettier happy --- ts/input/tex/FilterUtil.ts | 10 ++++++---- ts/input/tex/ParseUtil.ts | 20 ++++++++++++++------ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/ts/input/tex/FilterUtil.ts b/ts/input/tex/FilterUtil.ts index f748e3f49..e4777ee9e 100644 --- a/ts/input/tex/FilterUtil.ts +++ b/ts/input/tex/FilterUtil.ts @@ -334,7 +334,6 @@ namespace FilterUtil { arg.data.root.setInheritedAttributes({}, arg.math['display'], 0, false); }; - /** * Removes unneeded mstyle elements that just set the scriptlevel */ @@ -352,15 +351,18 @@ namespace FilterUtil { } } const names = attributes.getExplicitNames(); - if (names.filter(key => key.substring(0, 10) !== 'data-latex').length === 0) { + if ( + names.filter((key) => key.substring(0, 10) !== 'data-latex').length === + 0 + ) { const child = mml.childNodes[0].childNodes[0]; - names.forEach(key => child.attributes.set(key, attributes.get(key))); + names.forEach((key) => child.attributes.set(key, attributes.get(key))); mml.parent.replaceChild(child, mml); remove.push(mml); } } options.removeFromList('mstyle', remove); - } + }; } export default FilterUtil; diff --git a/ts/input/tex/ParseUtil.ts b/ts/input/tex/ParseUtil.ts index a901ad094..1c689582b 100644 --- a/ts/input/tex/ParseUtil.ts +++ b/ts/input/tex/ParseUtil.ts @@ -637,12 +637,20 @@ export const ParseUtil = { let node: MmlNode = mml; if (stack) { // @test Overbrace 1 2 3, Underbrace, Overbrace Op 1 2 - node = parser.create('node', 'TeXAtom', [ - parser.create('node', 'mstyle', [mml], { displaystyle: true, scriptlevel: 0 }) - ], { - texClass: TEXCLASS.OP, - movesupsub: true, - }); + node = parser.create( + 'node', + 'TeXAtom', + [ + parser.create('node', 'mstyle', [mml], { + displaystyle: true, + scriptlevel: 0, + }), + ], + { + texClass: TEXCLASS.OP, + movesupsub: true, + } + ); } NodeUtil.setProperty(node, 'subsupOK', true); return node;