Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
4.42% |
35 / 791 |
|
0.00% |
0 / 47 |
CRAP | |
0.00% |
0 / 1 |
BaseParsing | |
4.42% |
35 / 791 |
|
0.00% |
0 / 47 |
57920.66 | |
0.00% |
0 / 1 |
accent | |
85.00% |
17 / 20 |
|
0.00% |
0 / 1 |
5.08 | |||
array | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
156 | |||
alignAt | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
42 | |||
amsEqnArray | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
20 | |||
boldsymbol | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
cancel | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
cancelTo | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
chemCustom | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
customLetters | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
cFrac | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
2 | |||
crLaTeX | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
dots | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
genFrac | |
0.00% |
0 / 51 |
|
0.00% |
0 / 1 |
210 | |||
frac | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
30 | |||
hline | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
hskip | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
42 | |||
handleOperatorName | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
lap | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
20 | |||
macro | |
0.00% |
0 / 110 |
|
0.00% |
0 / 1 |
462 | |||
matrix | |
0.00% |
0 / 52 |
|
0.00% |
0 / 1 |
306 | |||
namedOp | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
30 | |||
over | |
0.00% |
0 / 26 |
|
0.00% |
0 / 1 |
72 | |||
oint | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
72 | |||
overset | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
phantom | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 | |||
raiseLower | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
56 | |||
underset | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 | |||
underOver | |
94.74% |
18 / 19 |
|
0.00% |
0 / 1 |
6.01 | |||
mathFont | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
30 | |||
mathChoice | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
132 | |||
makeBig | |
0.00% |
0 / 33 |
|
0.00% |
0 / 1 |
182 | |||
machine | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
namedFn | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
30 | |||
limits | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
90 | |||
setFont | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
sideset | |
0.00% |
0 / 32 |
|
0.00% |
0 / 1 |
30 | |||
spacer | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
smash | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
72 | |||
texAtom | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
42 | |||
intent | |
0.00% |
0 / 31 |
|
0.00% |
0 / 1 |
240 | |||
hBox | |
0.00% |
0 / 37 |
|
0.00% |
0 / 1 |
240 | |||
setStyle | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
not | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
vbox | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 | |||
sqrt | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
12 | |||
tilde | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
xArrow | |
0.00% |
0 / 31 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | namespace MediaWiki\Extension\Math\WikiTexVC\MMLmappings; |
3 | |
4 | use IntlChar; |
5 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\Misc; |
6 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\Sizes; |
7 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\Tag; |
8 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\TexClass; |
9 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\Variants; |
10 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util\MMLParsingUtil; |
11 | use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util\MMLutil; |
12 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmenclose; |
13 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmerror; |
14 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmfrac; |
15 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmi; |
16 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmmultiscripts; |
17 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmo; |
18 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmover; |
19 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmpadded; |
20 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmphantom; |
21 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmroot; |
22 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmrow; |
23 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmspace; |
24 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmsqrt; |
25 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmstyle; |
26 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmsub; |
27 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmsup; |
28 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmtable; |
29 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmtd; |
30 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmtext; |
31 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmtr; |
32 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmunder; |
33 | use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmunderover; |
34 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\Curly; |
35 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\DQ; |
36 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\FQ; |
37 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun1; |
38 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun1nb; |
39 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun2; |
40 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun2sq; |
41 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\Fun4; |
42 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\Literal; |
43 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\Matrix; |
44 | use MediaWiki\Extension\Math\WikiTexVC\Nodes\TexNode; |
45 | use MediaWiki\Extension\Math\WikiTexVC\TexVC; |
46 | |
47 | /** |
48 | * Parsing functions for specific recognized mappings. |
49 | * Usually the parsing functions are invoked from the BaseMethods classes. |
50 | */ |
51 | class BaseParsing { |
52 | |
53 | public static function accent( $node, $passedArgs, $name, $operatorContent, $accent, $stretchy = null ) { |
54 | // Currently this is own implementation from Fun1.php |
55 | // TODO The first if-clause is mathjax specific (and not necessary by generic parsers) |
56 | // and will most probably removed (just for running all tc atm) |
57 | if ( $accent == "00B4" || $accent == "0060" ) { |
58 | $attrs = [ Tag::SCRIPTTAG => "true" ]; |
59 | } else { |
60 | if ( $stretchy == null ) { |
61 | // $attrs = [ "stretchy" => "false" ]; // not mention explicit stretchy |
62 | $attrs = []; |
63 | } else { |
64 | $attrs = [ "stretchy" => "true" ]; |
65 | } |
66 | } |
67 | // Fetching entity from $accent key tbd |
68 | $entity = MMLutil::createEntity( $accent ); |
69 | if ( !$entity ) { |
70 | $entity = $accent; |
71 | } |
72 | |
73 | $mrow = new MMLmrow(); |
74 | $mo = new MMLmo( "", $attrs ); // $passedArgs |
75 | $mover = new MMLmover(); |
76 | $ret = $mrow->encapsulateRaw( |
77 | $mrow->encapsulateRaw( |
78 | $mover->encapsulateRaw( |
79 | $node->getArg()->renderMML( $passedArgs ) . |
80 | $mo->encapsulateRaw( $entity ) |
81 | ) |
82 | ) |
83 | ); |
84 | return $ret; |
85 | } |
86 | |
87 | public static function array( $node, $passedArgs, $operatorContent, $name, $begin = null, $open = null, |
88 | $close = null, $align = null, $spacing = null, |
89 | $vspacing = null, $style = null, $raggedHeight = null ) { |
90 | $output = ""; |
91 | $mrow = new MMLmrow(); |
92 | if ( $open != null ) { |
93 | $resDelimiter = BaseMappings::getDelimiterByKey( trim( $open ) ); |
94 | if ( $resDelimiter ) { |
95 | // $retDelim = $bm->checkAndParseDelimiter($open, $node,$passedArgs,true); |
96 | $moOpen = new MMLmo( TexClass::OPEN ); |
97 | $output .= $moOpen->encapsulateRaw( $resDelimiter[0] ); |
98 | } |
99 | } |
100 | if ( $name == "Bmatrix" || $name == "bmatrix" || $name == "Vmatrix" |
101 | || $name == "vmatrix" || $name == "smallmatrix" || $name == "pmatrix" || $name == "matrix" ) { |
102 | // This is a workaround and might be improved mapping BMatrix to Matrix directly instead of array |
103 | return self::matrix( $node, $passedArgs, $operatorContent, $name, |
104 | $open, $close, null, null, null, null, true ); |
105 | |
106 | } else { |
107 | $output .= $mrow->encapsulateRaw( $node->getMainarg()->renderMML() ); |
108 | } |
109 | |
110 | if ( $close != null ) { |
111 | $resDelimiter = BaseMappings::getDelimiterByKey( trim( $close ) ); |
112 | if ( $resDelimiter ) { |
113 | // $retDelim = $bm->checkAndParseDelimiter($open, $node,$passedArgs,true); |
114 | $moClose = new MMLmo( TexClass::CLOSE ); |
115 | $output .= $moClose->encapsulateRaw( $resDelimiter[0] ); |
116 | } |
117 | } |
118 | return $output; |
119 | } |
120 | |
121 | public static function alignAt( $node, $passedArgs, $operatorContent, $name, $smth, $smth2 = null ) { |
122 | // Parsing is very similar to AmsEQArray, maybe extract function ... tcs: 178 |
123 | $mrow = new MMLmrow(); |
124 | // tbd how are the table args composed ? |
125 | $tableArgs = [ "columnalign" => "right", |
126 | "columnspacing" => "0em", "displaystyle" => "true", "rowspacing" => "3pt" ]; |
127 | $mtable = new MMLmtable( "", $tableArgs ); |
128 | $mtr = new MMLmtr(); |
129 | $mtd = new MMLmtd(); |
130 | $renderedInner = ""; |
131 | |
132 | $tableElements = array_slice( $node->getArgs(), 1 )[0]; |
133 | $discarded = false; |
134 | foreach ( $tableElements->getArgs() as $tableRow ) { |
135 | $renderedInner .= $mtr->getStart(); |
136 | foreach ( $tableRow->getArgs() as $tableCell ) { |
137 | $renderedInner .= $mtd->getStart(); |
138 | foreach ( $tableCell->getArgs() as $cellItem ) { |
139 | if ( !$discarded && $cellItem instanceof Curly ) { |
140 | $discarded = true; |
141 | // Just discard the number of rows atm, it is in the first Curly |
142 | } else { |
143 | $renderedInner .= $cellItem->renderMML(); // pass args here ? |
144 | } |
145 | } |
146 | |
147 | $renderedInner .= $mtd->getEnd(); |
148 | |
149 | } |
150 | $renderedInner .= $mtr->getEnd(); |
151 | } |
152 | return $mrow->encapsulateRaw( $mtable->encapsulateRaw( $renderedInner ) ); |
153 | } |
154 | |
155 | public static function amsEqnArray( $node, $passedArgs, $operatorContent, $name, $smth, $smth2 = null ) { |
156 | // this goes for name =="aligned" ... tcs: 358 420 421 |
157 | $mrow = new MMLmrow(); |
158 | // tbd how are the table args composed ? |
159 | |
160 | $direction = ( $name == "aligned" ) ? "left" : "right"; |
161 | $tableArgs = [ "columnalign" => $direction, |
162 | "columnspacing" => "0em", "displaystyle" => "true", "rowspacing" => "3pt" ]; |
163 | $mtable = new MMLmtable( "", $tableArgs ); |
164 | $mtr = new MMLmtr(); |
165 | $mtd = new MMLmtd(); |
166 | $renderedInner = ""; |
167 | $tableElements = array_slice( $node->getArgs(), 1 )[0]; |
168 | foreach ( $tableElements->getArgs() as $tableRow ) { |
169 | $renderedInner .= $mtr->getStart(); |
170 | foreach ( $tableRow->getArgs() as $tableCell ) { |
171 | $renderedInner .= $mtd->encapsulateRaw( $tableCell->renderMML() ); // pass args here ? |
172 | } |
173 | $renderedInner .= $mtr->getEnd(); |
174 | } |
175 | return $mrow->encapsulateRaw( $mtable->encapsulateRaw( $renderedInner ) ); |
176 | } |
177 | |
178 | public static function boldsymbol( $node, $passedArgs, $operatorContent, $name, $smth = null, $smth2 = null ) { |
179 | $mrow = new MMLmrow(); |
180 | $passedArgs = array_merge( [ "mathvariant" => Variants::BOLDITALIC ] ); |
181 | return $mrow->encapsulateRaw( $node->getArg()->renderMML( $passedArgs ) ); |
182 | } |
183 | |
184 | public static function cancel( $node, $passedArgs, $operatorContent, $name, $notation = null, $smth2 = null ) { |
185 | $mrow = new MMLmrow(); |
186 | $menclose = new MMLmenclose( "", [ "notation" => $notation ] ); |
187 | return $mrow->encapsulateRaw( $menclose->encapsulateRaw( $node->getArg()->renderMML() ) ); |
188 | } |
189 | |
190 | public static function cancelTo( $node, $passedArgs, $operatorContent, $name, $notation = null ) { |
191 | $mrow = new MMLmrow(); |
192 | $msup = new MMLmsup(); |
193 | $mpAdded = new MMLmpadded( "", [ "depth" => "-.1em", "height" => "+.1em", "voffset" => ".1em" ] ); |
194 | |
195 | $menclose = new MMLmenclose( "", [ "notation" => $notation ] ); |
196 | $inner = $menclose->encapsulateRaw( |
197 | $node->getArg2()->renderMML() ) . $mpAdded->encapsulateRaw( $node->getArg1()->renderMML() ); |
198 | return $mrow->encapsulateRaw( $msup->encapsulateRaw( $inner ) ); |
199 | } |
200 | |
201 | public static function chemCustom( $node, $passedArgs, $operatorContent, $name, $translation = null ) { |
202 | if ( $translation ) { |
203 | return $translation; |
204 | } |
205 | return "tbd chemCustom"; |
206 | } |
207 | |
208 | public static function customLetters( $node, $passedArgs, $operatorContent, $name, $char, $isOperator = false ) { |
209 | $mrow = new MMLmrow(); |
210 | |
211 | if ( $isOperator ) { |
212 | $mo = new MMLmo(); |
213 | return $mrow->encapsulateRaw( $mo->encapsulateRaw( $char ) ); |
214 | } |
215 | |
216 | $mi = new MMLmi( "", [ "mathvariant" => "normal" ] ); |
217 | return $mrow->encapsulateRaw( $mi->encapsulateRaw( $char ) ); |
218 | } |
219 | |
220 | public static function cFrac( $node, $passedArgs, $operatorContent, $name ) { |
221 | $mrow = new MMLmrow(); |
222 | $mfrac = new MMLmfrac(); |
223 | $mstyle = new MMLmstyle( "", [ "displaystyle" => "false", "scriptlevel" => "0" ] ); |
224 | $mpAdded = new MMLmpadded( "", [ "depth" => "3pt", "height" => "8.6pt", "width" => "0" ] ); |
225 | // See TexUtilMMLTest testcase 81 |
226 | // (mml3 might be erronous here, but this element seems to be rendered correctly) |
227 | $whatIsThis = $mrow->getStart() . $mpAdded->getStart() . $mpAdded->getEnd() . $mrow->getEnd(); |
228 | $inner = $mrow->encapsulateRaw( $whatIsThis . |
229 | $mstyle->encapsulateRaw( $mrow->encapsulateRaw( $node->getArg1()->renderMML() ) ) ) . |
230 | $mrow->encapsulateRaw( $whatIsThis . $mstyle->encapsulateRaw( |
231 | $mrow->encapsulateRaw( $node->getArg2()->renderMML() ) ) ); |
232 | |
233 | return $mrow->encapsulateRaw( $mfrac->encapsulateRaw( $inner ) ); |
234 | } |
235 | |
236 | public static function crLaTeX( $node, $passedArgs, $operatorContent, $name ) { |
237 | $mspace = new MMLmspace( "", [ "linebreak" => "newline" ] ); |
238 | return $mspace->getEmpty(); |
239 | } |
240 | |
241 | public static function dots( $node, $passedArgs, $operatorContent, $name, $smth = null, $smth2 = null ) { |
242 | // lowerdots || centerdots seems aesthetical, just using lowerdots atm s |
243 | $mo = new MMLmo( "", $passedArgs ); |
244 | return $mo->encapsulateRaw( "…" ); |
245 | } |
246 | |
247 | public static function genFrac( $node, $passedArgs, $operatorContent, $name, |
248 | $left = null, $right = null, $thick = null, $style = null ) { |
249 | // Actually this is in AMSMethods, consider refactoring left, right, thick, style |
250 | $bm = new BaseMethods(); |
251 | $ret = $bm->checkAndParseDelimiter( $name, $node, $passedArgs, $operatorContent, true ); |
252 | if ( $ret ) { |
253 | // TBD |
254 | if ( $left == null ) { |
255 | $left = $ret; |
256 | } |
257 | if ( $right == null ) { |
258 | $right = $ret; |
259 | } |
260 | if ( $thick == null ) { |
261 | $thick = $ret; |
262 | } |
263 | if ( $style == null ) { |
264 | $style = trim( $ret ); |
265 | } |
266 | } |
267 | $attrs = []; |
268 | $fract = null; |
269 | $styleAttr = []; |
270 | $displayStyle = "false"; |
271 | if ( in_array( $thick, [ 'thin', 'medium', 'thick', '0' ], true ) ) { |
272 | $attrs = array_merge( $attrs, [ "linethickness" => $thick ] ); |
273 | } |
274 | if ( $style !== '' ) { |
275 | $styleDigit = intval( $style, 10 ); |
276 | $styleAlpha = [ 'D', 'T', 'S', 'SS' ][$styleDigit]; |
277 | if ( $styleAlpha == null ) { |
278 | $mrow = new MMLmrow(); |
279 | return $mrow->encapsulateRaw( "Bad math style" ); |
280 | } |
281 | |
282 | if ( $styleAlpha === 'D' ) { |
283 | // NodeUtil_js_1.default.setProperties(frac, { displaystyle: true, scriptlevel: 0 }); |
284 | |
285 | // tbd add props |
286 | $displayStyle = "true"; |
287 | $styleAttr = [ "minsize" => "2.047em" ]; |
288 | |
289 | } else { |
290 | $styleAttr = [ "minsize" => "1.2em" ]; |
291 | } |
292 | |
293 | /* @phan-suppress-next-line SecurityCheck-DoubleEscaped */ |
294 | $frac = new MMLmfrac( '', $attrs ); |
295 | } else { |
296 | // NodeUtil_js_1.default.setProperties(frac, { displaystyle: false, |
297 | // scriptlevel: styleDigit - 1 }); |
298 | // tbd add props |
299 | /* @phan-suppress-next-line SecurityCheck-DoubleEscaped */ |
300 | $frac = new MMLmfrac( '', $attrs ); |
301 | $styleAttr = [ "maxsize" => "1.2em", "minsize" => "1.2em" ]; |
302 | |
303 | } |
304 | $mrow = new MMLmrow(); |
305 | $mstyle = new MMLmstyle( "", [ "displaystyle" => $displayStyle, "scriptlevel" => "0" ] ); |
306 | $output = $mrow->getStart(); |
307 | if ( $style !== '' ) { |
308 | $output .= $mstyle->getStart(); |
309 | } |
310 | $output .= $mrow->getStart(); |
311 | if ( $left ) { |
312 | $mrowOpen = new MMLmrow( TexClass::OPEN ); |
313 | $moL = new MMLmo( "", $styleAttr ); |
314 | $output .= $mrowOpen->encapsulateRaw( $moL->encapsulateRaw( $left ) ); |
315 | } |
316 | $output .= $frac->encapsulateRaw( $mrow->encapsulateRaw( $node->getArg1()->renderMML() ) . |
317 | $mrow->encapsulateRaw( $node->getArg2()->renderMML() ) ); |
318 | if ( $right ) { |
319 | $mrowClose = new MMLmrow( TexClass::CLOSE ); |
320 | $moR = new MMLmo( "", $styleAttr ); |
321 | $output .= $mrowClose->encapsulateRaw( $moR->encapsulateRaw( $right ) ); |
322 | |
323 | } |
324 | $output .= $mrow->getEnd(); |
325 | if ( $style !== '' ) { |
326 | $output .= $mstyle->getEnd(); |
327 | } |
328 | $output .= $mrow->getEnd(); |
329 | |
330 | return $output; |
331 | } |
332 | |
333 | public static function frac( $node, $passedArgs, $operatorContent, $name ) { |
334 | $mrow = new MMLmrow(); |
335 | $mfrac = new MMLmfrac(); |
336 | if ( $node instanceof Fun2 ) { |
337 | $inner = $mrow->encapsulateRaw( $node->getArg1()->renderMML() ) . |
338 | $mrow->encapsulateRaw( $node->getArg2()->renderMML() ); |
339 | } elseif ( $node instanceof DQ ) { |
340 | $inner = $mrow->encapsulateRaw( $node->getBase()->renderMML() ) . |
341 | $mrow->encapsulateRaw( $node->getDown()->renderMML() ); |
342 | } else { |
343 | $inner = ""; |
344 | foreach ( $node->getArgs() as $arg ) { |
345 | $rendered = is_string( $arg ) ? $arg : $arg->renderMML(); |
346 | $inner .= $mrow->encapsulateRaw( $rendered ); |
347 | } |
348 | } |
349 | return $mrow->encapsulateRaw( $mfrac->encapsulateRaw( $inner ) ); |
350 | } |
351 | |
352 | public static function hline( $node, $passedArgs, $operatorContent, $name, |
353 | $smth1 = null, $smth2 = null, $smth3 = null, $smth4 = null ) { |
354 | // HLine is most probably not parsed this way, since only parsed in Matrix context |
355 | $mmlRow = new MMLmrow( "tbd" ); |
356 | return $mmlRow->encapsulateRaw( "HLINE TBD" ); |
357 | } |
358 | |
359 | public static function hskip( $node, $passedArgs, $operatorContent, $name ) { |
360 | if ( $node->getArg() instanceof Curly ) { |
361 | $unit = MMLutil::squashLitsToUnit( $node->getArg() ); |
362 | if ( !$unit ) { |
363 | return null; |
364 | } |
365 | $em = MMLutil::dimen2em( $unit ); |
366 | } else { |
367 | // Prevent parsing in unmapped cases |
368 | return null; |
369 | } |
370 | // Added kern j4t |
371 | if ( $name == "mskip" || $name == "mkern" || "kern" ) { |
372 | $args = [ "width" => $em ]; |
373 | } else { |
374 | return null; |
375 | } |
376 | |
377 | $mspace = new MMLmspace( "", $args ); |
378 | return $mspace->encapsulateRaw( "" ); |
379 | } |
380 | |
381 | public static function handleOperatorName( $node, $passedArgs, $operatorContent, $name ) { |
382 | // In example "\\operatorname{a}" |
383 | $mmlNot = ""; |
384 | if ( isset( $operatorContent['not'] ) && $operatorContent['not'] == true ) { |
385 | $mmlNot = MMLParsingUtil::createNot(); |
386 | } |
387 | $passedArgs = array_merge( $passedArgs, [ Tag::CLASSTAG => TexClass::OP, "mathvariant" => Variants::NORMAL ] ); |
388 | return $mmlNot . $node->getArg()->renderMML( $passedArgs ); |
389 | } |
390 | |
391 | public static function lap( $node, $passedArgs, $operatorContent, $name ) { |
392 | if ( !$node instanceof Fun1 ) { |
393 | return null; |
394 | } |
395 | if ( $name == "rlap" ) { |
396 | $args = [ "width" => "0" ]; |
397 | } elseif ( $name == "llap" ) { |
398 | $args = [ "width" => "0", "lspace" => "-1width" ]; |
399 | } else { |
400 | return null; |
401 | } |
402 | $mrow = new MMLmrow(); |
403 | $mpAdded = new MMLmpadded( "", $args ); |
404 | return $mrow->encapsulateRaw( $mpAdded->encapsulateRaw( $node->getArg()->renderMML() ) ); |
405 | } |
406 | |
407 | public static function macro( $node, $passedArgs, $operatorContent, $name, $macro, $argcount = null, $def = null ) { |
408 | // Parse the Macro |
409 | switch ( $name ) { |
410 | case "mod": |
411 | $mmlRow = new MMLmrow(); |
412 | $mo = new MMLmo( "", [ "lspace" => "2.5pt", "rspace" => "2.5pt" ] ); |
413 | $inner = $node->getArg() instanceof TexNode ? $node->getArg()->renderMML() : ""; |
414 | return $mmlRow->encapsulateRaw( $mo->encapsulate( "mod" ) . $inner ); |
415 | case "pmod": |
416 | // tbd indicate in mapping that this is composed within php |
417 | $mmlRow = new MMLmrow(); |
418 | $mspace = new MMLmspace( "", [ "width" => "0.444em" ] ); |
419 | $mspace2 = new MMLmspace( "", [ "width" => "0.333em" ] ); |
420 | $mo = new MMLmo( "", [ "stretchy" => "false" ] ); |
421 | $mi = new MMLmi(); |
422 | $inner = $node->getArg() instanceof TexNode ? $node->getArg()->renderMML() : ""; |
423 | |
424 | return $mmlRow->encapsulateRaw( $mspace->encapsulate() . |
425 | $mo->encapsulate( "(" ) . $mi->encapsulate( "mod" ) . |
426 | $mspace2->encapsulate() . $inner . $mo->encapsulate( ")" ) ); |
427 | case "varlimsup": |
428 | case "varliminf": |
429 | // hardcoded macro in php (there is also a dynamic mapping which is not completely resolved atm) |
430 | $mmlRow = new MMLmrow( TexClass::OP ); |
431 | if ( $name === "varlimsup" ) { |
432 | $movu = new MMLmover(); |
433 | |
434 | } else { |
435 | $movu = new MMLmunder(); |
436 | } |
437 | $mmlMi = new MMLmi(); |
438 | $mo = new MMLmo( "", [ "accent" => "true" ] ); |
439 | return $mmlRow->encapsulateRaw( $movu->encapsulateRaw( |
440 | $mmlMi->encapsulateRaw( "lim" ) . $mo->encapsulateRaw( "―" ) ) ); |
441 | |
442 | case "varinjlim": |
443 | $mmlRow = new MMLmrow( TexClass::OP ); |
444 | $mmlMunder = new MMLmunder(); |
445 | $mi = new MMLmi(); |
446 | $mo = new MMLmo(); |
447 | return $mmlRow->encapsulateRaw( $mmlMunder->encapsulateRaw( |
448 | $mi->encapsulateRaw( "lim" ) . |
449 | $mo->encapsulateRaw( "→" ) ) |
450 | ); |
451 | case "varprojlim": |
452 | $mmlRow = new MMLmrow( TexClass::OP ); |
453 | $mmlMunder = new MMLmunder(); |
454 | $mi = new MMLmi(); |
455 | $mo = new MMLmo(); |
456 | return $mmlRow->encapsulateRaw( $mmlMunder->encapsulateRaw( |
457 | $mi->encapsulate( "lim" ) . |
458 | $mo->encapsulateRaw( "←" ) |
459 | ) ); |
460 | case "stackrel": |
461 | // hardcoded macro in php (there is also a dynamic mapping which is not not completely resolved atm) |
462 | $mmlRow = new MMLmrow(); |
463 | $mmlRowInner = new MMLmrow( TexClass::REL ); |
464 | $mover = new MMLmover(); |
465 | $mmlRowArg2 = new MMLmrow( TexClass::OP ); |
466 | if ( $node instanceof DQ ) { |
467 | $inner = $mover->encapsulateRaw( $mmlRowArg2->encapsulateRaw( |
468 | $node->getBase()->renderMML() ) . |
469 | $mmlRow->encapsulateRaw( $node->getDown()->renderMML() ) |
470 | ); |
471 | } else { |
472 | $inner = $mover->encapsulateRaw( $mmlRowArg2->encapsulateRaw( |
473 | $node->getArg2()->renderMML() ) . |
474 | $mmlRow->encapsulateRaw( $node->getArg1()->renderMML() ) |
475 | ); |
476 | } |
477 | return $mmlRow->encapsulateRaw( $mmlRowInner->encapsulateRaw( $inner ) ); |
478 | case "bmod": |
479 | $mo = new MMLmo( "", [ "lspace" => Sizes::THICKMATHSPACE, "rspace" => Sizes::THICKMATHSPACE ] ); |
480 | $mmlRow = new MMLmrow( TexClass::ORD ); |
481 | $mspace = new MMLmspace( "", [ "width" => "0.167em" ] ); |
482 | $inner = $node->getArg() instanceof TexNode ? |
483 | $mmlRow->encapsulateRaw( $node->getArg()->renderMML() ) : ""; |
484 | return $mmlRow->encapsulateRaw( $mo->encapsulate( "mod" ) . |
485 | $inner . $mmlRow->encapsulateRaw( $mspace->getEmpty() ) ); |
486 | case "implies": |
487 | $mstyle = new MMLmstyle( "", [ "scriptlevel" => "0" ] ); |
488 | $mspace = new MMLmspace( "", [ "width" => "0.278em" ] ); |
489 | $mo = new MMLmo(); |
490 | return $mstyle->encapsulateRaw( $mspace->getEmpty() ) . $mo->encapsulateRaw( "⟹" ) . |
491 | $mstyle->encapsulateRaw( $mspace->getEmpty() ); |
492 | case "iff": |
493 | $mstyle = new MMLmstyle( "", [ "scriptlevel" => "0" ] ); |
494 | $mspace = new MMLmspace( "", [ "width" => "0.278em" ] ); |
495 | $mo = new MMLmo(); |
496 | return $mstyle->encapsulateRaw( $mspace->getEmpty() ) . $mo->encapsulateRaw( "⟺" ) . |
497 | $mstyle->encapsulateRaw( $mspace->getEmpty() ); |
498 | case "tripledash": |
499 | // Using emdash for rendering here. |
500 | $mo = new MMLmo(); |
501 | return $mo->encapsulateRaw( "—" ); |
502 | case "longrightleftharpoons": |
503 | case "longLeftrightharpoons": |
504 | case "longRightleftharpoons": |
505 | $texvc = new TexVC(); |
506 | $warnings = []; |
507 | $checkRes = $texvc->check( $macro, [ "usemhchem" => true, "usemhchemtexified" => true ], |
508 | $warnings, true ); |
509 | return $checkRes["input"]->renderMML(); |
510 | case "longleftrightarrows": |
511 | // The tex-cmds used in makro are not supported, just use a hardcoded mml macro here. |
512 | $mtext = new MMLmtext(); |
513 | $mrowRel = new MMLmrow( TexClass::REL ); |
514 | $mrowOrd = new MMLmrow( TexClass::ORD ); |
515 | $mrowOp = new MMLmrow( TexClass::OP ); |
516 | $mover = new MMLmover(); |
517 | $mpadded = new MMLmpadded( "", [ "height" => "0", "depth" => "0" ] ); |
518 | $mo = new MMLmo( "", [ "stretchy" => "false" ] ); |
519 | $mspace = new MMLmspace( "", [ "width" => "0px", "height" => ".25em", |
520 | "depth" => "0px", "mathbackground" => "black" ] ); |
521 | return $mtext->encapsulateRaw( " " ) . |
522 | $mrowRel->encapsulateRaw( $mover->encapsulateRaw( |
523 | $mrowOp->encapsulateRaw( |
524 | $mrowOrd->encapsulateRaw( $mpadded->encapsulateRaw( |
525 | $mo->encapsulateRaw( "⟵" ) ) ) . |
526 | $mspace->getEmpty() ) . |
527 | $mrowOrd->encapsulateRaw( |
528 | $mo->encapsulateRaw( "⟶" ) |
529 | ) ) ); |
530 | } |
531 | |
532 | // Removed all token based parsing, since macro resolution for the supported macros can be hardcoded in php |
533 | $mmlMrow = new MMLmrow(); |
534 | return $mmlMrow->encapsulate( "macro not resolved: " . $macro ); |
535 | } |
536 | |
537 | public static function matrix( $node, $passedArgs, $operatorContent, |
538 | $name, $open = null, $close = null, $align = null, $spacing = null, |
539 | $vspacing = null, $style = null, $cases = null, $numbered = null ) { |
540 | $resInner = ""; |
541 | $mtr = new MMLmtr(); |
542 | $mtd = new MMLmtd(); |
543 | $addHlines = false; |
544 | $columnInfo = []; |
545 | // tbd hline element is the first literal element within second texarray -> resolve |
546 | foreach ( $node->getMainarg()->getArgs() as $mainarg ) { |
547 | $resInner .= $mtr->getStart(); |
548 | foreach ( $mainarg->getArgs() as $arg ) { |
549 | $usedArg = clone $arg; |
550 | if ( count( $arg->getArgs() ) >= 1 && $arg->getArgs()[0] instanceof Literal ) { |
551 | // Discarding the column information Curly at the moment |
552 | if ( $arg->getArgs()[0]->getArg() == "\\hline " ) { |
553 | // discarding the hline |
554 | // $usedArg->args[0] = null; // this does no work tbd |
555 | $usedArg->pop(); |
556 | $addHlines = true; |
557 | } |
558 | } |
559 | if ( count( $arg->getArgs() ) >= 1 && $arg->getArgs()[0] instanceof Curly ) { |
560 | // Discarding the column information Curly at the moment |
561 | // $usedArg->getArgs()[0] = null; |
562 | $columnInfo = $usedArg->getArgs()[0]->render(); |
563 | $usedArg->pop(); |
564 | |
565 | } |
566 | $resInner .= $mtd->encapsulateRaw( $usedArg->renderMML( $passedArgs, [ 'inMatrix' |
567 | => true ] |
568 | ) ); |
569 | } |
570 | $resInner .= $mtr->getEnd(); |
571 | } |
572 | $mrow = new MMLmrow(); |
573 | $tableArgs = [ "columnspacing" => "1em", "rowspacing" => "4pt" ]; |
574 | $mencloseArgs = null; |
575 | if ( $addHlines ) { |
576 | // TBD this is just simple check, create a parsing function for hlines when there are more cases |
577 | // solid as first val: hline for header row |
578 | // none as second val: no hlines for follow up rows |
579 | $tableArgs = array_merge( $tableArgs, [ "rowlines" => "solid none" ] ); |
580 | } |
581 | if ( $columnInfo ) { |
582 | // TBD this is just simple check, create a parsing function for hlines when there are more cases |
583 | if ( str_contains( $columnInfo, "|" ) ) { |
584 | $mencloseArgs = [ "data-padding" => "0", "notation" => "left right" ]; |
585 | // it seems this is creted when left and right is solely coming from columninfo |
586 | $tableArgs = array_merge( $tableArgs, [ "columnlines" => "solid" ] ); |
587 | } |
588 | } |
589 | $mtable = new MMLmtable( "", $tableArgs ); |
590 | if ( $cases || ( $open != null && $close != null ) ) { |
591 | $bm = new BaseMethods(); |
592 | $mmlMoOpen = $bm->checkAndParseDelimiter( $open, $node, [], [], |
593 | true, TexClass::OPEN ); |
594 | if ( $mmlMoOpen == null ) { |
595 | $open = MMLutil::inputPreparation( $open ); |
596 | $mmlMoOpen = new MMLmo( TexClass::OPEN, [] ); |
597 | $mmlMoOpen = $mmlMoOpen->encapsulateRaw( $open ); |
598 | } |
599 | |
600 | $closeAtts = [ "fence" => "true", "stretchy" => "true", "symmetric" => "true" ]; |
601 | $mmlMoClose = $bm->checkAndParseDelimiter( $close, $node, $closeAtts, |
602 | null, true, TexClass::CLOSE ); |
603 | if ( $mmlMoOpen == null ) { |
604 | $close = MMLutil::inputPreparation( $close ); |
605 | $mmlMoClose = new MMLmo( TexClass::CLOSE, $closeAtts ); |
606 | $mmlMoClose = $mmlMoClose->encapsulateRaw( $close ); |
607 | } |
608 | $resInner = $mmlMoOpen . $mtable->encapsulateRaw( $resInner ) . $mmlMoClose; |
609 | } else { |
610 | $resInner = $mtable->encapsulateRaw( $resInner ); |
611 | } |
612 | if ( $mencloseArgs ) { |
613 | $menclose = new MMLmenclose( "", $mencloseArgs ); |
614 | $matrix = $mrow->encapsulateRaw( $menclose->encapsulateRaw( $resInner ) ); |
615 | |
616 | } else { |
617 | $matrix = $mrow->encapsulateRaw( $resInner ); |
618 | } |
619 | return $matrix; |
620 | } |
621 | |
622 | public static function namedOp( $node, $passedArgs, $operatorContent, $name, $id = null ) { |
623 | /* Determine wether the named function should have an added apply function. The operatorContent is defined |
624 | as state in parsing of TexArray */ |
625 | $applyFct = ""; |
626 | if ( array_key_exists( "foundNamedFct", $operatorContent ) ) { |
627 | $hasNamedFct = $operatorContent['foundNamedFct'][0]; |
628 | $hasValidParameters = $operatorContent["foundNamedFct"][1]; |
629 | if ( $hasNamedFct && $hasValidParameters ) { |
630 | $applyFct = MMLParsingUtil::renderApplyFunction(); |
631 | } |
632 | } |
633 | |
634 | if ( $node instanceof Literal ) { |
635 | $mi = new MMLmi( "", $passedArgs ); |
636 | return $mi->encapsulateRaw( $id ?? $name ) . $applyFct; |
637 | } |
638 | $mrow = new MMLmrow( TexClass::ORD, [] ); |
639 | $msub = new MMLmsub( "", $passedArgs ); |
640 | return $msub->encapsulateRaw( $node->getBase()->renderMML() . |
641 | $applyFct . |
642 | $mrow->encapsulateRaw( $node->getDown()->renderMML() ) ); |
643 | } |
644 | |
645 | public static function over( $node, $passedArgs, $operatorContent, $name, $id = null ) { |
646 | $attributes = []; |
647 | $start = ""; |
648 | $tail = ""; |
649 | if ( $name === "atop" ) { |
650 | $attributes = [ "linethickness" => "0" ]; |
651 | } elseif ( $name == "choose" ) { |
652 | $mrowAll = new MMLmrow( TexClass::ORD ); |
653 | $mrowOpen = new MMLmrow( TexClass::OPEN ); |
654 | $mrowClose = new MMLmrow( TexClass::CLOSE ); |
655 | $mo = new MMLmo( "", [ "maxsize" => "1.2em", "minsize" => "1.2em" ] ); |
656 | $start = $mrowAll->getStart() . $mrowOpen->encapsulateRaw( $mo->encapsulate( "(" ) ); |
657 | $tail = $mrowClose->encapsulateRaw( $mo->encapsulate( ")" ) ) . $mrowAll->getEnd(); |
658 | $attributes = [ "linethickness" => "0" ]; |
659 | |
660 | } |
661 | $mfrac = new MMLmfrac( "", $attributes ); |
662 | |
663 | $mrow = new MMLmrow( "", [] ); |
664 | if ( $node instanceof Fun2 ) { |
665 | return $start . $mfrac->encapsulateRaw( $mrow->encapsulateRaw( |
666 | $node->getArg1()->renderMML() ) . $mrow->encapsulateRaw( $node->getArg2()->renderMML() ) ) |
667 | . $tail; |
668 | } |
669 | $inner = ""; |
670 | foreach ( $node->getArgs() as $arg ) { |
671 | if ( is_string( $arg ) && str_contains( $arg, $name ) ) { |
672 | continue; |
673 | } |
674 | $rendered = $arg instanceof TexNode ? $arg->renderMML() : $arg; |
675 | $inner .= $mrow->encapsulateRaw( $rendered ); |
676 | } |
677 | |
678 | return $start . $mfrac->encapsulateRaw( $inner ) . $tail; |
679 | } |
680 | |
681 | public static function oint( $node, $passedArgs, $operatorContent, |
682 | $name, $uc = null, $attributes = null, $smth2 = null ) { |
683 | // This is a custom mapping not in js. |
684 | $mmlText = new MMLmtext( "", $attributes ); |
685 | $mrow = new MMLmrow(); |
686 | switch ( $name ) { |
687 | case "oint": |
688 | $mStyle = new MMLmstyle( "", [ "displaystyle" => "true" ] ); |
689 | $mo = new MMLmo(); |
690 | return $mStyle->encapsulateRaw( $mo->encapsulateRaw( MMLutil::uc2xNotation( $uc ) ) ); |
691 | case "\\P": |
692 | $mo = new MMLmo(); |
693 | return $mo->encapsulateRaw( MMLutil::uc2xNotation( $uc ) ); |
694 | case "oiint": |
695 | case "oiiint": |
696 | case "ointctrclockwise": |
697 | case "varointclockwise": |
698 | $mStyle = new MMLmstyle( "", [ "mathsize" => "2.07em" ] ); |
699 | $mSpace = new MMLmspace( "", [ "width" => Sizes::THINMATHSPACE ] ); |
700 | return $mrow->encapsulateRaw( $mStyle->encapsulateRaw( |
701 | $mmlText->encapsulateRaw( MMLutil::uc2xNotation( $uc ) ) |
702 | . $mSpace->getEmpty() ) ); |
703 | default: |
704 | return $mmlText->encapsulate( "not found in OintMethod" ); |
705 | |
706 | } |
707 | } |
708 | |
709 | public static function overset( $node, $passedArgs, $operatorContent, $name, $id = null ) { |
710 | $mrow = new MMLmrow( TexClass::ORD, [] ); // tbd remove mathjax specifics |
711 | $mrow2 = new MMLmrow( "", [] ); |
712 | $mover = new MMLmover(); |
713 | |
714 | if ( $node instanceof DQ ) { |
715 | return $mrow->encapsulateRaw( $mover->encapsulateRaw( $mrow2->encapsulateRaw( |
716 | $node->getDown()->renderMML() . $node->getDown()->renderMML() ) ) ); |
717 | } else { |
718 | $inrow = $mrow2->encapsulateRaw( $node->getArg2()->renderMML() ); |
719 | } |
720 | return $mrow->encapsulateRaw( $mover->encapsulateRaw( $inrow . $node->getArg1()->renderMML() ) ); |
721 | } |
722 | |
723 | public static function phantom( $node, $passedArgs, $operatorContent, |
724 | $name, $vertical = null, $horizontal = null, $smh3 = null ) { |
725 | $mrow = new MMLmrow( TexClass::ORD, [] ); |
726 | |
727 | $attrs = []; |
728 | if ( $vertical ) { |
729 | $attrs = array_merge( $attrs, [ "width" => "0" ] ); |
730 | } |
731 | if ( $horizontal ) { |
732 | $attrs = array_merge( $attrs, [ "depth" => "0", "height" => "0" ] ); |
733 | } |
734 | $mpadded = new MMLmpadded( "", $attrs ); |
735 | $mphantom = new MMLmphantom(); |
736 | return $mrow->encapsulateRaw( $mrow->encapsulateRaw( |
737 | $mpadded->encapsulateRaw( $mphantom->encapsulateRaw( $node->getArg()->renderMML() ) ) ) ); |
738 | } |
739 | |
740 | public static function raiseLower( $node, $passedArgs, $operatorContent, $name ) { |
741 | if ( !$node instanceof Fun2 ) { |
742 | return null; |
743 | } |
744 | |
745 | $arg1 = $node->getArg1(); |
746 | if ( $arg1 instanceof Curly ) { |
747 | $unit = MMLutil::squashLitsToUnit( $arg1 ); |
748 | if ( !$unit ) { |
749 | return null; |
750 | } |
751 | $em = MMLutil::dimen2em( $unit ); |
752 | if ( !$em ) { |
753 | return null; |
754 | } |
755 | } else { |
756 | return null; |
757 | } |
758 | |
759 | if ( $name == "raise" ) { |
760 | $args = [ "height" => MMLutil::addPreOperator( $em, "+" ), |
761 | "depth" => MMLutil::addPreOperator( $em, "-" ), |
762 | "voffset" => MMLutil::addPreOperator( $em, "+" ) ]; |
763 | } elseif ( $name == "lower" ) { |
764 | $args = [ "height" => MMLutil::addPreOperator( $em, "-" ), |
765 | "depth" => MMLutil::addPreOperator( $em, "+" ), |
766 | "voffset" => MMLutil::addPreOperator( $em, "-" ) ]; |
767 | } else { |
768 | // incorrect name, should not happen, prevent erroneous mappings from getting rendered. |
769 | return null; |
770 | } |
771 | $mrow = new MMLmrow(); |
772 | $mpAdded = new MMLmpadded( "", $args ); |
773 | return $mrow->encapsulateRaw( $mpAdded->encapsulateRaw( $node->getArg2()->renderMML() ) ); |
774 | } |
775 | |
776 | public static function underset( $node, $passedArgs, $operatorContent, $name, $smh = null ) { |
777 | $mrow = new MMLmrow( TexClass::ORD, [] ); |
778 | $inrow = $node->getArg2()->renderMML(); |
779 | $arg1 = $node->getArg1()->renderMML(); |
780 | if ( $inrow && $arg1 ) { |
781 | $munder = new MMLmunder(); |
782 | return $mrow->encapsulateRaw( $munder->encapsulateRaw( $inrow . $arg1 ) ); |
783 | } |
784 | |
785 | // If there are no two elements in munder, not render munder |
786 | return $mrow->encapsulateRaw( $inrow . $arg1 ); |
787 | } |
788 | |
789 | public static function underOver( $node, $passedArgs, $operatorContent, |
790 | $name, $operatorId = null, $stack = null, $nonHex = false ) { |
791 | // tbd verify if stack interpreted correctly ? |
792 | $texClass = $stack ? TexClass::OP : TexClass::ORD; // ORD or "" |
793 | |
794 | $mrow = new MMLmrow( $texClass ); |
795 | |
796 | if ( $name[0] === 'o' ) { |
797 | $movun = new MMLmover(); |
798 | } else { |
799 | $movun = new MMLmunder(); |
800 | } |
801 | |
802 | if ( $operatorId == 2015 ) { // eventually move such cases to mapping |
803 | $mo = new MMLmo( "", [ "accent" => "true" ] ); |
804 | } else { |
805 | $mo = new MMLmo(); |
806 | } |
807 | if ( $node instanceof DQ ) { |
808 | $mrowI = new MMLmrow(); |
809 | return $movun->encapsulateRaw( |
810 | $node->getBase()->renderMML( $passedArgs ) . |
811 | $mrowI->encapsulateRaw( $node->getDown()->renderMML( $passedArgs ) ) |
812 | ); |
813 | } |
814 | |
815 | $inner = $nonHex ? $operatorId : MMLutil::number2xNotation( $operatorId ); |
816 | return $mrow->encapsulateRaw( $movun->encapsulateRaw( |
817 | $node->getArg()->renderMML( $passedArgs ) . |
818 | $mo->encapsulateRaw( $inner ) |
819 | ) ); |
820 | } |
821 | |
822 | public static function mathFont( $node, $passedArgs, $operatorContent, $name, $mathvariant = null ) { |
823 | $mrow = new MMLmrow( TexClass::ORD, [] ); |
824 | $args = MMLParsingUtil::getFontArgs( $name, $mathvariant, $passedArgs ); |
825 | $state = []; |
826 | |
827 | // Unicode fixes for the operators |
828 | if ( $mathvariant == Variants::DOUBLESTRUCK ) { |
829 | $state = [ "double-struck-literals" => true ]; |
830 | } elseif ( $mathvariant == Variants::CALLIGRAPHIC ) { |
831 | $state = [ "calligraphic" => true ]; |
832 | } elseif ( $mathvariant == Variants::BOLDCALLIGRAPHIC ) { |
833 | $state = [ "bold-calligraphic" => true ]; |
834 | } |
835 | |
836 | if ( $node instanceof Fun1nb ) { |
837 | // Only one mrow from Fun1nb !? |
838 | return $mrow->encapsulateRaw( $node->getArg()->renderMML( $args, $state ) ); |
839 | } |
840 | return $mrow->encapsulateRaw( $mrow->encapsulateRaw( $node->getArg()->renderMML( $args, $state ) ) ); |
841 | } |
842 | |
843 | public static function mathChoice( $node, $passedArgs, $operatorContent, $name, $smth = null ) { |
844 | if ( !$node instanceof Fun4 ) { |
845 | $merror = new MMLmerror(); |
846 | return $merror->encapsulateRaw( "Wrong node type in mathChoice" ); |
847 | } |
848 | |
849 | /** |
850 | * Parametrization for mathchoice: |
851 | * \mathchoice |
852 | * {<material for display style>} |
853 | * {<material for text style>} |
854 | * {<material for script style>} |
855 | * {<material for scriptscript style>} |
856 | */ |
857 | |
858 | if ( isset( $operatorContent["styleargs"] ) ) { |
859 | $styleArgs = $operatorContent["styleargs"]; |
860 | $displayStyle = $styleArgs["displaystyle"] ?? "true"; |
861 | $scriptLevel = $styleArgs["scriptlevel"] ?? "0"; |
862 | |
863 | if ( $displayStyle == "true" && $scriptLevel == "0" ) { |
864 | // This is displaystyle |
865 | return $node->getArg1()->renderMML( $passedArgs, $operatorContent ); |
866 | } elseif ( $displayStyle == "false" && $scriptLevel == "0" ) { |
867 | // This is textstyle |
868 | return $node->getArg2()->renderMML( $passedArgs, $operatorContent ); |
869 | } elseif ( $displayStyle == "false" && $scriptLevel == "1" ) { |
870 | // This is scriptstyle |
871 | return $node->getArg3()->renderMML( $passedArgs, $operatorContent ); |
872 | } elseif ( $displayStyle == "false" && $scriptLevel == "2" ) { |
873 | // This is scriptscriptstyle |
874 | return $node->getArg4()->renderMML( $passedArgs, $operatorContent ); |
875 | } |
876 | } |
877 | // By default render displaystyle |
878 | return $node->getArg1()->renderMML( $passedArgs, $operatorContent ); |
879 | } |
880 | |
881 | public static function makeBig( $node, $passedArgs, $operatorContent, $name, $texClass = null, $size = null ) { |
882 | // Create the em format and shorten commas |
883 | $size *= Misc::P_HEIGHT; |
884 | $sizeShortened = MMLutil::size2em( strval( $size ) ); |
885 | $mrowOuter = new MMLmrow( TexClass::ORD, [] ); |
886 | $mrow = new MMLmrow( $texClass, [] ); |
887 | $passedArgs = array_merge( $passedArgs, [ "maxsize" => $sizeShortened, "minsize" => $sizeShortened ] ); |
888 | $mo = new MMLmo( "", $passedArgs ); |
889 | // Sieve arg if it is a delimiter (it seems args are not applied here |
890 | $bm = new BaseMethods(); |
891 | $argcurrent = trim( $node->getArg() ); |
892 | switch ( $argcurrent ) { |
893 | case "\\|": |
894 | $passedArgs = array_merge( $passedArgs, [ "symmetric" => "true" ] ); |
895 | break; |
896 | case "\\uparrow": |
897 | case "\\downarrow": |
898 | case "\\Uparrow": |
899 | case "\\Downarrow": |
900 | case "\\updownarrow": |
901 | case "\\Updownarrow": |
902 | $passedArgs = array_merge( [ "fence" => "true" ], $passedArgs, [ "symmetric" => "true" ] ); |
903 | break; |
904 | case "\\backslash": |
905 | case "/": |
906 | $passedArgs = array_merge( [ "fence" => "true" ], |
907 | $passedArgs, [ "stretchy" => "true", "symmetric" => "true" ] ); |
908 | break; |
909 | } |
910 | |
911 | if ( in_array( $name, [ "bigl", "Bigl", "biggl", "Biggl" ] ) ) { |
912 | $passedArgs = array_merge( $passedArgs, [ Tag::CLASSTAG => TexClass::OPEN ] ); |
913 | } |
914 | |
915 | if ( in_array( $name, [ "bigr", "Bigr", "biggr", "Biggr" ] ) ) { |
916 | $passedArgs = array_merge( $passedArgs, [ Tag::CLASSTAG => TexClass::CLOSE ] ); |
917 | } |
918 | |
919 | $ret = $bm->checkAndParseDelimiter( $node->getArg(), $node, $passedArgs, $operatorContent, true ); |
920 | if ( $ret ) { |
921 | return $ret; |
922 | } |
923 | |
924 | $argPrep = MMLutil::inputPreparation( $node->getArg() ); |
925 | return $mrowOuter->encapsulateRaw( $mrow->encapsulateRaw( $mo->encapsulateRaw( $argPrep ) ) ); |
926 | } |
927 | |
928 | public static function machine( $node, $passedArgs, $operatorContent, $name, $type = null ) { |
929 | // this could also be shifted to MhChem.php renderMML for ce |
930 | // For parsing chem (ce) or ??? (pu) |
931 | $mmlMrow = new MMLmrow(); |
932 | return $mmlMrow->encapsulateRaw( $node->getArg()->renderMML() ); |
933 | } |
934 | |
935 | public static function namedFn( $node, $passedArgs, $operatorContent, $name, $smth = null ) { |
936 | // Determine wether the named function should have an added apply function. The state is defined in |
937 | // parsing of TexArray |
938 | $applyFct = ""; |
939 | if ( array_key_exists( "foundNamedFct", $operatorContent ) ) { |
940 | $hasNamedFct = $operatorContent['foundNamedFct'][0]; |
941 | $hasValidParameters = $operatorContent["foundNamedFct"][1]; |
942 | if ( $hasNamedFct && $hasValidParameters ) { |
943 | $applyFct = MMLParsingUtil::renderApplyFunction(); |
944 | } |
945 | } |
946 | if ( $node instanceof Literal ) { |
947 | $mi = new MMLmi(); |
948 | return $mi->encapsulateRaw( $name ) . $applyFct; |
949 | } |
950 | $mrow = new MMLmrow( TexClass::ORD, [] ); // tbd remove mathjax specifics |
951 | $msub = new MMLmsub(); |
952 | return $msub->encapsulateRaw( $node->getBase()->renderMML() . |
953 | $applyFct . |
954 | $mrow->encapsulateRaw( $node->getDown()->renderMML() ) ); |
955 | } |
956 | |
957 | public static function limits( $node, $passedArgs, $operatorContent, $name, $smth = null ) { |
958 | $argsOp = [ "form" => "prefix" ]; |
959 | if ( $operatorContent != null && array_key_exists( "styleargs", $operatorContent ) ) { |
960 | if ( $operatorContent["styleargs"]["displaystyle"] === "false" ) { |
961 | $argsOp = [ "movablelimits" => "true" ]; |
962 | } |
963 | if ( $node->containsFunc( "\\nolimits" ) ) { |
964 | $argsOp = [ "movablelimits" => "false" ]; |
965 | } |
966 | } |
967 | $mrow = new MMLmrow( TexClass::ORD, [] ); |
968 | $opParsed = ( $operatorContent != null && $operatorContent["limits"] ) |
969 | ? $operatorContent["limits"]->renderMML( $argsOp ) : ""; |
970 | |
971 | if ( $node instanceof DQ ) { |
972 | $munder = new MMLmunder(); |
973 | return $munder->encapsulateRaw( $opParsed . $mrow->encapsulateRaw( $node->getDown()->renderMML() ) ); |
974 | } elseif ( $node instanceof FQ ) { |
975 | $munderOver = new MMLmunderover(); |
976 | return $munderOver->encapsulateRaw( $opParsed . $mrow->encapsulateRaw( $node->getDown()->renderMML() ) |
977 | . $mrow->encapsulateRaw( $node->getUp()->renderMML() ) ); |
978 | } |
979 | } |
980 | |
981 | public static function setFont( $node, $passedArgs, $operatorContent, $name, $variant = null ) { |
982 | $mrow = new MMLmrow(); |
983 | $args = MMLParsingUtil::getFontArgs( $name, $variant, $passedArgs ); |
984 | return $mrow->encapsulateRaw( $mrow->encapsulateRaw( $node->getArg()->renderMML( $args ) ) ); |
985 | } |
986 | |
987 | public static function sideset( $node, $passedArgs, $operatorContent, $name ) { |
988 | if ( !array_key_exists( "sideset", $operatorContent ) ) { |
989 | $merror = new MMLmerror(); |
990 | return $merror->encapsulateRaw( "Error parsing sideset expression, no succeeding operator found" ); |
991 | } |
992 | |
993 | $mmlMrow = new MMLmrow( TexClass::OP ); |
994 | if ( $operatorContent["sideset"] instanceof Literal ) { |
995 | $mmlMultiscripts = new MMLmmultiscripts( "", [ Tag::ALIGN => "left" ] ); |
996 | |
997 | $bm = new BaseMethods(); |
998 | $opParsed = $bm->checkAndParseOperator( $operatorContent["sideset"]->getArg(), null, [], [], null ); |
999 | $in1 = $node->getArg1()->renderMML(); |
1000 | $in2 = $node->getArg2()->renderMML(); |
1001 | return $mmlMrow->encapsulateRaw( $mmlMultiscripts->encapsulateRaw( $opParsed . |
1002 | $in2 . "<mprescripts/>" . $in1 ) ); |
1003 | } |
1004 | |
1005 | if ( $operatorContent["sideset"] instanceof FQ ) { |
1006 | $mmlMultiscripts = new MMLmmultiscripts( "", [] ); |
1007 | $mmlMunderOver = new MMLmunderover(); |
1008 | $mstyle = new MMLmstyle( "", [ "displaystyle" => "true" ] ); |
1009 | $bm = new BaseMethods(); |
1010 | if ( count( $operatorContent["sideset"]->getBase()->getArgs() ) == 1 ) { |
1011 | $opParsed = $bm->checkAndParseOperator( $operatorContent["sideset"]->getBase()->getArgs()[0], |
1012 | null, [ "largeop" => "true", "movablelimits" => "false", "symmetric" => "true" ], [], null ); |
1013 | } else { |
1014 | $merror = new MMLmerror(); |
1015 | $opParsed = $merror->encapsulateRaw( "Sideset operator parsing not implemented yet" ); |
1016 | } |
1017 | |
1018 | $in1 = $node->getArg1()->renderMML(); |
1019 | $in2 = $node->getArg2()->renderMML(); |
1020 | |
1021 | $mrowEnd = new MMLmrow( "", [] ); |
1022 | $end1 = $mrowEnd->encapsulateRaw( $operatorContent["sideset"]->getDown()->renderMML() ); |
1023 | $end2 = $mrowEnd->encapsulateRaw( $operatorContent["sideset"]->getUp()->renderMML() ); |
1024 | |
1025 | return $mmlMrow->encapsulateRaw( $mmlMunderOver->encapsulateRaw( $mstyle->encapsulateRaw( |
1026 | $mmlMultiscripts->encapsulateRaw( $opParsed . $in2 . "<mprescripts/>" . $in1 ) ) |
1027 | . $end1 . $end2 ) ); |
1028 | } |
1029 | |
1030 | $merror = new MMLmerror(); |
1031 | return $merror->encapsulateRaw( "Error parsing sideset expression, no valid succeeding operator found" ); |
1032 | } |
1033 | |
1034 | public static function spacer( $node, $passedArgs, $operatorContent, $name, $withIn = null, $smth2 = null ) { |
1035 | $width = MMLutil::round2em( $withIn ); |
1036 | $mspace = new MMLmspace( "", [ "width" => $width ] ); |
1037 | return $mspace->encapsulate(); |
1038 | } |
1039 | |
1040 | public static function smash( $node, $passedArgs, $operatorContent, $name ) { |
1041 | $mpArgs = []; |
1042 | $inner = ""; |
1043 | if ( $node instanceof Fun2sq ) { |
1044 | $arg1 = $node->getArg1(); |
1045 | $arg1i = ""; |
1046 | if ( $arg1 instanceof Curly ) { |
1047 | $arg1i = $arg1->getArg()->render(); |
1048 | } |
1049 | |
1050 | if ( str_contains( $arg1i, "{b}" ) ) { |
1051 | $mpArgs = [ "depth" => "0" ]; |
1052 | } |
1053 | if ( str_contains( $arg1i, "{t}" ) ) { |
1054 | $mpArgs = [ "height" => "0" ]; |
1055 | } |
1056 | if ( str_contains( $arg1i, "{tb}" ) || str_contains( $arg1i, "{bt}" ) ) { |
1057 | $mpArgs = [ "height" => "0", "depth" => "0" ]; |
1058 | } |
1059 | |
1060 | $inner = $node->getArg2()->renderMML() ?? ""; |
1061 | } elseif ( $node instanceof Fun1 ) { |
1062 | // Implicitly assume "tb" as default mode |
1063 | $mpArgs = [ "height" => "0", "depth" => "0" ]; |
1064 | $inner = $node->getArg()->renderMML() ?? ""; |
1065 | } |
1066 | $mrow = new MMLmrow(); |
1067 | $mpAdded = new MMLmpadded( "", $mpArgs ); |
1068 | return $mrow->encapsulateRaw( $mpAdded->encapsulateRaw( $inner ) ); |
1069 | } |
1070 | |
1071 | public static function texAtom( $node, $passedArgs, $operatorContent, $name, $texClass = null ) { |
1072 | switch ( $name ) { |
1073 | case "mathclose": |
1074 | $mrow = new MMLmrow(); |
1075 | $mrow2 = new MMLmrow( $texClass, [] ); |
1076 | $inner = $node->getArg()->renderMML(); |
1077 | return $mrow->encapsulateRaw( $mrow2->encapsulateRaw( $inner ) ); |
1078 | case "mathbin": |
1079 | // no break |
1080 | case "mathop": |
1081 | // no break |
1082 | case "mathrel": |
1083 | $mrow2 = new MMLmrow( $texClass, [] ); |
1084 | $inner = $node->getArg()->renderMML(); |
1085 | return $mrow2->encapsulateRaw( $inner ); |
1086 | default: |
1087 | $mrow = new MMLmrow( TexClass::ORD ); |
1088 | $mrow2 = new MMLmrow( $texClass, [] ); |
1089 | $inner = $node->getArg()->renderMML(); |
1090 | return $mrow->encapsulateRaw( $mrow2->encapsulateRaw( $inner ) ); |
1091 | } |
1092 | } |
1093 | |
1094 | public static function intent( $node, $passedArgs, $operatorContent, $name, $smth = null ) { |
1095 | if ( !$node instanceof Fun2 ) { |
1096 | return null; |
1097 | } |
1098 | // if there is intent annotation add intent to root element |
1099 | // match args in row of subargs, unless an element has explicit annotations |
1100 | // nested annotations ? |
1101 | $arg1 = $node->getArg1(); |
1102 | if ( !$node->getArg2() instanceof Curly ) { |
1103 | return null; |
1104 | } |
1105 | // tbd refactor intent form and fiddle in mml or tree |
1106 | $intentStr = MMLutil::squashLitsToUnitIntent( $node->getArg2() ); |
1107 | $intentContent = MMLParsingUtil::getIntentContent( $intentStr ); |
1108 | $intentParams = MMLParsingUtil::getIntentParams( $intentContent ); |
1109 | // Sometimes the intent has additioargs = {array[3]} nal args in the same string |
1110 | $intentArg = MMLParsingUtil::getIntentArgs( $intentStr ); |
1111 | if ( !$intentContent && !$intentParams && isset( $intentArg ) ) { |
1112 | // explicit args annotation parsing in literal |
1113 | // return $arg1->renderMML([],["intent-params-expl"=>$intentArg]); |
1114 | // alternative just add the arg here |
1115 | return $arg1->renderMML( [ "arg" => $intentArg ] ); |
1116 | } |
1117 | $intentContentAtr = [ "intent" => $intentContent ]; |
1118 | if ( isset( $intentArg ) ) { |
1119 | $intentContentAtr["arg"] = $intentArg; |
1120 | } |
1121 | // tbd refine intent params and operator content merging (does it overwrite ??) |
1122 | $intentParamsState = $intentParams ? [ "intent-params" => $intentParams ] : $operatorContent; |
1123 | // Here are some edge cases, they might go into renderMML in the related element |
1124 | if ( str_contains( $intentContent, "matrix" ) || |
1125 | ( $arg1 instanceof Curly && $arg1->getArg()->getArgs()[0] instanceof Matrix ) ) { |
1126 | $element = $arg1->getArg()->getArgs()[0]; |
1127 | $rendered = $element->renderMML( [], $intentParamsState ); |
1128 | $hackyXML = MMLParsingUtil::forgeIntentToSpecificElement( $rendered, |
1129 | $intentContentAtr, "mtable" ); |
1130 | return $hackyXML; |
1131 | } elseif ( $arg1 instanceof Curly && count( $arg1->getArg()->getArgs() ) >= 2 ) { |
1132 | // Create a surrounding element which holds the intents |
1133 | $mrow = new MMLmrow( "", $intentContentAtr ); |
1134 | return $mrow->encapsulateRaw( $arg1->renderMML( [], $intentParamsState ) ); |
1135 | } elseif ( $arg1 instanceof Curly && count( $arg1->getArg()->getArgs() ) >= 1 ) { |
1136 | // Forge the intent attribute to the top-level element after MML rendering |
1137 | $element = $arg1->getArg()->getArgs()[0]; |
1138 | $rendered = $element->renderMML( [], $intentParamsState ); |
1139 | $hackyXML = MMLParsingUtil::forgeIntentToTopElement( $rendered, $intentContentAtr ); |
1140 | return $hackyXML; |
1141 | } else { |
1142 | // This is the default case |
1143 | return $arg1->renderMML( $intentContentAtr, $intentParamsState ); |
1144 | } |
1145 | } |
1146 | |
1147 | public static function hBox( $node, $passedArgs, $operatorContent, $name, $smth = null ) { |
1148 | switch ( $name ) { |
1149 | case "mbox": |
1150 | $mo = new MMLmo(); |
1151 | $mmlMrow = new MMLmrow(); |
1152 | if ( $operatorContent != null && array_key_exists( "foundOC", $operatorContent ) ) { |
1153 | $op = MMLutil::inputPreparation( $operatorContent["foundOC"] ); |
1154 | $macro = BaseMappings::getNullaryMacro( $op ); |
1155 | if ( !$macro ) { |
1156 | $macro = BaseMappings::getIdentifierByKey( $op ); |
1157 | } |
1158 | $input = $macro[0] ?? $operatorContent["foundOC"]; |
1159 | return $mmlMrow->encapsulateRaw( $mo->encapsulateRaw( $input ) ); |
1160 | } else { |
1161 | $mmlMrow = new MMLmrow(); |
1162 | $mtext = new MMLmtext(); |
1163 | return $mmlMrow->encapsulateRaw( $mtext->encapsulateRaw( "\mbox" ) ); |
1164 | } |
1165 | case "hbox": |
1166 | $mmlMrow = new MMLmrow(); |
1167 | $mstyle = new MMLmstyle( "", [ "displaystyle" => "false", "scriptlevel" => "0" ] ); |
1168 | $mtext = new MMLmtext(); |
1169 | $inner = $node->getArg() instanceof TexNode ? $node->getArg()->renderMML() : $node->getArg(); |
1170 | return $mmlMrow->encapsulateRaw( $mstyle->encapsulateRaw( $mtext->encapsulateRaw( $inner ) ) ); |
1171 | case "text": |
1172 | $mmlMrow = new MMLmrow(); |
1173 | $mtext = new MMLmtext(); |
1174 | $inner = $node->getArg() instanceof TexNode ? $node->getArg()->renderMML() : $node->getArg(); |
1175 | return $mmlMrow->encapsulateRaw( $mtext->encapsulateRaw( $inner ) ); |
1176 | case "textbf": |
1177 | // no break |
1178 | case "textit": |
1179 | // no break |
1180 | case "textrm": |
1181 | // no break |
1182 | case "textsf": |
1183 | // no break |
1184 | case "texttt": |
1185 | $mmlMrow = new MMLmrow(); |
1186 | $mtext = new MMLmtext( "", MMLParsingUtil::getFontArgs( $name, null, null ) ); |
1187 | |
1188 | $inner = $node->getArg() instanceof Curly ? $node->getArg()->getArg()->renderMML( |
1189 | [], [ "inHBox" => true ] ) |
1190 | : $node->getArg()->renderMML( [ "fromHBox" => true ] ); |
1191 | return $mmlMrow->encapsulateRaw( $mtext->encapsulateRaw( $inner ) ); |
1192 | } |
1193 | |
1194 | $merror = new MMLmerror(); |
1195 | // $node->getArg1()->renderMML() . $node->getArg2()->renderMML() |
1196 | return $merror->encapsulateRaw( "undefined hbox" ); |
1197 | } |
1198 | |
1199 | public static function setStyle( $node, $passedArgs, $operatorContent, $name, |
1200 | $smth = null, $smth1 = null, $smth2 = null ) { |
1201 | // Just discard setstyle since they are captured in TexArray now} |
1202 | return " "; |
1203 | } |
1204 | |
1205 | public static function not( $node, $passedArgs, $operatorContent, $name, $smth = null, |
1206 | $smth1 = null, $smth2 = null ) { |
1207 | // This is only tested for \not statement without follow-up parameters |
1208 | if ( $node instanceof Literal ) { |
1209 | return MMLParsingUtil::createNot(); |
1210 | } else { |
1211 | $mError = new MMLmerror(); |
1212 | return $mError->encapsulateRaw( "TBD implement not" ); |
1213 | } |
1214 | } |
1215 | |
1216 | public static function vbox( $node, $passedArgs, $operatorContent, $name, $smth = null ) { |
1217 | // This is only example functionality for vbox("ab"). |
1218 | // TBD: it should be discussed if vbox is supported since it |
1219 | // does not seem to be supported by mathjax |
1220 | if ( is_string( $node->getArg() ) ) { |
1221 | $mmlMover = new MMLmover(); |
1222 | $mmlmrow = new MMLmrow(); |
1223 | $arr1 = str_split( $node->getArg() ); |
1224 | $inner = ""; |
1225 | foreach ( $arr1 as $char ) { |
1226 | $inner .= $mmlmrow->encapsulateRaw( $char ); |
1227 | } |
1228 | return $mmlMover->encapsulateRaw( $inner ); |
1229 | } |
1230 | $mError = new MMLmerror(); |
1231 | return $mError->encapsulateRaw( "no implemented vbox" ); |
1232 | } |
1233 | |
1234 | public static function sqrt( $node, $passedArgs, $operatorContent, $name ) { |
1235 | $mrow = new MMLmrow(); |
1236 | |
1237 | // There is an additional argument for the root |
1238 | if ( $node instanceof Fun2sq ) { |
1239 | $mroot = new MMLmroot(); |
1240 | |
1241 | // In case of an empty curly add an mrow |
1242 | $arg2Rendered = $node->getArg2()->renderMML( $passedArgs ); |
1243 | if ( trim( $arg2Rendered ) === "" ) { |
1244 | $arg2Rendered = $mrow->getEmpty(); |
1245 | } |
1246 | return $mrow->encapsulateRaw( |
1247 | $mroot->encapsulateRaw( |
1248 | $arg2Rendered . |
1249 | $mrow->encapsulateRaw( |
1250 | $node->getArg1()->renderMML( $passedArgs ) |
1251 | ) |
1252 | ) |
1253 | ); |
1254 | } |
1255 | $msqrt = new MMLmsqrt(); |
1256 | // Currently this is own implementation from Fun1.php |
1257 | return $mrow->encapsulateRaw( // assuming that this is always encapsulated in mrow |
1258 | $msqrt->encapsulateRaw( |
1259 | $node->getArg()->renderMML( $passedArgs ) |
1260 | ) |
1261 | ); |
1262 | } |
1263 | |
1264 | public static function tilde( $node, $passedArgs, $operatorContent, $name ) { |
1265 | $mspace = new MMLmspace( "", [ "width" => "0.5em" ] ); |
1266 | return $mspace->getEmpty(); |
1267 | } |
1268 | |
1269 | public static function xArrow( $node, $passedArgs, $operatorContent, $name, $chr = null, $l = null, $r = null ) { |
1270 | $defWidth = "+" . MMLutil::round2em( ( $l + $r ) / 18 ); |
1271 | $defLspace = MMLutil::round2em( $l / 18 ); |
1272 | |
1273 | $mover = new MMLmover(); |
1274 | $mstyle = new MMLmstyle( "", [ "scriptlevel" => "0" ] ); |
1275 | $moArrow = new MMLmo( Texclass::REL, [] ); |
1276 | $char = IntlChar::chr( $chr ); |
1277 | |
1278 | $mpaddedArgs = [ "height" => "-.2em", "lspace" => $defLspace, "voffset" => "-.2em", "width" => $defWidth ]; |
1279 | $mpadded = new MMLmpadded( "", $mpaddedArgs ); |
1280 | $mspace = new MMLmspace( "", [ "depth" => ".25em" ] ); |
1281 | if ( $node instanceof Fun2sq ) { |
1282 | $mmlMrow = new MMLmrow(); |
1283 | $mmlUnderOver = new MMLmunderover(); |
1284 | return $mmlMrow->encapsulateRaw( $mmlUnderOver->encapsulateRaw( |
1285 | $mstyle->encapsulateRaw( $moArrow->encapsulateRaw( $char ) ) . |
1286 | $mpadded->encapsulateRaw( |
1287 | $mmlMrow->encapsulateRaw( |
1288 | $node->getArg1()->renderMML() |
1289 | ) . |
1290 | $mspace->encapsulate() |
1291 | ) . |
1292 | $mpadded->encapsulateRaw( |
1293 | $node->getArg2()->renderMML() |
1294 | ) |
1295 | ) ); |
1296 | |
1297 | } |
1298 | return $mover->encapsulateRaw( |
1299 | $mstyle->encapsulateRaw( $moArrow->encapsulateRaw( $char ) ) . |
1300 | $mpadded->encapsulateRaw( |
1301 | $node->getArg()->renderMML() . |
1302 | $mspace->encapsulate() |
1303 | ) |
1304 | ); |
1305 | } |
1306 | } |