Mobrovac has submitted this change and it was merged.

Change subject: Render all math tags in parallel
......................................................................


Render all math tags in parallel

Bug: T125543
Change-Id: Ia2febf2c0309e5de514445ad2aad58b7e5ce6837
---
M Math.hooks.php
M MathInputCheckRestbase.php
M MathMathML.php
M MathRenderer.php
M MathRestbaseInterface.php
M extension.json
M tests/MathRestBaseInterfaceTest.php
7 files changed, 180 insertions(+), 70 deletions(-)

Approvals:
  Mobrovac: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/Math.hooks.php b/Math.hooks.php
index bd2d07b..3a76d8a 100644
--- a/Math.hooks.php
+++ b/Math.hooks.php
@@ -9,6 +9,7 @@
 use MediaWiki\Logger\LoggerFactory;
 
 class MathHooks {
+       private static $tags = array();
        const MATHCACHEKEY = 'math=';
 
        public static function mathConstantToString( $value, array $defs, 
$prefix, $default ) {
@@ -179,22 +180,40 @@
         * @return array
         */
        static function mathTagHook( $content, $attributes, $parser ) {
-
+               static $n = 1;
                if ( trim( $content ) === '' ) { // bug 8372
                        return '';
                }
+               $marker = Parser::MARKER_PREFIX .
+                               '-postMath-' . sprintf( '%08X', $n ++ ) .
+                               Parser::MARKER_SUFFIX;
 
                $mode = self::mathModeToString( $parser->getUser()->getOption( 
'math' ) );
                // Indicate that this page uses math.
                // This affects the page caching behavior.
-               if ( is_callable( 'ParserOptions::getMath' ) ) {
-                       $parser->getOptions()->getMath();
-               } else {
-                       $parser->getOptions()->optionUsed( 'math' );
-               }
-
+               $parser->getOptions()->optionUsed( 'math' );
                $renderer = MathRenderer::getRenderer( $content, $attributes, 
$mode );
 
+               self::$tags[$marker] = array( $renderer, $parser );
+               $parser->getOutput()->addModuleStyles( array( 'ext.math.styles' 
) );
+               if ( $mode == 'mathml' ) {
+                       $parser->getOutput()->addModuleStyles( array( 
'ext.math.desktop.styles' ) );
+                       $parser->getOutput()->addModules( array( 
'ext.math.scripts' ) );
+               }
+               return $marker;
+
+       }
+
+       /**
+        * Callback function for the <math> parser hook.
+        *
+        * @param Parser $parser
+        * @param MathRenderer $renderer
+        * @return array
+        * @throws FatalError
+        * @throws MWException
+        */
+       private static function mathPostTagHook( $renderer, $parser ) {
                $checkResult = $renderer->checkTeX();
 
                if ( $checkResult !== true ) {
@@ -212,15 +231,11 @@
                }
                Hooks::run( 'MathFormulaPostRender',
                        array( $parser, &$renderer, &$renderedMath ) );// 
Enables indexing of math formula
-               $parser->getOutput()->addModuleStyles( array( 'ext.math.styles' 
) );
-               if ( $mode == 'mathml' ) {
-                       $parser->getOutput()->addModuleStyles( array( 
'ext.math.desktop.styles' ) );
-                       $parser->getOutput()->addModules( array( 
'ext.math.scripts' ) );
-               }
+
                // Writes cache if rendering was successful
                $renderer->writeCache();
 
-               return array( $renderedMath, "markerType" => 'nowiki' );
+               return $renderedMath;
        }
 
        /**
@@ -354,6 +369,29 @@
        }
 
        /**
+        * @param Parser $parser
+        * @param $text
+        * @return bool
+        */
+       public static function onParserBeforeTidy( &$parser, &$text ) {
+               $rbis = array();
+               foreach ( self::$tags as $key => $tag ){
+                       /** @var MathRenderer $renderer */
+                       $renderer = $tag[0];
+                       $rbi = new MathRestbaseInterface( $renderer->getTex(), 
$renderer->getInputType() );
+                       $renderer->setRestbaseInterface( $rbi );
+                       $rbis[] = $rbi;
+               }
+               MathRestbaseInterface::batchEvaluate( $rbis );
+               foreach ( self::$tags as $key => $tag ){
+                       $value = call_user_func_array( array( 
"MathHooks","mathPostTagHook" ), $tag );
+                       $text = str_replace( $key, $value, $text );
+               }
+               // This hook might be called multiple times. However one the 
tags are rendered the job is done.
+               self::$tags = array();
+               return true;
+       }
+       /**
         *
         * @global type $wgOut
         * @param type $toolbar
diff --git a/MathInputCheckRestbase.php b/MathInputCheckRestbase.php
index 8d21b63..d73d8d5 100644
--- a/MathInputCheckRestbase.php
+++ b/MathInputCheckRestbase.php
@@ -17,10 +17,16 @@
         * (performs no checking)
         * @param string $tex the TeX input string to be checked
         * @param string $type
+        * @param MathRestbaseInterface $ref
         */
-       public function __construct( $tex = '', $type = 'tex' ) {
+       public function __construct( $tex = '', $type = 'tex', &$ref = null ) {
                parent::__construct( $tex );
-               $this->restbaseInterface = new MathRestbaseInterface( $tex, 
$type );
+               if ( $ref ) {
+                       $this->restbaseInterface = $ref;
+               } else {
+                       $this->restbaseInterface = new MathRestbaseInterface( 
$tex, $type );
+                       $ref = $this->restbaseInterface;
+               }
        }
 
        /**
@@ -56,7 +62,7 @@
         * @return boolean
         */
        public function isValid() {
-               return $this->restbaseInterface->checkTeX();
+               return $this->restbaseInterface->getSuccess();
        }
 
        /**
diff --git a/MathMathML.php b/MathMathML.php
index 27acbf0..f669503 100644
--- a/MathMathML.php
+++ b/MathMathML.php
@@ -21,6 +21,7 @@
        /** @var boolean if false MathML output is not validated */
        private $XMLValidation = true;
        private $svgPath = false;
+       private $mathoidStyle;
 
        public function __construct( $tex = '', $params = array() ) {
                global $wgMathMathMLUrl;
@@ -79,14 +80,13 @@
        */
        public function render( $forceReRendering = false ) {
                if ( in_array( $this->inputType, $this->restbaseInputTypes ) && 
$this->mode == 'mathml' ) {
-                       $rbi = $this->rbi;
-                       if ( !$rbi ){
-                               $rbi = new MathRestbaseInterface( 
$this->getTex(), $this->getInputType() );
-                               $rbi->checkTeX();
+                       if ( !$this->rbi ){
+                               $this->rbi = new MathRestbaseInterface( 
$this->getTex(), $this->getInputType() );
                        }
+                       $rbi = $this->rbi;
                        if ( $rbi->getSuccess() ) {
                                $this->mathml = $rbi->getMathML();
-                               $this->svg = $rbi->getSvg();
+                               $this->mathoidStyle = $rbi->getMathoidStyle();
                                $this->svgPath = $rbi->getFullSvgUrl();
                        }
                        $this->changed = false;
@@ -378,11 +378,13 @@
                } else {
                        $class = $classOverride;
                }
-
+               if ( ! $this->mathoidStyle ) {
+                       $this->correctSvgStyle( $this->getSvg(), 
$this->mathoidStyle );
+               }
                // TODO: move the common styles to the global stylesheet!
                $style = 'background-image: url(\''. $url .
-                                '\'); background-repeat: no-repeat; 
background-size: 100% 100%;';
-               $this->correctSvgStyle( $this->getSvg(), $style );
+                        '\'); background-repeat: no-repeat; background-size: 
100% 100%; '.
+                       $this->mathoidStyle;
                if ( $class ) {
                        $attribs['class'] = $class;
                }
diff --git a/MathRenderer.php b/MathRenderer.php
index 4da750d..8781b86 100644
--- a/MathRenderer.php
+++ b/MathRenderer.php
@@ -381,6 +381,13 @@
        }
 
        /**
+        * @param MathRestbaseInterface $param
+        */
+       public function setRestbaseInterface( $param ) {
+               $this->rbi = $param;
+       }
+
+       /**
         * Returns sanitized attributes
         *
         * @param string $tag element name
@@ -587,12 +594,11 @@
                                        return true;
                                }
                        }
-                       $checker = new MathInputCheckRestbase( $this->tex, 
$this->getInputType() );
+                       $checker = new MathInputCheckRestbase( $this->tex, 
$this->getInputType(), $this->rbi );
                        try {
                                if ( $checker->isValid() ) {
                                        $this->setTex( $checker->getValidTex() 
);
                                        $this->texSecure = true;
-                                       $this->rbi = $checker->getRbi();
                                        return true;
                                }
                        } catch ( MWException $e ) {
@@ -655,6 +661,9 @@
         */
        public function getSvg( /** @noinspection PhpUnusedParameterInspection 
*/ $render = 'render' ) {
                // Spaces will prevent the image from being displayed correctly 
in the browser
+               if ( !$this->svg && $this->rbi ){
+                       $this->svg = $this->rbi->getSvg();
+               }
                return trim( $this->svg );
        }
 
diff --git a/MathRestbaseInterface.php b/MathRestbaseInterface.php
index 2e24e22..2273c2b 100644
--- a/MathRestbaseInterface.php
+++ b/MathRestbaseInterface.php
@@ -16,6 +16,8 @@
        private $success;
        private $identifiers;
        private $error;
+       private $mathoidStyle;
+       private $mml;
 
        /**
         * MathRestbaseInterface constructor.
@@ -32,7 +34,10 @@
         * @throws MWException
         */
        public function getMathML() {
-               return $this->getContent( 'mml' );
+               if ( !$this->mml ){
+                       $this->mml = $this->getContent( 'mml' );
+               }
+               return $this->mml;
        }
 
        private function getContent( $type ) {
@@ -44,6 +49,9 @@
                $serviceClient = $this->getServiceClient();
                $response = $serviceClient->run( $request );
                if ( $response['code'] === 200 ) {
+                       if ( array_key_exists( 'x-mathoid-style', 
$response['headers'] ) ) {
+                               $this->mathoidStyle =  
$response['headers']['x-mathoid-style'];
+                       }
                        return $response['body'];
                }
                $this->log()->error( 'Restbase math server problem:', array(
@@ -64,27 +72,9 @@
        }
 
        public function checkTeX() {
-               $postData = array(
-                       'type' => $this->type,
-                       'q'    => $this->tex
-               );
-               $requestResult = $this->makeRestbaseCheckRequest( $postData, 
$res );
-               $json = json_decode( $res );
-               if ( $requestResult ) {
-                       $this->success = $json->success;
-                       $this->checkedTex = $json->checked;
-                       $this->identifiers = $json->identifiers;
-                       return true;
-               } else {
-                       if ( isset( $json->detail ) && isset( 
$json->detail->success ) ) {
-                               $this->success = $json->detail->success;
-                               $this->error = $json->detail;
-                       } else {
-                               $this->success = false;
-                               $this->setErrorMessage( 'Math extension cannot 
connect to Restbase.' );
-                       }
-                       return false;
-               }
+               $request = $this->getCheckRequest();
+               $requestResult = $this->executeRestbaseCheckRequest( $request );
+               return $this->evaluateRestbaseCheckResponse( $requestResult );
        }
 
        /**
@@ -92,33 +82,47 @@
         * Generates error messages on failure
         * @see Http::post()
         *
-        * @param string $post the encoded post request
-        * @param mixed $res the result
+        * @param array $request the request object
         * @return bool success
         */
-       private function makeRestbaseCheckRequest( $post, &$res ) {
+       private function executeRestbaseCheckRequest( $request ) {
                $res = null;
-               $request = array(
-                       'method' => 'POST',
-                       'body'   => $post
-               );
                $serviceClient = $this->getServiceClient();
-               $request['url'] = $this->getUrl( 
"media/math/check/{$this->type}" );
-               $response = $serviceClient->run( $request );
-               if ( $response['code'] === 200 ) {
-                       $res = $response['body'];
-                       $headers = $response['headers'];
-                       $this->hash = $headers['x-resource-location'];
-                       return true;
-               } else {
-                       $res = $response['body'];
+               $response =  $serviceClient->run( $request );
+               if ( $response['code'] !== 200 ) {
                        $this->log()->info( 'Tex check failed:', array(
-                               'post'     => $post,
-                               'error'    => $response['error'],
-                               'url'      => $request['url']
+                                       'post'  => $request['body'],
+                                       'error' => $response['error'],
+                                       'url'   => $request['url']
                        ) );
-                       return false;
                }
+               return $response;
+
+       }
+
+       /**
+        * @param array $rbis array of MathRestbaseInterface instances
+        */
+       public static function batchEvaluate( $rbis ) {
+               if ( count( $rbis ) == 0 ){
+                       return;
+               }
+               $requests = array();
+               /** @var MathRestbaseInterface $first */
+               $first = $rbis[0];
+               $serviceClient = $first->getServiceClient();
+               foreach ( $rbis as $rbi ) {
+                       /** @var MathRestbaseInterface $rbi */
+                       $requests[] = $rbi->getCheckRequest();
+               }
+               $results = $serviceClient->runMulti( $requests );
+               $i = 0;
+               foreach ( $results as $response ) {
+                       /** @var MathRestbaseInterface $rbi */
+                       $rbi = $rbis[$i ++];
+                       $rbi->evaluateRestbaseCheckResponse( $response );
+               }
+
        }
 
        private function getServiceClient() {
@@ -258,6 +262,9 @@
         * @return boolean
         */
        public function getSuccess() {
+               if ( $this->success === null ) {
+                       $this->checkTeX();
+               }
                return $this->success;
        }
 
@@ -293,4 +300,51 @@
                $this->error = (object)array( 'error' => (object)array( 
'message' => $msg ) );
        }
 
+       /**
+        * @return array
+        * @throws MWException
+        */
+       public function getCheckRequest() {
+               $request = array(
+                               'method' => 'POST',
+                               'body'   => array(
+                                               'type' => $this->type,
+                                               'q'    => $this->tex
+                               ),
+                               'url'    => $this->getUrl( 
"media/math/check/{$this->type}" )
+               );
+               return $request;
+       }
+
+       /**
+        * @param $response
+        * @return bool
+        */
+       public function evaluateRestbaseCheckResponse( $response ) {
+               $json = json_decode( $response['body'] );
+               if ( $response['code'] === 200 ) {
+                       $headers = $response['headers'];
+                       $this->hash = $headers['x-resource-location'];
+                       $this->success = $json->success;
+                       $this->checkedTex = $json->checked;
+                       $this->identifiers = $json->identifiers;
+                       return true;
+               } else {
+                       if ( isset( $json->detail ) && isset( 
$json->detail->success ) ) {
+                               $this->success = $json->detail->success;
+                               $this->error = $json->detail;
+                       } else {
+                               $this->success = false;
+                               $this->setErrorMessage( 'Math extension cannot 
connect to Restbase.' );
+                       }
+                       return false;
+               }
+       }
+
+       /**
+        * @return mixed
+        */
+       public function getMathoidStyle() {
+               return $this->mathoidStyle;
+       }
 }
diff --git a/extension.json b/extension.json
index edc8732..9db5772 100644
--- a/extension.json
+++ b/extension.json
@@ -68,6 +68,9 @@
                ],
                "WikibaseRepoDataTypes": [
                        "MathWikidataHook::onWikibaseRepoDataTypes"
+               ],
+               "ParserBeforeTidy":[
+                       "MathHooks::onParserBeforeTidy"
                ]
        },
        "config": {
diff --git a/tests/MathRestBaseInterfaceTest.php 
b/tests/MathRestBaseInterfaceTest.php
index 5bb9d0f..45d7311 100644
--- a/tests/MathRestBaseInterfaceTest.php
+++ b/tests/MathRestBaseInterfaceTest.php
@@ -38,7 +38,6 @@
        public function testSuccess() {
                $input = '\\sin x^2';
                $rbi = new MathRestbaseInterface( $input );
-               $this->assertTrue( $rbi->checkTeX(), "Assuming that $input is 
valid input." );
                $this->assertTrue( $rbi->getSuccess(), "Assuming that $input is 
valid input." );
                $this->assertEquals( '\\sin x^{2}', $rbi->getCheckedTex() );
                $this->assertContains( '<mi>sin</mi>', $rbi->getMathML() );
@@ -52,7 +51,6 @@
        public function testFail() {
                $input = '\\sin\\newcommand';
                $rbi = new MathRestbaseInterface( $input );
-               $this->assertFalse( $rbi->checkTeX(), "Assuming that $input is 
invalid input." );
                $this->assertFalse( $rbi->getSuccess(), "Assuming that $input 
is invalid input." );
                $this->assertEquals( '', $rbi->getCheckedTex() );
                $this->assertEquals( 'Illegal TeX function', 
$rbi->getError()->error->message );

-- 
To view, visit https://gerrit.wikimedia.org/r/267878
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ia2febf2c0309e5de514445ad2aad58b7e5ce6837
Gerrit-PatchSet: 11
Gerrit-Project: mediawiki/extensions/Math
Gerrit-Branch: master
Gerrit-Owner: Physikerwelt <w...@physikerwelt.de>
Gerrit-Reviewer: Aaron Schulz <asch...@wikimedia.org>
Gerrit-Reviewer: GWicke <gwi...@wikimedia.org>
Gerrit-Reviewer: Mobrovac <mobro...@wikimedia.org>
Gerrit-Reviewer: Physikerwelt <w...@physikerwelt.de>
Gerrit-Reviewer: TheDJ <hartman.w...@gmail.com>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to