mml3.ts 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. /*************************************************************
  2. *
  3. * Copyright (c) 2021-2022 The MathJax Consortium
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /**
  18. * @fileoverview Implements the elementary MathML3 support (experimental)
  19. * using David Carlisle's XLST transform.
  20. *
  21. * @author dpvc@mathjax.org (Davide Cervone)
  22. */
  23. import {MathItem} from '../../../core/MathItem.js';
  24. import {MathDocument} from '../../../core/MathDocument.js';
  25. import {Handler} from '../../../core/Handler.js';
  26. import {OptionList} from '../../../util/Options.js';
  27. import {createTransform} from './mml3-node.js';
  28. import {MathML} from '../../mathml.js';
  29. /**
  30. * The data for a MathML prefilter.
  31. *
  32. * @template N The HTMLElement node class
  33. * @template T The Text node class
  34. * @template D The Document class
  35. */
  36. export type FILTERDATA<N, T, D> = {math: MathItem<N, T, D>, document: MathDocument<N, T, D>, data: N};
  37. /**
  38. * Class that handles XSLT transform for MathML3 elementary math tags.
  39. */
  40. export class Mml3<N, T, D> {
  41. /**
  42. * The XSLT transform as a string;
  43. */
  44. public static XSLT: string; // added below (it is huge)
  45. /**
  46. * The function to convert serialized MathML using the XSLT.
  47. * (Different for browser and node environments.)
  48. */
  49. protected transform: (node: N, doc: MathDocument<N, T, D>) => N;
  50. /**
  51. * @param {MathDocument} document The MathDocument for the transformation
  52. * @constructor
  53. */
  54. constructor(document: MathDocument<N, T, D>) {
  55. if (typeof XSLTProcessor === 'undefined') {
  56. //
  57. // For Node, get the trasnform from the external module
  58. //
  59. this.transform = createTransform();
  60. } else {
  61. //
  62. // For in-browser use, use the browser's XSLTProcessor
  63. //
  64. const processor = new XSLTProcessor();
  65. const parsed = document.adaptor.parse(Mml3.XSLT, 'text/xml') as any as Node;
  66. processor.importStylesheet(parsed);
  67. this.transform = (node: N) => {
  68. const adaptor = document.adaptor;
  69. const div = adaptor.node('div', {}, [adaptor.clone(node)]);
  70. const mml = processor.transformToDocument(div as any as Node) as any as N;
  71. return adaptor.tags(mml, 'math')[0];
  72. };
  73. }
  74. }
  75. /**
  76. * The mathml filter for the MathML input jax
  77. *
  78. * @param {FILTERDATA} args The data from the pre-filter chain.
  79. */
  80. public mmlFilter(args: FILTERDATA<N, T, D>) {
  81. if (args.document.options.enableMml3) {
  82. args.data = this.transform(args.data, args.document);
  83. }
  84. }
  85. }
  86. /**
  87. * Add Mml3 support into the handler.
  88. */
  89. export function Mml3Handler<N, T, D>(handler: Handler<N, T, D>): Handler<N, T, D> {
  90. handler.documentClass = class extends handler.documentClass {
  91. /**
  92. * @override
  93. */
  94. public static OPTIONS: OptionList = {
  95. ...handler.documentClass.OPTIONS,
  96. enableMml3: true,
  97. };
  98. /**
  99. * Add a prefilter to the MathML input jax, if there is one.
  100. *
  101. * @override
  102. * @constructor
  103. */
  104. constructor(...args: any[]) {
  105. super(...args);
  106. for (const jax of this.inputJax || []) {
  107. if (jax.name === 'MathML') {
  108. if (!jax.options._mml3) { // prevent filter being added twice (e.g., when a11y tools load)
  109. const mml3 = new Mml3(this);
  110. (jax as MathML<N, T, D>).mmlFilters.add(mml3.mmlFilter.bind(mml3));
  111. jax.options._mml3 = true;
  112. }
  113. break;
  114. }
  115. }
  116. }
  117. };
  118. return handler;
  119. }
  120. //
  121. // The actual XSLT transform
  122. //
  123. Mml3.XSLT = `
  124. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  125. xmlns:m="http://www.w3.org/1998/Math/MathML"
  126. xmlns:c="http://exslt.org/common"
  127. exclude-result-prefixes="m c">
  128. <xsl:output indent="yes" omit-xml-declaration="yes"/>
  129. <xsl:output indent="yes" omit-xml-declaration="yes"/>
  130. <xsl:template match="*">
  131. <xsl:copy>
  132. <xsl:copy-of select="@*"/>
  133. <xsl:apply-templates/>
  134. </xsl:copy>
  135. </xsl:template>
  136. <xsl:template match="m:*[@dir='rtl']" priority="10">
  137. <xsl:apply-templates mode="rtl" select="."/>
  138. </xsl:template>
  139. <xsl:template match="@*" mode="rtl">
  140. <xsl:copy-of select="."/>
  141. <xsl:attribute name="dir">ltr</xsl:attribute>
  142. </xsl:template>
  143. <xsl:template match="*" mode="rtl">
  144. <xsl:copy>
  145. <xsl:apply-templates select="@*" mode="rtl"/>
  146. <xsl:for-each select="node()">
  147. <xsl:sort data-type="number" order="descending" select="position()"/>
  148. <xsl:text> </xsl:text>
  149. <xsl:apply-templates mode="rtl" select="."/>
  150. </xsl:for-each>
  151. </xsl:copy>
  152. </xsl:template>
  153. <xsl:template match="@open" mode="rtl">
  154. <xsl:attribute name="close"><xsl:value-of select="."/></xsl:attribute>
  155. </xsl:template>
  156. <xsl:template match="@open[.='(']" mode="rtl">
  157. <xsl:attribute name="close">)</xsl:attribute>
  158. </xsl:template>
  159. <xsl:template match="@open[.=')']" mode="rtl">
  160. <xsl:attribute name="close">(</xsl:attribute>
  161. </xsl:template>
  162. <xsl:template match="@open[.='[']" mode="rtl">
  163. <xsl:attribute name="close">]</xsl:attribute>
  164. </xsl:template>
  165. <xsl:template match="@open[.=']']" mode="rtl">
  166. <xsl:attribute name="close">[</xsl:attribute>
  167. </xsl:template>
  168. <xsl:template match="@open[.='{']" mode="rtl">
  169. <xsl:attribute name="close">}</xsl:attribute>
  170. </xsl:template>
  171. <xsl:template match="@open[.='}']" mode="rtl">
  172. <xsl:attribute name="close">{</xsl:attribute>
  173. </xsl:template>
  174. <xsl:template match="@close" mode="rtl">
  175. <xsl:attribute name="open"><xsl:value-of select="."/></xsl:attribute>
  176. </xsl:template>
  177. <xsl:template match="@close[.='(']" mode="rtl">
  178. <xsl:attribute name="open">)</xsl:attribute>
  179. </xsl:template>
  180. <xsl:template match="@close[.=')']" mode="rtl">
  181. <xsl:attribute name="open">(</xsl:attribute>
  182. </xsl:template>
  183. <xsl:template match="@close[.='[']" mode="rtl">
  184. <xsl:attribute name="open">]</xsl:attribute>
  185. </xsl:template>
  186. <xsl:template match="@close[.=']']" mode="rtl">
  187. <xsl:attribute name="open">[</xsl:attribute>
  188. </xsl:template>
  189. <xsl:template match="@close[.='{']" mode="rtl">
  190. <xsl:attribute name="open">}</xsl:attribute>
  191. </xsl:template>
  192. <xsl:template match="@close[.='}']" mode="rtl">
  193. <xsl:attribute name="open">{</xsl:attribute>
  194. </xsl:template>
  195. <xsl:template match="m:mfrac[@bevelled='true']" mode="rtl">
  196. <m:mrow>
  197. <m:msub><m:mi></m:mi><xsl:apply-templates select="*[2]" mode="rtl"/></m:msub>
  198. <m:mo>&#x5c;</m:mo>
  199. <m:msup><m:mi></m:mi><xsl:apply-templates select="*[1]" mode="rtl"/></m:msup>
  200. </m:mrow>
  201. </xsl:template>
  202. <xsl:template match="m:mfrac" mode="rtl">
  203. <xsl:copy>
  204. <xsl:apply-templates mode="rtl" select="@*|*"/>
  205. </xsl:copy>
  206. </xsl:template>
  207. <xsl:template match="m:mroot" mode="rtl">
  208. <m:msup>
  209. <m:menclose notation="top right">
  210. <xsl:apply-templates mode="rtl" select="@*|*[1]"/>
  211. </m:menclose>
  212. <xsl:apply-templates mode="rtl" select="*[2]"/>
  213. </m:msup>
  214. </xsl:template>
  215. <xsl:template match="m:msqrt" mode="rtl">
  216. <m:menclose notation="top right">
  217. <xsl:apply-templates mode="rtl" select="@*|*[1]"/>
  218. </m:menclose>
  219. </xsl:template>
  220. <xsl:template match="m:mtable|m:munder|m:mover|m:munderover" mode="rtl" priority="2">
  221. <xsl:copy>
  222. <xsl:apply-templates select="@*" mode="rtl"/>
  223. <xsl:apply-templates mode="rtl">
  224. </xsl:apply-templates>
  225. </xsl:copy>
  226. </xsl:template>
  227. <xsl:template match="m:msup" mode="rtl" priority="2">
  228. <m:mmultiscripts>
  229. <xsl:apply-templates select="*[1]" mode="rtl"/>
  230. <m:mprescripts/>
  231. <m:none/>
  232. <xsl:apply-templates select="*[2]" mode="rtl"/>
  233. </m:mmultiscripts>
  234. </xsl:template>
  235. <xsl:template match="m:msub" mode="rtl" priority="2">
  236. <m:mmultiscripts>
  237. <xsl:apply-templates select="*[1]" mode="rtl"/>
  238. <m:mprescripts/>
  239. <xsl:apply-templates select="*[2]" mode="rtl"/>
  240. <m:none/>
  241. </m:mmultiscripts>
  242. </xsl:template>
  243. <xsl:template match="m:msubsup" mode="rtl" priority="2">
  244. <m:mmultiscripts>
  245. <xsl:apply-templates select="*[1]" mode="rtl"/>
  246. <m:mprescripts/>
  247. <xsl:apply-templates select="*[2]" mode="rtl"/>
  248. <xsl:apply-templates select="*[3]" mode="rtl"/>
  249. </m:mmultiscripts>
  250. </xsl:template>
  251. <xsl:template match="m:mmultiscripts" mode="rtl" priority="2">
  252. <m:mmultiscripts>
  253. <xsl:apply-templates select="*[1]" mode="rtl"/>
  254. <xsl:for-each select="m:mprescripts/following-sibling::*[position() mod 2 = 1]">
  255. <xsl:sort data-type="number" order="descending" select="position()"/>
  256. <xsl:apply-templates select="." mode="rtl"/>
  257. <xsl:apply-templates select="following-sibling::*[1]" mode="rtl"/>
  258. </xsl:for-each>
  259. <m:mprescripts/>
  260. <xsl:for-each select="m:mprescripts/preceding-sibling::*[position()!=last()][position() mod 2 = 0]">
  261. <xsl:sort data-type="number" order="descending" select="position()"/>
  262. <xsl:apply-templates select="." mode="rtl"/>
  263. <xsl:apply-templates select="following-sibling::*[1]" mode="rtl"/>
  264. </xsl:for-each>
  265. </m:mmultiscripts>
  266. </xsl:template>
  267. <xsl:template match="m:mmultiscripts[not(m:mprescripts)]" mode="rtl" priority="3">
  268. <m:mmultiscripts>
  269. <xsl:apply-templates select="*[1]" mode="rtl"/>
  270. <m:mprescripts/>
  271. <xsl:for-each select="*[position() mod 2 = 0]">
  272. <xsl:sort data-type="number" order="descending" select="position()"/>
  273. <xsl:apply-templates select="." mode="rtl"/>
  274. <xsl:apply-templates select="following-sibling::*[1]" mode="rtl"/>
  275. </xsl:for-each>
  276. </m:mmultiscripts>
  277. </xsl:template>
  278. <xsl:template match="text()[.='(']" mode="rtl">)</xsl:template>
  279. <xsl:template match="text()[.=')']" mode="rtl">(</xsl:template>
  280. <xsl:template match="text()[.='{']" mode="rtl">}</xsl:template>
  281. <xsl:template match="text()[.='}']" mode="rtl">{</xsl:template>
  282. <xsl:template match="text()[.='&lt;']" mode="rtl">&gt;</xsl:template>
  283. <xsl:template match="text()[.='&gt;']" mode="rtl">&lt;</xsl:template>
  284. <xsl:template match="text()[.='&#x2208;']" mode="rtl">&#x220b;</xsl:template>
  285. <xsl:template match="text()[.='&#x220b;']" mode="rtl">&#x2208;</xsl:template>
  286. <xsl:template match="@notation[.='radical']" mode="rtl">
  287. <xsl:attribute name="notation">top right</xsl:attribute>
  288. </xsl:template>
  289. <xsl:template match="m:mlongdiv|m:mstack" mode="rtl">
  290. <m:mrow dir="ltr">
  291. <xsl:apply-templates select="."/>
  292. </m:mrow>
  293. </xsl:template>
  294. <xsl:template match="m:mstack" priority="11">
  295. <xsl:variable name="m">
  296. <m:mtable columnspacing="0em" rowspacing="0em">
  297. <xsl:copy-of select="@align"/>
  298. <xsl:variable name="t">
  299. <xsl:apply-templates select="*" mode="mstack1">
  300. <xsl:with-param name="p" select="0"/>
  301. </xsl:apply-templates>
  302. </xsl:variable>
  303. <xsl:variable name="maxl">
  304. <xsl:for-each select="c:node-set($t)/*/@l">
  305. <xsl:sort data-type="number" order="descending"/>
  306. <xsl:if test="position()=1">
  307. <xsl:value-of select="."/>
  308. </xsl:if>
  309. </xsl:for-each>
  310. </xsl:variable>
  311. <xsl:for-each select="c:node-set($t)/*[not(@class='mscarries') or following-sibling::*[1]/@class='mscarries']">
  312. <xsl:variable name="c" select="preceding-sibling::*[1][@class='mscarries']"/>
  313. <xsl:text>&#10;</xsl:text>
  314. <m:mtr>
  315. <xsl:copy-of select="@class[.='msline']"/>
  316. <xsl:variable name="offset" select="$maxl - @l"/>
  317. <xsl:choose>
  318. <xsl:when test="@class='msline' and @l='*'">
  319. <xsl:variable name="msl" select="*[1]"/>
  320. <xsl:for-each select="(//node())[position()&lt;=$maxl]">
  321. <xsl:copy-of select="$msl"/>
  322. </xsl:for-each>
  323. </xsl:when>
  324. <xsl:when test="$c">
  325. <xsl:variable name="ldiff" select="$c/@l - @l"/>
  326. <xsl:variable name="loffset" select="$maxl - $c/@l"/>
  327. <xsl:for-each select="(//*)[position()&lt;= $offset]">
  328. <xsl:variable name="pn" select="position()"/>
  329. <xsl:variable name="cy" select="$c/*[position()=$pn - $loffset]"/>
  330. <m:mtd>
  331. <xsl:if test="$cy/*">
  332. <m:mover><m:mphantom><m:mn>0</m:mn></m:mphantom><m:mpadded width="0em" lspace="-0.5width">
  333. <xsl:copy-of select="$cy/*"/></m:mpadded></m:mover>
  334. </xsl:if>
  335. </m:mtd>
  336. </xsl:for-each>
  337. <xsl:for-each select="*">
  338. <xsl:variable name="pn" select="position()"/>
  339. <xsl:variable name="cy" select="$c/*[position()=$pn + $ldiff]"/>
  340. <xsl:copy>
  341. <xsl:copy-of select="@*"/>
  342. <xsl:variable name="b">
  343. <xsl:choose>
  344. <xsl:when test="not(string($cy/@crossout) or $cy/@crossout='none')"><xsl:copy-of select="*"/></xsl:when>
  345. <xsl:otherwise>
  346. <m:menclose notation="{$cy/@crossout}"><xsl:copy-of select="*"/></m:menclose>
  347. </xsl:otherwise>
  348. </xsl:choose>
  349. </xsl:variable>
  350. <xsl:choose>
  351. <xsl:when test="$cy/m:none or not($cy/*)"><xsl:copy-of select="$b"/></xsl:when>
  352. <xsl:when test="not(string($cy/@location)) or $cy/@location='n'">
  353. <m:mover>
  354. <xsl:copy-of select="$b"/><m:mpadded width="0em" lspace="-0.5width">
  355. <xsl:copy-of select="$cy/*"/>
  356. </m:mpadded>
  357. </m:mover>
  358. </xsl:when>
  359. <xsl:when test="$cy/@location='nw'">
  360. <m:mmultiscripts><xsl:copy-of select="$b"/><m:mprescripts/><m:none/><m:mpadded lspace="-1width" width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:mmultiscripts>
  361. </xsl:when>
  362. <xsl:when test="$cy/@location='s'">
  363. <m:munder><xsl:copy-of select="$b"/><m:mpadded width="0em" lspace="-0.5width"><xsl:copy-of select="$cy/*"/></m:mpadded></m:munder>
  364. </xsl:when>
  365. <xsl:when test="$cy/@location='sw'">
  366. <m:mmultiscripts><xsl:copy-of select="$b"/><m:mprescripts/><m:mpadded lspace="-1width" width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded><m:none/></m:mmultiscripts>
  367. </xsl:when>
  368. <xsl:when test="$cy/@location='ne'">
  369. <m:msup><xsl:copy-of select="$b"/><m:mpadded width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:msup>
  370. </xsl:when>
  371. <xsl:when test="$cy/@location='se'">
  372. <m:msub><xsl:copy-of select="$b"/><m:mpadded width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:msub>
  373. </xsl:when>
  374. <xsl:when test="$cy/@location='w'">
  375. <m:msup><m:mrow/><m:mpadded lspace="-1width" width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:msup>
  376. <xsl:copy-of select="$b"/>
  377. </xsl:when>
  378. <xsl:when test="$cy/@location='e'">
  379. <xsl:copy-of select="$b"/>
  380. <m:msup><m:mrow/><m:mpadded width="0em"><xsl:copy-of select="$cy/*"/></m:mpadded></m:msup>
  381. </xsl:when>
  382. <xsl:otherwise>
  383. <xsl:copy-of select="$b"/>
  384. </xsl:otherwise>
  385. </xsl:choose>
  386. </xsl:copy>
  387. </xsl:for-each>
  388. </xsl:when>
  389. <xsl:otherwise>
  390. <xsl:for-each select="(//*)[position()&lt;= $offset]"><m:mtd/></xsl:for-each>
  391. <xsl:copy-of select="*"/>
  392. </xsl:otherwise>
  393. </xsl:choose>
  394. </m:mtr>
  395. </xsl:for-each>
  396. </m:mtable>
  397. </xsl:variable>
  398. <xsl:apply-templates mode="ml" select="c:node-set($m)"/>
  399. </xsl:template>
  400. <xsl:template match="m:none" mode="ml">
  401. <m:mrow/>
  402. </xsl:template>
  403. <xsl:template match="*" mode="ml">
  404. <xsl:copy>
  405. <xsl:copy-of select="@*"/>
  406. <xsl:apply-templates mode="ml"/>
  407. </xsl:copy>
  408. </xsl:template>
  409. <xsl:template mode="ml" match="m:mtr[following-sibling::*[1][@class='msline']]">
  410. <m:mtr>
  411. <xsl:copy-of select="@*"/>
  412. <xsl:variable name="m" select="following-sibling::*[1]/m:mtd"/>
  413. <xsl:for-each select="m:mtd">
  414. <xsl:variable name="p" select="position()"/>
  415. <m:mtd>
  416. <xsl:copy-of select="@*"/>
  417. <xsl:choose>
  418. <xsl:when test="$m[$p]/m:mpadded">
  419. <m:mpadded depth="+.2em">
  420. <m:menclose notation="bottom">
  421. <m:mpadded depth=".1em" height=".8em" width=".8em">
  422. <m:mspace width=".15em"/>
  423. <xsl:copy-of select="*"/>
  424. </m:mpadded>
  425. </m:menclose>
  426. </m:mpadded>
  427. </xsl:when>
  428. <xsl:otherwise>
  429. <xsl:copy-of select="*"/>
  430. </xsl:otherwise>
  431. </xsl:choose>
  432. </m:mtd>
  433. </xsl:for-each>
  434. </m:mtr>
  435. </xsl:template>
  436. <xsl:template mode="ml" match="m:mtr[not(preceding-sibling::*)][@class='msline']" priority="3">
  437. <m:mtr>
  438. <xsl:copy-of select="@*"/>
  439. <xsl:for-each select="m:mtd">
  440. <m:mtd>
  441. <xsl:copy-of select="@*"/>
  442. <xsl:if test="m:mpadded">
  443. <m:menclose notation="bottom">
  444. <m:mpadded depth=".1em" height="1em" width=".5em">
  445. <m:mspace width=".2em"/>
  446. </m:mpadded>
  447. </m:menclose>
  448. </xsl:if>
  449. </m:mtd>
  450. </xsl:for-each>
  451. </m:mtr>
  452. </xsl:template>
  453. <xsl:template mode="ml" match="m:mtr[@class='msline']" priority="2"/>
  454. <xsl:template mode="mstack1" match="*">
  455. <xsl:param name="p"/>
  456. <xsl:param name="maxl" select="0"/>
  457. <m:mtr l="{1 + $p}">
  458. <xsl:if test="ancestor::mstack[1]/@stackalign='left'">
  459. <xsl:attribute name="l"><xsl:value-of select="$p"/></xsl:attribute>
  460. </xsl:if>
  461. <m:mtd><xsl:apply-templates select="."/></m:mtd>
  462. </m:mtr>
  463. </xsl:template>
  464. <xsl:template mode="mstack1" match="m:msrow">
  465. <xsl:param name="p"/>
  466. <xsl:param name="maxl" select="0"/>
  467. <xsl:variable name="align1" select="ancestor::m:mstack[1]/@stackalign"/>
  468. <xsl:variable name="align">
  469. <xsl:choose>
  470. <xsl:when test="string($align1)=''">decimalpoint</xsl:when>
  471. <xsl:otherwise><xsl:value-of select="$align1"/></xsl:otherwise>
  472. </xsl:choose>
  473. </xsl:variable>
  474. <xsl:variable name="row">
  475. <xsl:apply-templates mode="mstack1" select="*">
  476. <xsl:with-param name="p" select="0"/>
  477. </xsl:apply-templates>
  478. </xsl:variable>
  479. <xsl:text>&#10;</xsl:text>
  480. <xsl:variable name="l1">
  481. <xsl:choose>
  482. <xsl:when test="$align='decimalpoint' and m:mn">
  483. <xsl:for-each select="c:node-set($row)/m:mtr[m:mtd/m:mn][1]">
  484. <xsl:value-of select="number(sum(@l))+count(preceding-sibling::*/@l)"/>
  485. </xsl:for-each>
  486. </xsl:when>
  487. <xsl:when test="$align='right' or $align='decimalpoint'">
  488. <xsl:value-of select="count(c:node-set($row)/m:mtr/m:mtd)"/>
  489. </xsl:when>
  490. <xsl:otherwise>
  491. <xsl:value-of select="0"/>
  492. </xsl:otherwise>
  493. </xsl:choose>
  494. </xsl:variable>
  495. <m:mtr class="msrow" l="{number($l1) + number(sum(@position)) +$p}">
  496. <xsl:copy-of select="c:node-set($row)/m:mtr/*"/>
  497. </m:mtr>
  498. </xsl:template>
  499. <xsl:template mode="mstack1" match="m:mn">
  500. <xsl:param name="p"/>
  501. <xsl:variable name="align1" select="ancestor::m:mstack[1]/@stackalign"/>
  502. <xsl:variable name="dp1" select="ancestor::*[@decimalpoint][1]/@decimalpoint"/>
  503. <xsl:variable name="align">
  504. <xsl:choose>
  505. <xsl:when test="string($align1)=''">decimalpoint</xsl:when>
  506. <xsl:otherwise><xsl:value-of select="$align1"/></xsl:otherwise>
  507. </xsl:choose>
  508. </xsl:variable>
  509. <xsl:variable name="dp">
  510. <xsl:choose>
  511. <xsl:when test="string($dp1)=''">.</xsl:when>
  512. <xsl:otherwise><xsl:value-of select="$dp1"/></xsl:otherwise>
  513. </xsl:choose>
  514. </xsl:variable>
  515. <m:mtr l="$p">
  516. <xsl:variable name="mn" select="normalize-space(.)"/>
  517. <xsl:variable name="len" select="string-length($mn)"/>
  518. <xsl:choose>
  519. <xsl:when test="$align='right' or ($align='decimalpoint' and not(contains($mn,$dp)))">
  520. <xsl:attribute name="l"><xsl:value-of select="$p + $len"/></xsl:attribute>
  521. </xsl:when>
  522. <xsl:when test="$align='center'">
  523. <xsl:attribute name="l"><xsl:value-of select="round(($p + $len) div 2)"/></xsl:attribute>
  524. </xsl:when>
  525. <xsl:when test="$align='decimalpoint'">
  526. <xsl:attribute name="l"><xsl:value-of select="$p + string-length(substring-before($mn,$dp))"/></xsl:attribute>
  527. </xsl:when>
  528. </xsl:choose>
  529. <xsl:for-each select="(//node())[position() &lt;=$len]">
  530. <xsl:variable name="pos" select="position()"/>
  531. <xsl:variable name="digit" select="substring($mn,$pos,1)"/>
  532. <m:mtd>
  533. <xsl:if test="$digit='.' or $digit=','">
  534. <m:mspace width=".15em"/>
  535. </xsl:if>
  536. <m:mn><xsl:value-of select="$digit"/></m:mn>
  537. </m:mtd>
  538. </xsl:for-each>
  539. </m:mtr>
  540. </xsl:template>
  541. <xsl:template match="m:msgroup" mode="mstack1">
  542. <xsl:param name="p"/>
  543. <xsl:variable name="s" select="number(sum(@shift))"/>
  544. <xsl:variable name="thisp" select="number(sum(@position))"/>
  545. <xsl:for-each select="*">
  546. <xsl:apply-templates mode="mstack1" select=".">
  547. <xsl:with-param name="p" select="number($p)+$thisp+(position()-1)*$s"/>
  548. </xsl:apply-templates>
  549. </xsl:for-each>
  550. </xsl:template>
  551. <xsl:template match="m:msline" mode="mstack1">
  552. <xsl:param name="p"/>
  553. <xsl:variable name="align1" select="ancestor::m:mstack[1]/@stackalign"/>
  554. <xsl:variable name="align">
  555. <xsl:choose>
  556. <xsl:when test="string($align1)=''">decimalpoint</xsl:when>
  557. <xsl:otherwise><xsl:value-of select="$align1"/></xsl:otherwise>
  558. </xsl:choose>
  559. </xsl:variable>
  560. <m:mtr class="msline">
  561. <xsl:attribute name="l">
  562. <xsl:choose>
  563. <xsl:when test="not(string(@length)) or @length=0">*</xsl:when>
  564. <xsl:when test="string($align)='right' or string($align)='decimalpoint' "><xsl:value-of select="$p+ @length"/></xsl:when>
  565. <xsl:otherwise><xsl:value-of select="$p"/></xsl:otherwise>
  566. </xsl:choose>
  567. </xsl:attribute>
  568. <xsl:variable name="w">
  569. <xsl:choose>
  570. <xsl:when test="@mslinethickness='thin'">0.1em</xsl:when>
  571. <xsl:when test="@mslinethickness='medium'">0.15em</xsl:when>
  572. <xsl:when test="@mslinethickness='thick'">0.2em</xsl:when>
  573. <xsl:when test="@mslinethickness"><xsl:value-of select="@mslinethickness"/></xsl:when>
  574. <xsl:otherwise>0.15em</xsl:otherwise>
  575. </xsl:choose>
  576. </xsl:variable>
  577. <xsl:choose>
  578. <xsl:when test="not(string(@length)) or @length=0">
  579. <m:mtd class="mslinemax">
  580. <m:mpadded lspace="-0.2em" width="0em" height="0em">
  581. <m:mfrac linethickness="{$w}">
  582. <m:mspace width=".5em"/>
  583. <m:mrow/>
  584. </m:mfrac>
  585. </m:mpadded>
  586. </m:mtd>
  587. </xsl:when>
  588. <xsl:otherwise>
  589. <xsl:variable name="l" select="@length"/>
  590. <xsl:for-each select="(//node())[position()&lt;=$l]">
  591. <m:mtd class="msline">
  592. <m:mpadded lspace="-0.2em" width="0em" height="0em">
  593. <m:mfrac linethickness="{$w}">
  594. <m:mspace width=".5em"/>
  595. <m:mrow/>
  596. </m:mfrac>
  597. </m:mpadded>
  598. </m:mtd>
  599. </xsl:for-each>
  600. </xsl:otherwise>
  601. </xsl:choose>
  602. </m:mtr>
  603. </xsl:template>
  604. <xsl:template match="m:mscarries" mode="mstack1">
  605. <xsl:param name="p"/>
  606. <xsl:variable name="align1" select="ancestor::m:mstack[1]/@stackalign"/>
  607. <xsl:variable name="l1">
  608. <xsl:choose>
  609. <xsl:when test="string($align1)='left'">0</xsl:when>
  610. <xsl:otherwise><xsl:value-of select="count(*)"/></xsl:otherwise>
  611. </xsl:choose>
  612. </xsl:variable>
  613. <m:mtr class="mscarries" l="{$p + $l1 + sum(@position)}">
  614. <xsl:apply-templates select="*" mode="msc"/>
  615. </m:mtr>
  616. </xsl:template>
  617. <xsl:template match="*" mode="msc">
  618. <m:mtd>
  619. <xsl:copy-of select="../@location|../@crossout"/>
  620. <xsl:choose>
  621. <xsl:when test="../@scriptsizemultiplier">
  622. <m:mstyle mathsize="{round(../@scriptsizemultiplier div .007)}%">
  623. <xsl:apply-templates select="."/>
  624. </m:mstyle>
  625. </xsl:when>
  626. <xsl:otherwise>
  627. <xsl:apply-templates select="."/>
  628. </xsl:otherwise>
  629. </xsl:choose>
  630. </m:mtd>
  631. </xsl:template>
  632. <xsl:template match="m:mscarry" mode="msc">
  633. <m:mtd>
  634. <xsl:copy-of select="@location|@crossout"/>
  635. <xsl:choose>
  636. <xsl:when test="../@scriptsizemultiplier">
  637. <m:mstyle mathsize="{round(../@scriptsizemultiplier div .007)}%">
  638. <xsl:apply-templates/>
  639. </m:mstyle>
  640. </xsl:when>
  641. <xsl:otherwise>
  642. <xsl:apply-templates/>
  643. </xsl:otherwise>
  644. </xsl:choose>
  645. </m:mtd>
  646. </xsl:template>
  647. <xsl:template match="m:mlongdiv" priority="11">
  648. <xsl:variable name="ms">
  649. <m:mstack>
  650. <xsl:copy-of select="(ancestor-or-self::*/@decimalpoint)[last()]"/>
  651. <xsl:choose>
  652. <xsl:when test="@longdivstyle='left)(right'">
  653. <m:msrow>
  654. <m:mrow><xsl:copy-of select="*[1]"/></m:mrow>
  655. <m:mo>)</m:mo>
  656. <xsl:copy-of select="*[3]"/>
  657. <m:mo>(</m:mo>
  658. <xsl:copy-of select="*[2]"/>
  659. </m:msrow>
  660. </xsl:when>
  661. <xsl:when test="@longdivstyle='left/\right'">
  662. <m:msrow>
  663. <m:mrow><xsl:copy-of select="*[1]"/></m:mrow>
  664. <m:mo>/</m:mo>
  665. <xsl:copy-of select="*[3]"/>
  666. <m:mo>\</m:mo>
  667. <xsl:copy-of select="*[2]"/>
  668. </m:msrow>
  669. </xsl:when>
  670. <xsl:when test="@longdivstyle=':right=right'">
  671. <m:msrow>
  672. <xsl:copy-of select="*[3]"/>
  673. <m:mo>:</m:mo>
  674. <xsl:copy-of select="*[1]"/>
  675. <m:mo>=</m:mo>
  676. <xsl:copy-of select="*[2]"/>
  677. </m:msrow>
  678. </xsl:when>
  679. <xsl:when test="@longdivstyle='stackedrightright'
  680. or @longdivstyle='mediumstackedrightright'
  681. or @longdivstyle='shortstackedrightright'
  682. or @longdivstyle='stackedleftleft'
  683. ">
  684. <xsl:attribute name="align">top</xsl:attribute>
  685. <xsl:copy-of select="*[3]"/>
  686. </xsl:when>
  687. <xsl:when test="@longdivstyle='stackedleftlinetop'">
  688. <xsl:copy-of select="*[2]"/>
  689. <m:msline length="{string-length(*[3])}"/>
  690. <m:msrow>
  691. <m:mrow>
  692. <m:menclose notation="bottom right">
  693. <xsl:copy-of select="*[1]"/>
  694. </m:menclose>
  695. </m:mrow>
  696. <xsl:copy-of select="*[3]"/>
  697. </m:msrow>
  698. </xsl:when>
  699. <xsl:when test="@longdivstyle='righttop'">
  700. <xsl:copy-of select="*[2]"/>
  701. <m:msline length="{string-length(*[3])}"/>
  702. <m:msrow>
  703. <xsl:copy-of select="*[3]"/>
  704. <m:menclose notation="top left bottom">
  705. <xsl:copy-of select="*[1]"/></m:menclose>
  706. </m:msrow>
  707. </xsl:when>
  708. <xsl:otherwise>
  709. <xsl:copy-of select="*[2]"/>
  710. <m:msline length="{string-length(*[3])+1}"/>
  711. <m:msrow>
  712. <m:mrow><xsl:copy-of select="*[1]"/><m:mspace width=".2em"/></m:mrow>
  713. <m:mpadded voffset=".1em" lspace="-.15em" depth="-.2em" height="-.2em">
  714. <m:mo minsize="1.2em">)</m:mo>
  715. </m:mpadded>
  716. <xsl:copy-of select="*[3]"/>
  717. </m:msrow>
  718. </xsl:otherwise>
  719. </xsl:choose>
  720. <xsl:copy-of select="*[position()&gt;3]"/>
  721. </m:mstack>
  722. </xsl:variable>
  723. <xsl:choose>
  724. <xsl:when test="@longdivstyle='stackedrightright'">
  725. <m:menclose notation="right">
  726. <xsl:apply-templates select="c:node-set($ms)"/>
  727. </m:menclose>
  728. <m:mtable align="top">
  729. <m:mtr>
  730. <m:menclose notation="bottom">
  731. <xsl:copy-of select="*[1]"/>
  732. </m:menclose>
  733. </m:mtr>
  734. <m:mtr>
  735. <mtd><xsl:copy-of select="*[2]"/></mtd>
  736. </m:mtr>
  737. </m:mtable>
  738. </xsl:when>
  739. <xsl:when test="@longdivstyle='mediumstackedrightright'">
  740. <xsl:apply-templates select="c:node-set($ms)"/>
  741. <m:menclose notation="left">
  742. <m:mtable align="top">
  743. <m:mtr>
  744. <m:menclose notation="bottom">
  745. <xsl:copy-of select="*[1]"/>
  746. </m:menclose>
  747. </m:mtr>
  748. <m:mtr>
  749. <mtd><xsl:copy-of select="*[2]"/></mtd>
  750. </m:mtr>
  751. </m:mtable>
  752. </m:menclose>
  753. </xsl:when>
  754. <xsl:when test="@longdivstyle='shortstackedrightright'">
  755. <xsl:apply-templates select="c:node-set($ms)"/>
  756. <m:mtable align="top">
  757. <m:mtr>
  758. <m:menclose notation="left bottom">
  759. <xsl:copy-of select="*[1]"/>
  760. </m:menclose>
  761. </m:mtr>
  762. <m:mtr>
  763. <mtd><xsl:copy-of select="*[2]"/></mtd>
  764. </m:mtr>
  765. </m:mtable>
  766. </xsl:when>
  767. <xsl:when test="@longdivstyle='stackedleftleft'">
  768. <m:mtable align="top">
  769. <m:mtr>
  770. <m:menclose notation="bottom">
  771. <xsl:copy-of select="*[1]"/>
  772. </m:menclose>
  773. </m:mtr>
  774. <m:mtr>
  775. <mtd><xsl:copy-of select="*[2]"/></mtd>
  776. </m:mtr>
  777. </m:mtable>
  778. <m:menclose notation="left">
  779. <xsl:apply-templates select="c:node-set($ms)"/>
  780. </m:menclose>
  781. </xsl:when>
  782. <xsl:otherwise>
  783. <xsl:apply-templates select="c:node-set($ms)"/>
  784. </xsl:otherwise>
  785. </xsl:choose>
  786. </xsl:template>
  787. <xsl:template match="m:menclose[@notation='madruwb']" mode="rtl">
  788. <m:menclose notation="bottom right">
  789. <xsl:apply-templates mode="rtl"/>
  790. </m:menclose>
  791. </xsl:template>
  792. </xsl:stylesheet>
  793. `;