@@ -528,7 +528,7 @@ class TruetypeFonts(Fonts):
528528 A generic base class for all font setups that use Truetype fonts
529529 (through ft2font)
530530 """
531- basepath = os .path .join ( get_data_path (), 'fonts' , 'ttf' )
531+ basepath = os .path .join ( get_data_path (), 'fonts' )
532532
533533 class CachedFont :
534534 def __init__ (self , font ):
@@ -665,7 +665,7 @@ def __init__(self, *args, **kwargs):
665665 TruetypeFonts .__init__ (self , * args , ** kwargs )
666666 if not len (self .fontmap ):
667667 for key , val in self ._fontmap .iteritems ():
668- fullpath = os .path .join (self .basepath , val + ".ttf" )
668+ fullpath = os .path .join (self .basepath , 'ttf' , val + ".ttf" )
669669 self .fontmap [key ] = fullpath
670670 self .fontmap [val ] = fullpath
671671
@@ -750,7 +750,8 @@ class UnicodeFonts(TruetypeFonts):
750750 """
751751
752752 fontmap = {}
753-
753+ use_cmex = True
754+
754755 def __init__ (self , * args , ** kwargs ):
755756 # This must come first so the backend's owner is set correctly
756757 if rcParams ['mathtext.fallback_to_cm' ]:
@@ -772,18 +773,20 @@ def __init__(self, *args, **kwargs):
772773 def _get_glyph (self , fontname , sym , fontsize ):
773774 found_symbol = False
774775
775- uniindex = latex_to_cmex .get (sym )
776- if uniindex is not None :
777- fontname = 'ex'
778- found_symbol = True
779- else :
776+ if self .use_cmex :
777+ uniindex = latex_to_cmex .get (sym )
778+ if uniindex is not None :
779+ fontname = 'ex'
780+ found_symbol = True
781+
782+ if not found_symbol :
780783 try :
781784 uniindex = get_unicode_index (sym )
782785 found_symbol = True
783786 except ValueError :
784787 uniindex = ord ('?' )
785788 warn ("No TeX to unicode mapping for '%s'" %
786- sym .encode ('ascii' , 'replace ' ),
789+ sym .encode ('ascii' , 'backslashreplace ' ),
787790 MathTextWarning )
788791
789792 # Only characters in the "Letter" class should be italicized in 'it'
@@ -804,7 +807,7 @@ def _get_glyph(self, fontname, sym, fontsize):
804807 except KeyError :
805808 warn ("Font '%s' does not have a glyph for '%s'" %
806809 (cached_font .font .postscript_name ,
807- sym .encode ('ascii' , 'replace ' )),
810+ sym .encode ('ascii' , 'backslashreplace ' )),
808811 MathTextWarning )
809812 found_symbol = False
810813
@@ -815,6 +818,7 @@ def _get_glyph(self, fontname, sym, fontsize):
815818 return self .cm_fallback ._get_glyph (fontname , sym , fontsize )
816819 else :
817820 warn ("Substituting with a dummy symbol." , MathTextWarning )
821+ fontname = 'rm'
818822 new_fontname = fontname
819823 cached_font = self ._get_font (fontname )
820824 uniindex = 0xA4 # currency character, for lack of anything better
@@ -829,6 +833,71 @@ def get_sized_alternatives_for_symbol(self, fontname, sym):
829833 return self .cm_fallback .get_sized_alternatives_for_symbol (
830834 fontname , sym )
831835 return [(fontname , sym )]
836+
837+ class StixFonts (UnicodeFonts ):
838+ _fontmap = { 'rm' : ('STIXGeneral' , 'otf' ),
839+ 'tt' : ('VeraMono' , 'ttf' ),
840+ 'it' : ('STIXGeneralItalic' , 'otf' ),
841+ 'bf' : ('STIXGeneralBol' , 'otf' ),
842+ 'sf' : ('Vera' , 'ttf' ),
843+ 'nonunirm' : ('STIXNonUni' , 'otf' ),
844+ 'nonuniit' : ('STIXNonUniIta' , 'otf' ),
845+ 'nonunibf' : ('STIXNonUniBol' , 'otf' ),
846+
847+ 0 : ('STIXGeneral' , 'otf' ),
848+ 1 : ('STIXSiz1Sym' , 'otf' ),
849+ 2 : ('STIXSiz2Sym' , 'otf' ),
850+ 3 : ('STIXSiz3Sym' , 'otf' ),
851+ 4 : ('STIXSiz4Sym' , 'otf' ),
852+ 5 : ('STIXSiz5Sym' , 'otf' )
853+ }
854+ fontmap = {}
855+ use_cmex = False
856+ cm_fallback = False
857+
858+ def __init__ (self , * args , ** kwargs ):
859+ TruetypeFonts .__init__ (self , * args , ** kwargs )
860+ if not len (self .fontmap ):
861+ for key , (name , ext ) in self ._fontmap .iteritems ():
862+ fullpath = os .path .join (self .basepath , ext , name + "." + ext )
863+ self .fontmap [key ] = fullpath
864+ self .fontmap [name ] = fullpath
865+
866+ def _get_glyph (self , fontname , sym , fontsize ):
867+ # Handle calligraphic letters
868+ if fontname == 'cal' :
869+ if len (sym ) != 1 or ord (sym ) < ord ('A' ) or ord (sym ) > ord ('Z' ):
870+ raise ValueError (r"Sym '%s' is not available in \mathcal font" % sym )
871+ fontname = 'nonuniit'
872+ sym = unichr (ord (sym ) + 0xe22d - ord ('A' ))
873+
874+ # Handle private use area glyphs
875+ if (fontname in ('it' , 'rm' , 'bf' ) and
876+ len (sym ) == 1 and ord (sym ) >= 0xe000 and ord (sym ) <= 0xf8ff ):
877+ fontname = 'nonuni' + fontname
878+
879+ return UnicodeFonts ._get_glyph (self , fontname , sym , fontsize )
880+
881+ _size_alternatives = {}
882+ def get_sized_alternatives_for_symbol (self , fontname , sym ):
883+ alternatives = self ._size_alternatives .get (sym )
884+ if alternatives :
885+ return alternatives
886+
887+ alternatives = []
888+ try :
889+ uniindex = get_unicode_index (sym )
890+ except ValueError :
891+ return [(fontname , sym )]
892+
893+ for i in range (6 ):
894+ cached_font = self ._get_font (i )
895+ glyphindex = cached_font .charmap .get (uniindex )
896+ if glyphindex is not None :
897+ alternatives .append ((i , unichr (uniindex )))
898+
899+ self ._size_alternatives [sym ] = alternatives
900+ return alternatives
832901
833902class StandardPsFonts (Fonts ):
834903 """
@@ -1091,7 +1160,7 @@ def __init__(self, c, state):
10911160 Node .__init__ (self )
10921161 self .c = c
10931162 self .font_output = state .font_output
1094- assert isinstance (state .font , str )
1163+ assert isinstance (state .font , ( str , unicode , int ) )
10951164 self .font = state .font
10961165 self .fontsize = state .fontsize
10971166 self .dpi = state .dpi
@@ -1876,7 +1945,7 @@ def __init__(self):
18761945 ) | Error (r"Expected \hspace{n}" ))
18771946 ).setParseAction (self .customspace ).setName ('customspace' )
18781947
1879- symbol = (Regex (r "([a-zA-Z0-9 +\-*/<>=:,.;!'@()])|(\\[%${}\[\]])" )
1948+ symbol = (Regex (ur "([a-zA-Z0-9 +\-*/<>=:,.;!'@()\u0080-\uffff ])|(\\[%${}\[\]])" )
18801949 | Combine (
18811950 bslash
18821951 + oneOf (tex2uni .keys ())
@@ -2508,10 +2577,15 @@ def parse(self, s, dpi = 72, prop = None):
25082577 font_output = StandardPsFonts (prop )
25092578 else :
25102579 backend = self ._backend_mapping [self ._output ]()
2511- if rcParams ['mathtext.use_cm' ]:
2580+ fontset = rcParams ['mathtext.fontset' ]
2581+ if fontset == 'cm' :
25122582 font_output = BakomaFonts (prop , backend )
2513- else :
2583+ elif fontset == 'stix' :
2584+ font_output = StixFonts (prop , backend )
2585+ elif fontset == 'custom' :
25142586 font_output = UnicodeFonts (prop , backend )
2587+ else :
2588+ raise ValueError ("mathtext.fontset must be either 'cm', 'stix', or 'custom'" )
25152589
25162590 fontsize = prop .get_size_in_points ()
25172591
0 commit comments