Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 65
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialMathShowImage
0.00% covered (danger)
0.00%
0 / 65
0.00% covered (danger)
0.00%
0 / 5
462
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 setHeaders
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
12
 execute
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 1
210
 printSvgError
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 getGroupName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Extension\Math;
4
5use MediaWiki\Extension\Math\Render\RendererFactory;
6use MediaWiki\SpecialPage\SpecialPage;
7
8/**
9 * Description of SpecialMathShowSVG
10 *
11 * @author Moritz Schubotz (Physikerwelt)
12 */
13class SpecialMathShowImage extends SpecialPage {
14    /** @var bool */
15    private $noRender = false;
16    /** @var MathRenderer|null */
17    private $renderer = null;
18    /** @var string */
19    private $mode = MathConfig::MODE_MATHML;
20
21    /** @var MathConfig */
22    private $mathConfig;
23
24    /** @var RendererFactory */
25    private $rendererFactory;
26
27    /**
28     * @param MathConfig $mathConfig
29     * @param RendererFactory $rendererFactory
30     */
31    public function __construct(
32        MathConfig $mathConfig,
33        RendererFactory $rendererFactory
34    ) {
35        parent::__construct(
36            'MathShowImage',
37            '', // Don't restrict
38            false // Don't show on Special:SpecialPages - it's not useful interactively
39        );
40        $this->mathConfig = $mathConfig;
41        $this->rendererFactory = $rendererFactory;
42    }
43
44    /**
45     * Sets headers - this should be called from the execute() method of all derived classes!
46     * @param bool $success
47     */
48    public function setHeaders( $success = true ) {
49        $out = $this->getOutput();
50        $request = $this->getRequest();
51        $out->setArticleBodyOnly( true );
52        $out->setArticleRelated( false );
53        $out->setRobotPolicy( "noindex,nofollow" );
54        $out->disable();
55        $request->response()->header( "Content-type: image/svg+xml; charset=utf-8" );
56        if ( $success && !( $this->noRender ) ) {
57            $request->response()->header(
58                'Cache-Control: public, s-maxage=604800, max-age=3600'
59            ); // 1 week (server) 1 hour (client)
60            $request->response()->header( 'Vary: User-Agent' );
61        }
62    }
63
64    public function execute( $par ) {
65        global $wgMathEnableExperimentalInputFormats;
66        $request = $this->getRequest();
67        $hash = $request->getText( 'hash', '' );
68        $tex = $request->getText( 'tex', '' );
69        if ( $wgMathEnableExperimentalInputFormats ) {
70            $asciimath = $request->getText( 'asciimath', '' );
71        } else {
72            $asciimath = '';
73        }
74        $this->mode = MathConfig::normalizeRenderingMode( $request->getText( 'mode' ) );
75        if ( !$this->mathConfig->isValidRenderingMode( $this->mode ) ) {
76            // Fallback to the default if an invalid mode was specified
77            $this->mode = MathConfig::MODE_MATHML;
78        }
79        if ( $hash === '' && $tex === '' && $asciimath === '' ) {
80            $this->setHeaders( false );
81            echo $this->printSvgError( 'No Inputhash specified' );
82        } else {
83            if ( $tex === '' && $asciimath === '' ) {
84                $this->renderer = $this->rendererFactory->getFromHash( $hash );
85                $this->noRender = $request->getBool( 'noRender', false );
86                $isInDatabase = $this->renderer->readFromCache();
87                if ( $isInDatabase || $this->noRender ) {
88                    $success = $isInDatabase;
89                } else {
90                    $success = $this->renderer->render();
91                }
92            } elseif ( $asciimath === '' ) {
93                $this->renderer = $this->rendererFactory->getRenderer( $tex, [], $this->mode );
94                $success = $this->renderer->render();
95            } else {
96                $this->renderer = $this->rendererFactory->getRenderer(
97                    $asciimath, [ 'type' => 'ascii' ], $this->mode
98                );
99                $success = $this->renderer->render();
100            }
101            if ( $success ) {
102                $output = $this->renderer->getSvg();
103            } else {
104                $output = $this->printSvgError( $this->renderer->getLastError() );
105            }
106            if ( $output == "" ) {
107                $output = $this->printSvgError( 'No Output produced' );
108                $success = false;
109            }
110            $this->setHeaders( $success );
111            echo $output;
112            if ( $success ) {
113                $this->renderer->writeCache();
114            }
115        }
116    }
117
118    /**
119     * Prints the specified error message as svg.
120     * @param string $msg error message, HTML escaped
121     * @return string xml svg image with the error message
122     */
123    private function printSvgError( $msg ) {
124        global $wgDebugComments;
125        $result = <<<SVG
126<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 4" preserveAspectRatio="xMidYMid meet" >
127<text text-anchor="start" fill="red" y="2">
128$msg
129</text>
130</svg>
131SVG;
132        if ( $wgDebugComments ) {
133            $result .= '<!--' . var_export( $this->renderer, true ) . '-->';
134        }
135        return $result;
136    }
137
138    protected function getGroupName() {
139        return 'other';
140    }
141}