Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
42.72% covered (danger)
42.72%
44 / 103
27.27% covered (danger)
27.27%
3 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
MMLParsingUtil
42.72% covered (danger)
42.72%
44 / 103
27.27% covered (danger)
27.27%
3 / 11
623.55
0.00% covered (danger)
0.00%
0 / 1
 renderApplyFunction
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getFontArgs
66.67% covered (warning)
66.67%
24 / 36
0.00% covered (danger)
0.00%
0 / 1
25.48
 parseDefineColorExpression
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
4
 createNot
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 addToChr
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getIntentContent
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 getIntentParams
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 getIntentArgs
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 forgeIntentToTopElement
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 addAttributesToMML
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
182
 forgeIntentToSpecificElement
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3namespace MediaWiki\Extension\Math\WikiTexVC\MMLmappings\Util;
4
5use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\Tag;
6use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\TexClass;
7use MediaWiki\Extension\Math\WikiTexVC\MMLmappings\TexConstants\Variants;
8use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLbase;
9use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmo;
10use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmpadded;
11use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmrow;
12use MediaWiki\Extension\Math\WikiTexVC\MMLnodes\MMLmtext;
13
14/**
15 * This class contains functionalities for MML-node
16 * parsing which can be extracted and are used
17 * for multiple functions.
18 */
19class MMLParsingUtil {
20    public static function renderApplyFunction(): MMLbase {
21        return new MMLmo( "", [], "&#x2061;" );
22    }
23
24    public static function getFontArgs( string $name, ?string $variant, ?array $passedArgs ): array {
25        $args = [];
26        switch ( trim( $name, " \n\r\t\v\0\\" ) ) {
27            case "cal":
28            case "mathcal":
29                $args = [ Tag::MJXVARIANT => "-tex-calligraphic", 'mathvariant' => Variants::SCRIPT ];
30                break;
31            case "it":
32            case "mathit":
33                $args = [ Tag::MJXVARIANT => $variant, 'mathvariant' => Variants::ITALIC ];
34                break;
35            case "bf":
36            case "mathbf":
37                $args = [ 'mathvariant' => $variant ];
38                break;
39            // Sstatements from here come from other fct ok ? otherwise create second fct
40            case "textit":
41                $args = [ 'mathvariant' => Variants::ITALIC ];
42                break;
43            case "textbf":
44                $args = [ 'mathvariant' => Variants::BOLD ];
45                break;
46            case "textsf":
47                $args = [ 'mathvariant' => Variants::SANSSERIF ];
48                break;
49            case "texttt":
50                $args = [ 'mathvariant' => Variants::MONOSPACE ];
51                break;
52            case "textrm":
53                break;
54            case "emph":
55                // Toggle by passed args in emph
56                if ( isset( $passedArgs['mathvariant'] ) ) {
57                    if ( $passedArgs['mathvariant'] === Variants::ITALIC ) {
58                        $args = [ 'mathvariant' => Variants::NORMAL ];
59                    }
60                } else {
61                    $args = [ 'mathvariant' => Variants::ITALIC ];
62                }
63                break;
64            default:
65                $args = [ 'mathvariant' => $variant ];
66
67        }
68        return $args;
69    }
70
71    /**
72     * Parses an expression that defines a color; this is usually an argument in Literal.
73     * Example expression is: "\definecolor {ultramarine}{rgb}{0,0.12549019607843,0.37647058823529}"
74     * @param string $input tex-string, which contains the expression
75     * @return array|null either an array which contains hex of parsed expression or null if not parsable
76     */
77    public static function parseDefineColorExpression( string $input ): ?array {
78        $returnObj = null;
79        $matches = [];
80        $matched = preg_match_all( '/\{(.*?)\}/', $input, $matches );
81        if ( !$matched ) {
82            return null;
83        }
84        $ctr = count( $matches[1] ?? [] );
85
86        if ( $ctr == 3 && $matches[1][1] === "rgb" ) {
87            $returnObj = [];
88            $rgbValues = explode( ",", $matches[1][2] );
89            $r  = round( floatval( $rgbValues[0] ) * 255 );
90            $g = round( floatval( $rgbValues[1] ) * 255 );
91            $b = round( floatval( $rgbValues[2] ) * 255 );
92            $color = sprintf( "#%02x%02x%02x", $r, $g, $b );
93            $returnObj["name"] = $matches[1][0];
94            $returnObj["type"] = "rgb";
95            $returnObj["hex"] = $color;
96        }
97
98        return $returnObj;
99    }
100
101    /**
102     * Creates a negation block in MathML, usually preceding the negated statement
103     * @return MMLbase negation block as MathML
104     */
105    public static function createNot(): MMLbase {
106        return new MMLmrow( TexClass::REL, [],
107            new MMLmpadded( "", [ "width" => "0" ], new MMLmtext( "", [], "&#x29F8;" ) ) );
108    }
109
110    private static function addToChr( string $chr, string $base ): string {
111        return strtoupper( dechex( mb_ord( $chr ) + hexdec( $base ) ) );
112    }
113
114    public static function getIntentContent( ?string $input ): ?string {
115        if ( !$input ) {
116            return null;
117        }
118        $matchesInt = [];
119        $matchInt = preg_match( "/intent=[\'\"](.*)[\'\"]/", $input, $matchesInt );
120        if ( $matchInt && count( $matchesInt ) >= 2 ) {
121            return $matchesInt[1];
122        }
123        return null;
124    }
125
126    public static function getIntentParams( ?string $intentContent ): ?array {
127        if ( !$intentContent ) {
128            return null;
129        }
130        $matchesParams = [];
131        // tbd eventually not only alphanumerical chars valid in intent params
132        $matchParams = preg_match_all( "/\\\$([a-zA-Z]+)/", $intentContent, $matchesParams );
133        if ( $matchParams && count( $matchesParams ) >= 2 ) {
134            return $matchesParams[1];
135        }
136        return null;
137    }
138
139    public static function getIntentArgs( ?string $input ): ?string {
140        if ( !$input ) {
141            return null;
142        }
143        $matchesArgs = [];
144        $matchArg = preg_match( "/arg\s*=\s*[\'\"](.*?)[\'\"]/", $input, $matchesArgs );
145        if ( $matchArg && count( $matchesArgs ) >= 2 ) {
146            return $matchesArgs[1];
147        }
148        return null;
149    }
150
151    /**
152     * Converts a rendered MathML string to a XML tree and adds the attributes from input
153     * to the top-level element.Valid attributes for adding are "arg" and "intent.
154     * It overwrites pre-existing attributes in the top-level element.
155     * TBD: currently contains a hacky way to remove xml header in the output string
156     * example:" <msup intent="_($op,_of,$arg)">" intent attributes comes from input variables
157     * @param string $renderedMML defines input MathML string
158     * @param array $intentContentAtr defines attributes to add
159     * @return string MML with added attributes
160     */
161    public static function forgeIntentToTopElement( string $renderedMML, $intentContentAtr ) {
162        if ( !$intentContentAtr || !$renderedMML ) {
163            return $renderedMML;
164        }
165
166        return self::addAttributesToMML( $renderedMML, $intentContentAtr, "" );
167    }
168
169    /**
170     * Add parameters from aattributes to the MML string
171     * @param string $renderedMML defines input MathML string
172     * @param array $intentContentAtr defines attributes to add
173     * @param string $elementTag element tag when using foundNodes
174     * @param bool $useFoundNodes use found nodes
175     * @return string MML with added attributes
176     */
177    public static function addAttributesToMML(
178        string $renderedMML, array $intentContentAtr, string $elementTag, bool $useFoundNodes = false
179    ): string {
180        $xml = simplexml_load_string( $renderedMML );
181        if ( !$xml ) {
182            return "";
183        }
184        if ( $useFoundNodes ) {
185            $foundNodes = $xml->xpath( $elementTag );
186            if ( !( $foundNodes !== null && count( $foundNodes ) >= 1 ) ) {
187                return $renderedMML;
188            }
189        }
190
191        if ( isset( $intentContentAtr["intent"] ) ) {
192            if ( isset( $xml["intent"] ) ) {
193                $xml["intent"] = $intentContentAtr["intent"];
194            } elseif ( $intentContentAtr["intent"] != null && is_string( $intentContentAtr["intent"] ) ) {
195                $xml->addAttribute( "intent", $intentContentAtr["intent"] );
196            }
197        }
198        if ( isset( $intentContentAtr["arg"] ) ) {
199            if ( isset( $xml["arg"] ) ) {
200                $xml["arg"] = $intentContentAtr["arg"];
201            } elseif ( $intentContentAtr["arg"] != null && is_string( $intentContentAtr["arg"] ) ) {
202                $xml->addAttribute( "arg", $intentContentAtr["arg"] );
203            }
204        }
205
206        $hackyXML = str_replace( "<?xml version=\"1.0\"?>", "", $xml->asXML() );
207        return str_replace( "\n", "", $hackyXML );
208    }
209
210    public static function forgeIntentToSpecificElement(
211        string $renderedMML, array $intentContentAtr, string $elementTag
212    ): string {
213        if ( !$intentContentAtr || !$renderedMML || !$elementTag ) {
214            return $renderedMML;
215        }
216        return self::addAttributesToMML( $elementTag, $intentContentAtr, $elementTag, true );
217    }
218
219}