Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
60.80% |
107 / 176 |
|
43.18% |
19 / 44 |
CRAP | |
0.00% |
0 / 1 |
| MathRenderer | |
60.80% |
107 / 176 |
|
43.18% |
19 / 44 |
476.35 | |
0.00% |
0 / 1 |
| setRawError | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| __construct | |
61.90% |
13 / 21 |
|
0.00% |
0 / 1 |
7.99 | |||
| getRenderer | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
| render | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
| getHtmlOutput | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
| getError | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
| getInputHash | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
2 | |||
| readFromCache | |
80.00% |
4 / 5 |
|
0.00% |
0 / 1 |
2.03 | |||
| dbInArray | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
| initializeFromCache | |
90.00% |
9 / 10 |
|
0.00% |
0 / 1 |
5.03 | |||
| writeToCache | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
| dbOutArray | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
1 | |||
| setRestbaseInterface | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
| hasWarnings | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
| addTrackingCategories | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 | |||
| getChecker | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
| getAttributes | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
| writeCache | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
2 | |||
| getTex | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getMode | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| setMode | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
| setTex | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
| getMathml | |
66.67% |
2 / 3 |
|
0.00% |
0 / 1 |
2.15 | |||
| setMathml | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
| getParams | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| setParams | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| isChanged | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| isPurge | |
41.67% |
5 / 12 |
|
0.00% |
0 / 1 |
13.15 | |||
| setPurge | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
| getLastError | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| setMathStyle | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 | |||
| getMathStyle | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| isTexSecure | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| checkTeX | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
6 | |||
| isInDatabase | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
| getUserInputTex | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getID | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| setID | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| setSvg | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
| getSvg | |
66.67% |
2 / 3 |
|
0.00% |
0 / 1 |
3.33 | |||
| getMathTableName | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
| getModeName | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
| setInputType | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getInputType | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| doCheck | |
50.00% |
5 / 10 |
|
0.00% |
0 / 1 |
4.12 | |||
| debug | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getCacheKey | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * MediaWiki math extension |
| 4 | * |
| 5 | * @copyright 2002-2012 Tomasz Wegrzanowski, Brion Vibber, Moritz Schubotz, |
| 6 | * and other MediaWiki contributors |
| 7 | * @license GPL-2.0-or-later |
| 8 | * |
| 9 | * @file |
| 10 | */ |
| 11 | |
| 12 | namespace MediaWiki\Extension\Math; |
| 13 | |
| 14 | use MediaWiki\Context\RequestContext; |
| 15 | use MediaWiki\Extension\Math\InputCheck\BaseChecker; |
| 16 | use MediaWiki\Logger\LoggerFactory; |
| 17 | use MediaWiki\MediaWikiServices; |
| 18 | use MediaWiki\Message\Message; |
| 19 | use MediaWiki\Parser\Parser; |
| 20 | use MediaWiki\Parser\Sanitizer; |
| 21 | use Psr\Log\LoggerInterface; |
| 22 | use Wikimedia\Message\MessageParam; |
| 23 | use Wikimedia\Message\MessageSpecifier as MsgSp; |
| 24 | use Wikimedia\ObjectCache\WANObjectCache; |
| 25 | use Wikimedia\StringUtils\StringUtils; |
| 26 | |
| 27 | /** |
| 28 | * Abstract base class with static methods for rendering the <math> tags using |
| 29 | * different technologies. These static methods create a new instance of the |
| 30 | * extending classes and render the math tags based on the mode setting of the user. |
| 31 | * Furthermore, this class handles the caching of the rendered output. |
| 32 | * |
| 33 | * @author Tomasz Wegrzanowski |
| 34 | * @author Brion Vibber |
| 35 | * @author Moritz Schubotz |
| 36 | */ |
| 37 | abstract class MathRenderer { |
| 38 | |
| 39 | // REPRESENTATIONS OF THE MATHEMATICAL CONTENT |
| 40 | /** @var ?string tex representation */ |
| 41 | protected $tex = ''; |
| 42 | /** @var string MathML content and presentation */ |
| 43 | protected $mathml = ''; |
| 44 | /** @var string SVG layout only (no semantics) */ |
| 45 | protected $svg = ''; |
| 46 | /** @var string the original user input string (which was used to calculate the inputhash) */ |
| 47 | protected $userInputTex = ''; |
| 48 | // FURTHER PROPERTIES OF THE MATHEMATICAL CONTENT |
| 49 | /** @var string ('inlineDisplaystyle'|'display'|'inline'|'linebreak') the rendering style */ |
| 50 | protected $mathStyle = 'inlineDisplaystyle'; |
| 51 | /** @var array with userdefined parameters passed to the extension (not used) */ |
| 52 | protected $params = []; |
| 53 | /** @var string a userdefined identifier to link to the equation. */ |
| 54 | protected $id = ''; |
| 55 | |
| 56 | // STATE OF THE CLASS INSTANCE |
| 57 | /** @var bool has variable tex been security-checked */ |
| 58 | protected $texSecure = false; |
| 59 | /** @var bool has the mathematical content changed */ |
| 60 | protected $changed = false; |
| 61 | /** @var bool|null is there a database entry for the mathematical content */ |
| 62 | protected $storedInCache = null; |
| 63 | /** @var bool is there a request to purge the existing mathematical content */ |
| 64 | protected $purge = false; |
| 65 | /** @var string with last occurred error */ |
| 66 | protected $lastError = ''; |
| 67 | /** @var string binary packed inputhash */ |
| 68 | protected $inputHash = ''; |
| 69 | /** @var string rendering mode */ |
| 70 | protected $mode = MathConfig::MODE_MATHML; |
| 71 | /** @var string input type */ |
| 72 | protected $inputType = 'tex'; |
| 73 | /** @var MathRestbaseInterface used for checking */ |
| 74 | protected $rbi; |
| 75 | /** @var array with rendering warnings */ |
| 76 | protected $warnings; |
| 77 | /** @var LoggerInterface */ |
| 78 | private $logger; |
| 79 | |
| 80 | private WANObjectCache $cache; |
| 81 | private MathConfig $mathConfig; |
| 82 | private bool $rawError = false; |
| 83 | |
| 84 | public function setRawError( bool $rawError ): void { |
| 85 | $this->rawError = $rawError; |
| 86 | } |
| 87 | |
| 88 | /** |
| 89 | * Constructs a base MathRenderer |
| 90 | * |
| 91 | * @param string $tex (optional) LaTeX markup |
| 92 | * @param array $params (optional) HTML attributes |
| 93 | * @param WANObjectCache|null $cache (optional) |
| 94 | * @param MathConfig|null $mathConfig (optional) |
| 95 | */ |
| 96 | public function __construct( string $tex = '', $params = [], $cache = null, $mathConfig = null ) { |
| 97 | $this->cache = $cache ?? MediaWikiServices::getInstance()->getMainWANObjectCache(); |
| 98 | $this->mathConfig = $mathConfig ?? Math::getMathConfig(); |
| 99 | $this->params = $params; |
| 100 | if ( isset( $params['id'] ) ) { |
| 101 | $this->id = $params['id']; |
| 102 | } |
| 103 | if ( isset( $params['display'] ) ) { |
| 104 | $layoutMode = $params['display']; |
| 105 | if ( $layoutMode == 'block' ) { |
| 106 | $this->mathStyle = 'display'; |
| 107 | $tex = '{\displaystyle ' . $tex . '}'; |
| 108 | $this->inputType = 'tex'; |
| 109 | } elseif ( $layoutMode == 'inline' ) { |
| 110 | $this->mathStyle = 'inline'; |
| 111 | $this->inputType = 'inline-tex'; |
| 112 | $tex = '{\textstyle ' . $tex . '}'; |
| 113 | } elseif ( $layoutMode == 'linebreak' ) { |
| 114 | $this->mathStyle = 'linebreak'; |
| 115 | $tex = '\[ ' . $tex . ' \]'; |
| 116 | } |
| 117 | } |
| 118 | // TODO: Implement caching for attributes of the math tag |
| 119 | // Currently the key for the database entry relating to an equation |
| 120 | // is md5($tex) the new option to determine if the tex input |
| 121 | // is rendered in displaystyle or textstyle would require a database |
| 122 | // layout change to use a composite key e.g. (md5($tex),$mathStyle). |
| 123 | // As a workaround we use the prefix \displaystyle so that the key becomes |
| 124 | // md5((\{\\displaystyle|\{\\textstyle)?\s?$tex\}?) |
| 125 | // The new value of $tex string describes now how the rendering should look like. |
| 126 | // The variable MathRenderer::mathStyle determines if the rendered equation should |
| 127 | // be centered in a new line, or just in be displayed in the current line. |
| 128 | $this->userInputTex = $tex; |
| 129 | $this->tex = $tex; |
| 130 | $this->logger = LoggerFactory::getInstance( 'Math' ); |
| 131 | } |
| 132 | |
| 133 | /** |
| 134 | * Static factory method for getting a renderer based on mode |
| 135 | * |
| 136 | * @deprecated since 3.0.0. Use Math.RendererFactory service instead. |
| 137 | * @param string $tex LaTeX markup |
| 138 | * @param array $params HTML attributes |
| 139 | * @param string $mode indicating rendering mode |
| 140 | * @return self appropriate renderer for mode |
| 141 | */ |
| 142 | public static function getRenderer( $tex, $params = [], $mode = MathConfig::MODE_MATHML ) { |
| 143 | return MediaWikiServices::getInstance() |
| 144 | ->get( 'Math.RendererFactory' ) |
| 145 | ->getRenderer( $tex, $params, $mode ); |
| 146 | } |
| 147 | |
| 148 | /** |
| 149 | * Performs the rendering |
| 150 | * |
| 151 | * @return bool if rendering was successful. |
| 152 | */ |
| 153 | abstract public function render(); |
| 154 | |
| 155 | /** |
| 156 | * @param bool $svg |
| 157 | * @return string Html output that is embedded in the page |
| 158 | */ |
| 159 | abstract public function getHtmlOutput( bool $svg = true ): string; |
| 160 | |
| 161 | /** |
| 162 | * texvc error messages |
| 163 | * TODO: update to MathML |
| 164 | * Returns an internationalized HTML error string |
| 165 | * |
| 166 | * @param string $msg message key for the specific error |
| 167 | * @param MessageParam|MsgSp|string|int|float|list<MessageParam|MsgSp|string|int|float> ...$parameters |
| 168 | * See Message::params() |
| 169 | * |
| 170 | * @return string HTML error string |
| 171 | */ |
| 172 | public function getError( string $msg, ...$parameters ): string { |
| 173 | if ( $this->rawError ) { |
| 174 | return 'Error: ' . $msg . ' param ' . implode( ',', $parameters ); |
| 175 | } |
| 176 | $mf = wfMessage( 'math_failure' )->inContentLanguage()->escaped(); |
| 177 | $errmsg = wfMessage( $msg, $parameters )->inContentLanguage()->escaped(); |
| 178 | $source = htmlspecialchars( str_replace( "\n", ' ', $this->tex ) ); |
| 179 | return "<strong class=\"error texerror\">$mf ($errmsg): $source</strong>\n"; |
| 180 | } |
| 181 | |
| 182 | /** |
| 183 | * Return hash of input |
| 184 | * |
| 185 | * @return string hash |
| 186 | */ |
| 187 | public function getInputHash(): string { |
| 188 | if ( !$this->inputHash ) { |
| 189 | $this->inputHash = hash( 'md5', // xxh128 might be better when dropping php 7 support |
| 190 | $this->mode . |
| 191 | $this->userInputTex . |
| 192 | implode( $this->params ) |
| 193 | ); |
| 194 | } |
| 195 | return $this->inputHash; |
| 196 | } |
| 197 | |
| 198 | /** |
| 199 | * Reads rendering data from database |
| 200 | * |
| 201 | * @return bool true if read successfully, false otherwise |
| 202 | */ |
| 203 | public function readFromCache(): bool { |
| 204 | $rpage = $this->cache->get( $this->getCacheKey() ); |
| 205 | if ( $rpage !== false ) { |
| 206 | $this->initializeFromCache( $rpage ); |
| 207 | return true; |
| 208 | } else { |
| 209 | # Missing from the database and/or the render cache |
| 210 | return false; |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | /** |
| 215 | * @return array with the database column names |
| 216 | */ |
| 217 | protected function dbInArray() { |
| 218 | $in = [ 'math_inputhash', |
| 219 | 'math_mathml', |
| 220 | 'math_inputtex', |
| 221 | 'math_tex', |
| 222 | 'math_svg' |
| 223 | ]; |
| 224 | return $in; |
| 225 | } |
| 226 | |
| 227 | /** |
| 228 | * Reads the values from the database but does not overwrite set values with empty values |
| 229 | * @param array $rpage (a database row) |
| 230 | */ |
| 231 | public function initializeFromCache( $rpage ) { |
| 232 | $this->inputHash = $rpage['math_inputhash']; // MUST NOT BE NULL |
| 233 | if ( isset( $rpage['math_mathml'] ) ) { |
| 234 | $this->mathml = $rpage['math_mathml']; |
| 235 | } |
| 236 | if ( isset( $rpage['math_inputtex'] ) ) { |
| 237 | $this->userInputTex = $rpage['math_inputtex']; |
| 238 | } |
| 239 | if ( isset( $rpage['math_tex'] ) ) { |
| 240 | $this->tex = $rpage['math_tex']; |
| 241 | } |
| 242 | if ( isset( $rpage['math_svg'] ) ) { |
| 243 | $this->svg = $rpage['math_svg']; |
| 244 | } |
| 245 | $this->changed = false; |
| 246 | } |
| 247 | |
| 248 | /** |
| 249 | * Writes rendering entry to cache. |
| 250 | * |
| 251 | * WARNING: Use writeCache() instead of this method to be sure that all |
| 252 | * renderer specific (such as squid caching) are taken into account. |
| 253 | * This function stores the values that are currently present in the class |
| 254 | * to the cache even if they are empty. |
| 255 | * |
| 256 | * This function can be seen as protected function. |
| 257 | */ |
| 258 | public function writeToCache() { |
| 259 | $outArray = $this->dbOutArray(); |
| 260 | $this->cache->set( $this->getCacheKey(), $outArray ); |
| 261 | } |
| 262 | |
| 263 | /** |
| 264 | * Gets an array that matches the variables of the class to the database columns |
| 265 | * @return array |
| 266 | */ |
| 267 | protected function dbOutArray() { |
| 268 | $out = [ |
| 269 | 'math_inputhash' => $this->getInputHash(), |
| 270 | 'math_mathml' => $this->mathml, |
| 271 | 'math_inputtex' => $this->userInputTex, |
| 272 | 'math_tex' => $this->tex, |
| 273 | 'math_svg' => $this->svg, |
| 274 | 'math_mode' => $this->mode |
| 275 | ]; |
| 276 | return $out; |
| 277 | } |
| 278 | |
| 279 | /** |
| 280 | * @param MathRestbaseInterface $param |
| 281 | */ |
| 282 | public function setRestbaseInterface( $param ) { |
| 283 | $this->rbi = $param; |
| 284 | $this->rbi->setPurge( $this->isPurge() ); |
| 285 | } |
| 286 | |
| 287 | public function hasWarnings(): bool { |
| 288 | if ( is_array( $this->warnings ) && count( $this->warnings ) ) { |
| 289 | return true; |
| 290 | } |
| 291 | |
| 292 | return false; |
| 293 | } |
| 294 | |
| 295 | /** |
| 296 | * Adds tracking categories to the parser |
| 297 | * |
| 298 | * @param Parser $parser |
| 299 | */ |
| 300 | public function addTrackingCategories( $parser ) { |
| 301 | if ( !$this->checkTeX() ) { |
| 302 | $parser->addTrackingCategory( 'math-tracking-category-error' ); |
| 303 | } |
| 304 | if ( $this->lastError ) { |
| 305 | // Add a tracking category specialized on render errors. |
| 306 | $parser->addTrackingCategory( 'math-tracking-category-render-error' ); |
| 307 | } |
| 308 | } |
| 309 | |
| 310 | protected function getChecker(): BaseChecker { |
| 311 | return Math::getCheckerFactory() |
| 312 | ->newDefaultChecker( $this->tex, $this->getInputType(), $this->rbi, $this->isPurge() ); |
| 313 | } |
| 314 | |
| 315 | /** |
| 316 | * Returns sanitized attributes |
| 317 | * |
| 318 | * @param string $tag element name |
| 319 | * @param array $defaults default attributes |
| 320 | * @param array $overrides attributes to override defaults |
| 321 | * @return array HTML attributes |
| 322 | */ |
| 323 | protected function getAttributes( $tag, $defaults = [], $overrides = [] ) { |
| 324 | $attribs = Sanitizer::validateTagAttributes( $this->params, $tag ); |
| 325 | $attribs = Sanitizer::mergeAttributes( $defaults, $attribs ); |
| 326 | return Sanitizer::mergeAttributes( $attribs, $overrides ); |
| 327 | } |
| 328 | |
| 329 | /** |
| 330 | * Writes cache. Writes the database entry if values were changed |
| 331 | * @return bool |
| 332 | */ |
| 333 | public function writeCache() { |
| 334 | $this->debug( 'Writing of cache requested' ); |
| 335 | if ( $this->isChanged() ) { |
| 336 | $this->debug( 'Change detected. Perform writing' ); |
| 337 | $this->writeToCache(); |
| 338 | return true; |
| 339 | } else { |
| 340 | $this->debug( "Nothing was changed. Don't write to database" ); |
| 341 | return false; |
| 342 | } |
| 343 | } |
| 344 | |
| 345 | /** |
| 346 | * Gets TeX markup |
| 347 | * |
| 348 | * @return string TeX markup |
| 349 | */ |
| 350 | public function getTex() { |
| 351 | return $this->tex; |
| 352 | } |
| 353 | |
| 354 | /** |
| 355 | * Gets the rendering mode |
| 356 | * |
| 357 | * @return string |
| 358 | */ |
| 359 | public function getMode() { |
| 360 | return $this->mode; |
| 361 | } |
| 362 | |
| 363 | /** |
| 364 | * Sets the rendering mode |
| 365 | * @param string $newMode element of the array $wgMathValidModes |
| 366 | * @return bool |
| 367 | */ |
| 368 | public function setMode( string $newMode ): bool { |
| 369 | if ( $this->mathConfig->isValidRenderingMode( $newMode ) ) { |
| 370 | $this->mode = $newMode; |
| 371 | return true; |
| 372 | } else { |
| 373 | return false; |
| 374 | } |
| 375 | } |
| 376 | |
| 377 | /** |
| 378 | * Sets the TeX code |
| 379 | */ |
| 380 | public function setTex( ?string $tex ) { |
| 381 | if ( $this->tex != $tex ) { |
| 382 | $this->changed = true; |
| 383 | $this->tex = $tex; |
| 384 | } |
| 385 | } |
| 386 | |
| 387 | /** |
| 388 | * Gets the MathML XML element |
| 389 | * @return string in UTF-8 encoding |
| 390 | */ |
| 391 | public function getMathml() { |
| 392 | if ( !StringUtils::isUtf8( $this->mathml ) ) { |
| 393 | $this->setMathml( '' ); |
| 394 | } |
| 395 | return $this->mathml; |
| 396 | } |
| 397 | |
| 398 | /** |
| 399 | * @param string $mathml use UTF-8 encoding |
| 400 | */ |
| 401 | public function setMathml( $mathml ) { |
| 402 | $this->changed = true; |
| 403 | $this->mathml = $mathml; |
| 404 | } |
| 405 | |
| 406 | /** |
| 407 | * Get the attributes of the math tag |
| 408 | * |
| 409 | * @return array |
| 410 | */ |
| 411 | public function getParams() { |
| 412 | return $this->params; |
| 413 | } |
| 414 | |
| 415 | /** |
| 416 | * @param array $params |
| 417 | */ |
| 418 | public function setParams( $params ) { |
| 419 | // $changed is not set to true here, because the attributes do not affect |
| 420 | // the rendering in the current implementation. |
| 421 | // If this behavior will change in the future $this->tex is no longer a |
| 422 | // primary key and the input hash cannot be calculate form $this->tex |
| 423 | // only. See the discussion 'Tag extensions in Block mode' on wikitech-l. |
| 424 | $this->params = $params; |
| 425 | } |
| 426 | |
| 427 | /** |
| 428 | * Checks if the instance was modified i.e., because math was rendered |
| 429 | * |
| 430 | * @return bool true if something was changed false otherwise |
| 431 | */ |
| 432 | public function isChanged() { |
| 433 | return $this->changed; |
| 434 | } |
| 435 | |
| 436 | /** |
| 437 | * Checks if there is an explicit user request to rerender the math-tag. |
| 438 | * @return bool purge state |
| 439 | */ |
| 440 | public function isPurge() { |
| 441 | if ( $this->purge ) { |
| 442 | return true; |
| 443 | } |
| 444 | $refererHeader = RequestContext::getMain()->getRequest()->getHeader( 'REFERER' ); |
| 445 | if ( $refererHeader ) { |
| 446 | $url = parse_url( $refererHeader, PHP_URL_QUERY ); |
| 447 | if ( !is_string( $url ) ) { |
| 448 | return false; |
| 449 | } |
| 450 | parse_str( $url, $refererParam ); |
| 451 | if ( isset( $refererParam['action'] ) && $refererParam['action'] === 'purge' ) { |
| 452 | $this->logger->debug( 'Re-Rendering on user request' ); |
| 453 | return true; |
| 454 | } |
| 455 | } |
| 456 | return false; |
| 457 | } |
| 458 | |
| 459 | /** |
| 460 | * Sets purge. If set to true the render is forced to rerender and must not |
| 461 | * use a cached version. |
| 462 | * @param bool $purge |
| 463 | */ |
| 464 | public function setPurge( $purge = true ) { |
| 465 | $this->changed = true; |
| 466 | $this->purge = $purge; |
| 467 | } |
| 468 | |
| 469 | public function getLastError(): string { |
| 470 | return $this->lastError; |
| 471 | } |
| 472 | |
| 473 | /** |
| 474 | * @param string $mathStyle ('inlineDisplaystyle'|'display'|'inline') |
| 475 | */ |
| 476 | public function setMathStyle( $mathStyle = 'display' ) { |
| 477 | if ( $this->mathStyle !== $mathStyle ) { |
| 478 | $this->mathStyle = $mathStyle; |
| 479 | $this->changed = true; |
| 480 | $this->inputType = $mathStyle === 'inline' ? 'inline-tex' : 'tex'; |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | /** |
| 485 | * Returns the value of the DisplayStyle attribute |
| 486 | * @return string ('inlineDisplaystyle'|'display'|'inline'|'linebreak') the DisplayStyle |
| 487 | */ |
| 488 | public function getMathStyle() { |
| 489 | return $this->mathStyle; |
| 490 | } |
| 491 | |
| 492 | /** |
| 493 | * Get if the input tex was marked as secure |
| 494 | * @return bool |
| 495 | */ |
| 496 | public function isTexSecure() { |
| 497 | return $this->texSecure; |
| 498 | } |
| 499 | |
| 500 | /** |
| 501 | * @return bool |
| 502 | */ |
| 503 | public function checkTeX() { |
| 504 | if ( $this->texSecure ) { |
| 505 | // equation was already checked |
| 506 | return true; |
| 507 | } |
| 508 | $texCheckDisabled = MediaWikiServices::getInstance() |
| 509 | ->get( 'Math.Config' ) |
| 510 | ->texCheckDisabled(); |
| 511 | if ( $texCheckDisabled === MathConfig::ALWAYS ) { |
| 512 | // checking is disabled |
| 513 | $this->debug( 'Skip TeX check ' ); |
| 514 | return true; |
| 515 | } else { |
| 516 | if ( $texCheckDisabled === MathConfig::NEW && $this->mode != MathConfig::MODE_SOURCE ) { |
| 517 | if ( $this->readFromCache() ) { |
| 518 | $this->debug( 'Skip TeX check' ); |
| 519 | $this->texSecure = true; |
| 520 | return true; |
| 521 | } |
| 522 | } |
| 523 | $this->debug( 'Perform TeX check' ); |
| 524 | return $this->doCheck(); |
| 525 | } |
| 526 | } |
| 527 | |
| 528 | public function isInDatabase(): bool { |
| 529 | if ( $this->storedInCache === null ) { |
| 530 | $this->storedInCache = $this->readFromCache(); |
| 531 | } |
| 532 | return $this->storedInCache; |
| 533 | } |
| 534 | |
| 535 | /** |
| 536 | * @return string TeX the original tex string specified by the user |
| 537 | */ |
| 538 | public function getUserInputTex() { |
| 539 | return $this->userInputTex; |
| 540 | } |
| 541 | |
| 542 | /** |
| 543 | * @return string user defined ID |
| 544 | */ |
| 545 | public function getID() { |
| 546 | return $this->id; |
| 547 | } |
| 548 | |
| 549 | /** |
| 550 | * @param string $id user defined ID |
| 551 | */ |
| 552 | public function setID( $id ) { |
| 553 | // Changes in the ID affect the container for the math element on the current page |
| 554 | // only. Therefore an id change does not affect the $this->changed variable, which |
| 555 | // indicates if database relevant fields have been changed. |
| 556 | $this->id = $id; |
| 557 | } |
| 558 | |
| 559 | /** |
| 560 | * @param string $svg |
| 561 | */ |
| 562 | public function setSvg( $svg ) { |
| 563 | $this->changed = true; |
| 564 | $this->svg = trim( $svg ); |
| 565 | } |
| 566 | |
| 567 | /** |
| 568 | * Gets the SVG image |
| 569 | * |
| 570 | * @param string $render if set to 'render' (default) and no SVG image exists, the function |
| 571 | * tries to generate it on the fly. |
| 572 | * Otherwise, if set to 'cached', and there is no SVG in the database |
| 573 | * cache, an empty string is returned. |
| 574 | * |
| 575 | * @return string XML-Document of the rendered SVG |
| 576 | */ |
| 577 | public function getSvg( $render = 'render' ) { |
| 578 | // Spaces will prevent the image from being displayed correctly in the browser |
| 579 | if ( !$this->svg && $this->rbi ) { |
| 580 | $this->svg = $this->rbi->getSvg(); |
| 581 | } |
| 582 | return trim( $this->svg ); |
| 583 | } |
| 584 | |
| 585 | /** |
| 586 | * @return string |
| 587 | */ |
| 588 | abstract protected function getMathTableName(); |
| 589 | |
| 590 | protected function getModeName(): Message { |
| 591 | return MediaWikiServices::getInstance() |
| 592 | ->get( 'Math.Config' ) |
| 593 | ->getRenderingModeName( $this->getMode() ); |
| 594 | } |
| 595 | |
| 596 | public function setInputType( string $inputType ) { |
| 597 | $this->inputType = $inputType; |
| 598 | } |
| 599 | |
| 600 | public function getInputType(): string { |
| 601 | return $this->inputType; |
| 602 | } |
| 603 | |
| 604 | protected function doCheck(): bool { |
| 605 | $checker = $this->getChecker(); |
| 606 | |
| 607 | if ( $checker->isValid() ) { |
| 608 | $this->setTex( $checker->getValidTex() ); |
| 609 | $this->texSecure = true; |
| 610 | return true; |
| 611 | } |
| 612 | |
| 613 | $checkerError = $checker->getError(); |
| 614 | $this->lastError = $checkerError === null ? |
| 615 | $this->getError( 'math_unknown_error' ) : |
| 616 | $this->getError( $checkerError->getKey(), ...$checkerError->getParams() ); |
| 617 | return false; |
| 618 | } |
| 619 | |
| 620 | protected function debug( string $msg ) { |
| 621 | $this->logger->debug( "$msg for \"{tex}\".", [ 'tex' => $this->userInputTex ] ); |
| 622 | } |
| 623 | |
| 624 | private function getCacheKey(): string { |
| 625 | return $this->cache->makeGlobalKey( |
| 626 | self::class, |
| 627 | $this->getInputHash() |
| 628 | ); |
| 629 | } |
| 630 | } |