mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Math
synced 2024-09-23 10:21:31 +00:00
Fix mathcal in chrome
* map to unicode chars Bug: T352536 Change-Id: Iab04043df5cc04484d348b0c896a50c94ef79c16
This commit is contained in:
parent
001e11bd7a
commit
3d0dfe1e43
|
@ -202,7 +202,7 @@ class BaseParsing {
|
||||||
|
|
||||||
$menclose = new MMLmenclose( "", [ "notation" => $notation ] );
|
$menclose = new MMLmenclose( "", [ "notation" => $notation ] );
|
||||||
$inner = $menclose->encapsulateRaw(
|
$inner = $menclose->encapsulateRaw(
|
||||||
$node->getArg2()->renderMML() ) . $mpAdded->encapsulateRaw( $node->getArg1()->renderMML() );
|
$node->getArg2()->renderMML() ) . $mpAdded->encapsulateRaw( $node->getArg1()->renderMML() );
|
||||||
return $mrow->encapsulateRaw( $msup->encapsulateRaw( $inner ) );
|
return $mrow->encapsulateRaw( $msup->encapsulateRaw( $inner ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +236,7 @@ class BaseParsing {
|
||||||
$inner = $mrow->encapsulateRaw( $whatIsThis .
|
$inner = $mrow->encapsulateRaw( $whatIsThis .
|
||||||
$mstyle->encapsulateRaw( $mrow->encapsulateRaw( $node->getArg1()->renderMML() ) ) ) .
|
$mstyle->encapsulateRaw( $mrow->encapsulateRaw( $node->getArg1()->renderMML() ) ) ) .
|
||||||
$mrow->encapsulateRaw( $whatIsThis . $mstyle->encapsulateRaw(
|
$mrow->encapsulateRaw( $whatIsThis . $mstyle->encapsulateRaw(
|
||||||
$mrow->encapsulateRaw( $node->getArg2()->renderMML() ) ) );
|
$mrow->encapsulateRaw( $node->getArg2()->renderMML() ) ) );
|
||||||
|
|
||||||
return $mrow->encapsulateRaw( $mfrac->encapsulateRaw( $inner ) );
|
return $mrow->encapsulateRaw( $mfrac->encapsulateRaw( $inner ) );
|
||||||
}
|
}
|
||||||
|
@ -253,7 +253,7 @@ class BaseParsing {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function genFrac( $node, $passedArgs, $operatorContent, $name,
|
public static function genFrac( $node, $passedArgs, $operatorContent, $name,
|
||||||
$left = null, $right = null, $thick = null, $style = null ) {
|
$left = null, $right = null, $thick = null, $style = null ) {
|
||||||
// Actually this is in AMSMethods, consider refactoring left, right, thick, style
|
// Actually this is in AMSMethods, consider refactoring left, right, thick, style
|
||||||
$bm = new BaseMethods();
|
$bm = new BaseMethods();
|
||||||
$ret = $bm->checkAndParseDelimiter( $name, $node, $passedArgs, $operatorContent, true );
|
$ret = $bm->checkAndParseDelimiter( $name, $node, $passedArgs, $operatorContent, true );
|
||||||
|
@ -527,14 +527,14 @@ class BaseParsing {
|
||||||
$mspace = new MMLmspace( "", [ "width" => "0px","height" => ".25em",
|
$mspace = new MMLmspace( "", [ "width" => "0px","height" => ".25em",
|
||||||
"depth" => "0px","mathbackground" => "black" ] );
|
"depth" => "0px","mathbackground" => "black" ] );
|
||||||
return $mtext->encapsulateRaw( " " ) .
|
return $mtext->encapsulateRaw( " " ) .
|
||||||
$mrowRel->encapsulateRaw( $mover->encapsulateRaw(
|
$mrowRel->encapsulateRaw( $mover->encapsulateRaw(
|
||||||
$mrowOp->encapsulateRaw(
|
$mrowOp->encapsulateRaw(
|
||||||
$mrowOrd->encapsulateRaw( $mpadded->encapsulateRaw(
|
$mrowOrd->encapsulateRaw( $mpadded->encapsulateRaw(
|
||||||
$mo->encapsulateRaw( "⟵" ) ) ) .
|
$mo->encapsulateRaw( "⟵" ) ) ) .
|
||||||
$mspace->getEmpty() ) .
|
$mspace->getEmpty() ) .
|
||||||
$mrowOrd->encapsulateRaw(
|
$mrowOrd->encapsulateRaw(
|
||||||
$mo->encapsulateRaw( "⟶" )
|
$mo->encapsulateRaw( "⟶" )
|
||||||
) ) );
|
) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removed all token based parsing, since macro resolution for the supported macros can be hardcoded in php
|
// Removed all token based parsing, since macro resolution for the supported macros can be hardcoded in php
|
||||||
|
@ -672,7 +672,7 @@ class BaseParsing {
|
||||||
if ( $node instanceof Fun2 ) {
|
if ( $node instanceof Fun2 ) {
|
||||||
return $start . $mfrac->encapsulateRaw( $mrow->encapsulateRaw(
|
return $start . $mfrac->encapsulateRaw( $mrow->encapsulateRaw(
|
||||||
$node->getArg1()->renderMML() ) . $mrow->encapsulateRaw( $node->getArg2()->renderMML() ) )
|
$node->getArg1()->renderMML() ) . $mrow->encapsulateRaw( $node->getArg2()->renderMML() ) )
|
||||||
. $tail;
|
. $tail;
|
||||||
}
|
}
|
||||||
$inner = "";
|
$inner = "";
|
||||||
foreach ( $node->getArgs() as $arg ) {
|
foreach ( $node->getArgs() as $arg ) {
|
||||||
|
@ -842,10 +842,16 @@ class BaseParsing {
|
||||||
$mrow = new MMLmrow( TexClass::ORD, [] );
|
$mrow = new MMLmrow( TexClass::ORD, [] );
|
||||||
$args = MMLParsingUtil::getFontArgs( $name, $mathvariant, $passedArgs );
|
$args = MMLParsingUtil::getFontArgs( $name, $mathvariant, $passedArgs );
|
||||||
$state = [];
|
$state = [];
|
||||||
|
|
||||||
|
// Unicode fixes for the operators
|
||||||
if ( $mathvariant == Variants::DOUBLESTRUCK ) {
|
if ( $mathvariant == Variants::DOUBLESTRUCK ) {
|
||||||
// Unicode fix for the operators
|
|
||||||
$state = [ "double-struck-literals" => true ];
|
$state = [ "double-struck-literals" => true ];
|
||||||
|
} elseif ( $mathvariant == Variants::CALLIGRAPHIC ) {
|
||||||
|
$state = [ "calligraphic" => true ];
|
||||||
|
} elseif ( $mathvariant == Variants::BOLDCALLIGRAPHIC ) {
|
||||||
|
$state = [ "bold-calligraphic" => true ];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $node instanceof Fun1nb ) {
|
if ( $node instanceof Fun1nb ) {
|
||||||
// Only one mrow from Fun1nb !?
|
// Only one mrow from Fun1nb !?
|
||||||
return $mrow->encapsulateRaw( $node->getArg()->renderMML( $args, $state ) );
|
return $mrow->encapsulateRaw( $node->getArg()->renderMML( $args, $state ) );
|
||||||
|
@ -979,7 +985,7 @@ class BaseParsing {
|
||||||
}
|
}
|
||||||
$mrow = new MMLmrow( TexClass::ORD, [] );
|
$mrow = new MMLmrow( TexClass::ORD, [] );
|
||||||
$opParsed = ( $operatorContent != null && $operatorContent["limits"] )
|
$opParsed = ( $operatorContent != null && $operatorContent["limits"] )
|
||||||
? $operatorContent["limits"]->renderMML( $argsOp ) : "";
|
? $operatorContent["limits"]->renderMML( $argsOp ) : "";
|
||||||
|
|
||||||
if ( $node instanceof DQ ) {
|
if ( $node instanceof DQ ) {
|
||||||
$munder = new MMLmunder();
|
$munder = new MMLmunder();
|
||||||
|
@ -987,7 +993,7 @@ class BaseParsing {
|
||||||
} elseif ( $node instanceof FQ ) {
|
} elseif ( $node instanceof FQ ) {
|
||||||
$munderOver = new MMLmunderover();
|
$munderOver = new MMLmunderover();
|
||||||
return $munderOver->encapsulateRaw( $opParsed . $mrow->encapsulateRaw( $node->getDown()->renderMML() )
|
return $munderOver->encapsulateRaw( $opParsed . $mrow->encapsulateRaw( $node->getDown()->renderMML() )
|
||||||
. $mrow->encapsulateRaw( $node->getUp()->renderMML() ) );
|
. $mrow->encapsulateRaw( $node->getUp()->renderMML() ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1036,7 +1042,8 @@ class BaseParsing {
|
||||||
$end2 = $mrowEnd->encapsulateRaw( $operatorContent["sideset"]->getUp()->renderMML() );
|
$end2 = $mrowEnd->encapsulateRaw( $operatorContent["sideset"]->getUp()->renderMML() );
|
||||||
|
|
||||||
return $mmlMrow->encapsulateRaw( $mmlMunderOver->encapsulateRaw( $mstyle->encapsulateRaw(
|
return $mmlMrow->encapsulateRaw( $mmlMunderOver->encapsulateRaw( $mstyle->encapsulateRaw(
|
||||||
$mmlMultiscripts->encapsulateRaw( $opParsed . $in2 . "<mprescripts/>" . $in1 ) ) . $end1 . $end2 ) );
|
$mmlMultiscripts->encapsulateRaw( $opParsed . $in2 . "<mprescripts/>" . $in1 ) )
|
||||||
|
. $end1 . $end2 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
$merror = new MMLmerror();
|
$merror = new MMLmerror();
|
||||||
|
|
|
@ -126,9 +126,33 @@ class MMLParsingUtil {
|
||||||
'y' => '𝕪', 'z' => '𝕫'
|
'y' => '𝕪', 'z' => '𝕫'
|
||||||
];
|
];
|
||||||
|
|
||||||
// Replace each character in the input string with its double-struck Unicode equivalent
|
return self::matchAlphanumeric( $inputString, $map );
|
||||||
return preg_replace_callback( '/[A-Za-z0-9]/', static function ( $matches ) use ( $map ) {
|
}
|
||||||
return $map[$matches[0]] ?? $matches[0];
|
|
||||||
|
public static function mapToCaligraphicUnicode( $inputString ) {
|
||||||
|
$map = [
|
||||||
|
'0' => '𝟎', '1' => '𝟏', '2' => '𝟐', '3' => '𝟑', '4' => '𝟒',
|
||||||
|
'5' => '𝟓', '6' => '𝟔', '7' => '𝟕', '8' => '𝟖', '9' => '𝟗',
|
||||||
|
'A' => '𝒜', 'B' => 'ℬ', 'C' => '𝒞', 'D' => '𝒟', 'E' => 'ℰ',
|
||||||
|
'F' => 'ℱ', 'G' => '𝒢', 'H' => 'ℋ', 'I' => 'ℐ', 'J' => '𝒥',
|
||||||
|
'K' => '𝒦', 'L' => 'ℒ', 'M' => 'ℳ', 'N' => '𝒩', 'O' => '𝒪',
|
||||||
|
'P' => '𝒫', 'Q' => '𝒬', 'R' => 'ℛ', 'S' => '𝒮', 'T' => '𝒯',
|
||||||
|
'U' => '𝒰', 'V' => '𝒱', 'W' => '𝒲', 'X' => '𝒳', 'Y' => '𝒴',
|
||||||
|
'Z' => '𝒵', 'a' => '𝒶', 'b' => '𝒷', 'c' => '𝒸', 'd' => '𝒹',
|
||||||
|
'e' => 'ℯ', 'f' => '𝒻', 'g' => 'ℊ', 'h' => '𝒽', 'i' => '𝒾',
|
||||||
|
'j' => '𝒿', 'k' => '𝓀', 'l' => '𝓁', 'm' => '𝓂', 'n' => '𝓃',
|
||||||
|
'o' => 'ℴ', 'p' => '𝓅', 'q' => '𝓆', 'r' => '𝓇', 's' => '𝓈',
|
||||||
|
't' => '𝓉', 'u' => '𝓊', 'v' => '𝓋', 'w' => '𝓌', 'x' => '𝓍',
|
||||||
|
'y' => '𝓎', 'z' => '𝓏'
|
||||||
|
];
|
||||||
|
|
||||||
|
return self::matchAlphanumeric( $inputString, $map );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function matchAlphanumeric( $inputString, $map ) {
|
||||||
|
// Replace each character in the input string with its caligraphic Unicode equivalent
|
||||||
|
return preg_replace_callback( '/[A-Za-z0-9]/u', static function ( $matches ) use ( $map ) {
|
||||||
|
return $map[$matches[0]] ?? $matches[0];
|
||||||
}, $inputString );
|
}, $inputString );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,16 @@ class Literal extends TexNode {
|
||||||
array_push( $this->extendedLiterals, '\\infty', '\\emptyset' );
|
array_push( $this->extendedLiterals, '\\infty', '\\emptyset' );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function changeInputDoubleStruckChars( $input, $state ) {
|
public function changeUnicodeFontInput( $input, $state ) {
|
||||||
/** If it's definitely a literal, and it is double struck, map it to double-struck unicode
|
/**
|
||||||
* for correct rendering in Chrome, see https://phabricator.wikimedia.org/T352196
|
* In some font modifications, it is required to explicitly use unicode
|
||||||
|
* characters instead of (only) attributes in MathML to indicate the font.
|
||||||
|
* This is mostly because of Chrome behaviour. I.e. see: https://phabricator.wikimedia.org/T352196
|
||||||
*/
|
*/
|
||||||
if ( isset( $state["double-struck-literals"] ) ) {
|
if ( isset( $state["double-struck-literals"] ) ) {
|
||||||
return MMLParsingUtil::mapToDoubleStruckUnicode( $input );
|
return MMLParsingUtil::mapToDoubleStruckUnicode( $input );
|
||||||
|
} elseif ( isset( $state["calligraphic"] ) ) {
|
||||||
|
return MMLParsingUtil::mapToCaligraphicUnicode( $input );
|
||||||
}
|
}
|
||||||
return $input;
|
return $input;
|
||||||
}
|
}
|
||||||
|
@ -48,7 +52,7 @@ class Literal extends TexNode {
|
||||||
}
|
}
|
||||||
if ( is_numeric( $this->arg ) ) {
|
if ( is_numeric( $this->arg ) ) {
|
||||||
$mn = new MMLmn( "", $arguments );
|
$mn = new MMLmn( "", $arguments );
|
||||||
return $mn->encapsulateRaw( $this->changeInputDoubleStruckChars( $this->arg, $state ) );
|
return $mn->encapsulateRaw( $this->changeUnicodeFontInput( $this->arg, $state ) );
|
||||||
}
|
}
|
||||||
// is important to split and find chars within curly and differentiate, see tc 459
|
// is important to split and find chars within curly and differentiate, see tc 459
|
||||||
$foundOperatorContent = MMLutil::initalParseLiteralExpression( $this->arg );
|
$foundOperatorContent = MMLutil::initalParseLiteralExpression( $this->arg );
|
||||||
|
@ -95,8 +99,8 @@ class Literal extends TexNode {
|
||||||
|
|
||||||
// Sieve for Makros
|
// Sieve for Makros
|
||||||
$ret = BaseMethods::checkAndParse( $inputP, $arguments,
|
$ret = BaseMethods::checkAndParse( $inputP, $arguments,
|
||||||
array_merge( $operatorContent ?? [], $state ?? [] ),
|
array_merge( $operatorContent ?? [], $state ?? [] ),
|
||||||
$this, false );
|
$this, false );
|
||||||
if ( $ret ) {
|
if ( $ret ) {
|
||||||
|
|
||||||
return $ret;
|
return $ret;
|
||||||
|
@ -114,7 +118,7 @@ class Literal extends TexNode {
|
||||||
|
|
||||||
// If falling through all sieves just create an MI element
|
// If falling through all sieves just create an MI element
|
||||||
$mi = new MMLmi( "", $arguments );
|
$mi = new MMLmi( "", $arguments );
|
||||||
return $mi->encapsulateRaw( $this->changeInputDoubleStruckChars( $input, $state ) ); // $this->arg
|
return $mi->encapsulateRaw( $this->changeUnicodeFontInput( $input, $state ) ); // $this->arg
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -162,7 +166,7 @@ class Literal extends TexNode {
|
||||||
if ( preg_match( $regexp, $s ) == 1 ) {
|
if ( preg_match( $regexp, $s ) == 1 ) {
|
||||||
return [ $s ];
|
return [ $s ];
|
||||||
} elseif ( in_array( $s, $lit, true ) ) {
|
} elseif ( in_array( $s, $lit, true ) ) {
|
||||||
return [ $s ];
|
return [ $s ];
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,14 @@ use MediaWikiUnitTestCase;
|
||||||
* @covers \MediaWiki\Extension\Math\WikiTexVC\TexVC
|
* @covers \MediaWiki\Extension\Math\WikiTexVC\TexVC
|
||||||
*/
|
*/
|
||||||
class MMLRenderTest extends MediaWikiUnitTestCase {
|
class MMLRenderTest extends MediaWikiUnitTestCase {
|
||||||
|
public function testMathCalUnicode() {
|
||||||
|
$input = "\\mathcal{O}, \\mathcal{K}, \\mathcal{t}, \\mathcal{c}";
|
||||||
|
$mathMLtexVC = $this->generateMML( $input );
|
||||||
|
$this->assertStringContainsString( '𝒪', $mathMLtexVC );
|
||||||
|
$this->assertStringContainsString( '𝒦', $mathMLtexVC );
|
||||||
|
$this->assertStringContainsString( '𝓉', $mathMLtexVC );
|
||||||
|
$this->assertStringContainsString( '𝒸', $mathMLtexVC );
|
||||||
|
}
|
||||||
|
|
||||||
public function testDoubleStruckLiteralUnicode() {
|
public function testDoubleStruckLiteralUnicode() {
|
||||||
$input = "\\mathbb{Q}, \\R, \\Complex, \\mathbb{4}";
|
$input = "\\mathbb{Q}, \\R, \\Complex, \\mathbb{4}";
|
||||||
|
|
Loading…
Reference in a new issue