@@ -850,52 +850,41 @@ def get_underline_thickness(self, font, fontsize, dpi):
850850# Percentage of x-height of additional horiz. space after sub/superscripts
851851SCRIPT_SPACE = 0.3
852852# Percentage of x-height that sub/superscripts drop below the baseline
853- SUBDROP = 0.4
853+ SUBDROP = 0.3
854854# Percentage of x-height that superscripts drop below the baseline
855855SUP1 = 0.7
856856# Percentage of x-height that subscripts drop below the baseline
857857SUB1 = 0.0
858858# Percentage of x-height that superscripts are offset relative to the subscript
859- DELTA = 0.1
859+ DELTA = 0.25
860860
861861class MathTextWarning (Warning ):
862862 pass
863863
864864class Node (object ):
865- """A node in a linked list.
865+ """A node in the TeX box model
866866 @133
867867 """
868868 def __init__ (self ):
869- self .link = None
870869 self .size = 0
871870
872871 def __repr__ (self ):
873- s = self .__internal_repr__ ()
874- if self .link :
875- s += ' ' + self .link .__repr__ ()
876- return s
872+ return self .__internal_repr__ ()
877873
878874 def __internal_repr__ (self ):
879875 return self .__class__ .__name__
880876
881877 def get_kerning (self , next ):
882878 return 0.0
883879
884- def set_link (self , other ):
885- self .link = other
886-
887880 def shrink (self ):
888881 """Shrinks one level smaller. There are only three levels of sizes,
889882 after which things will no longer get smaller."""
890- if self .link :
891- self .link .shrink ()
892883 self .size += 1
893884
894885 def grow (self ):
895886 """Grows one level larger. There is no limit to how big something
896887 can get."""
897- if self .link :
898- self .link .grow ()
899888 self .size -= 1
900889
901890 def render (self , x , y ):
@@ -1027,29 +1016,17 @@ class List(Box):
10271016 def __init__ (self , elements ):
10281017 Box .__init__ (self , 0. , 0. , 0. )
10291018 self .shift_amount = 0. # An arbitrary offset
1030- self .list_head = None # The head of a linked list of Nodes in this box
1019+ self .children = elements # The child nodes of this list
10311020 # The following parameters are set in the vpack and hpack functions
10321021 self .glue_set = 0. # The glue setting of this list
10331022 self .glue_sign = 0 # 0: normal, -1: shrinking, 1: stretching
10341023 self .glue_order = 0 # The order of infinity (0 - 3) for the glue
1035-
1036- # Convert the Python list to a linked list
1037- if len (elements ):
1038- elem = self .list_head = elements [0 ]
1039- for next in elements [1 :]:
1040- elem .set_link (next )
1041- elem = next
10421024
10431025 def __repr__ (self ):
1044- s = '[%s <%d %d %d %d> ' % (self .__internal_repr__ (),
1045- self .width , self .height ,
1046- self .depth , self .shift_amount )
1047- if self .list_head :
1048- s += ' ' + self .list_head .__repr__ ()
1049- s += ']'
1050- if self .link :
1051- s += ' ' + self .link .__repr__ ()
1052- return s
1026+ return '[%s <%d %d %d %d> %s]' % (self .__internal_repr__ (),
1027+ self .width , self .height ,
1028+ self .depth , self .shift_amount ,
1029+ ' ' .join (self .children ))
10531030
10541031 def _determine_order (self , totals ):
10551032 """A helper function to determine the highest order of glue
@@ -1071,21 +1048,21 @@ def _set_glue(self, x, sign, totals, error_type):
10711048 self .glue_sign = 0
10721049 self .glue_ratio = 0.
10731050 if o == 0 :
1074- if self .list_head is not None :
1051+ if len ( self .children ) :
10751052 warn ("%s %s: %r" % (error_type , self .__class__ .__name__ , self ),
10761053 MathTextWarning )
10771054
10781055 def shrink (self ):
1079- if self .list_head :
1080- self . list_head .shrink ()
1056+ for child in self .children :
1057+ child .shrink ()
10811058 Box .shrink (self )
10821059 if self .size < NUM_SIZE_LEVELS :
10831060 self .shift_amount *= SHRINK_FACTOR
10841061 self .glue_set *= SHRINK_FACTOR
10851062
10861063 def grow (self ):
1087- if self .list_head :
1088- self . list_head .grow ()
1064+ for child in self .children :
1065+ child .grow ()
10891066 Box .grow (self )
10901067 self .shift_amount *= INV_SHRINK_FACTOR
10911068 self .glue_set *= INV_SHRINK_FACTOR
@@ -1103,15 +1080,21 @@ def kern(self):
11031080 Chars themselves determine the amount of kerning they need
11041081 (in get_kerning), and this function just creates the linked
11051082 list in the correct way."""
1106- elem = self .list_head
1107- while elem is not None :
1108- next = elem .link
1083+ new_children = []
1084+ num_children = len (self .children )
1085+ for i in range (num_children ):
1086+ elem = self .children [i ]
1087+ if i < num_children - 1 :
1088+ next = self .children [i + 1 ]
1089+ else :
1090+ next = None
1091+
1092+ new_children .append (elem )
11091093 kerning_distance = elem .get_kerning (next )
11101094 if kerning_distance != 0. :
11111095 kern = Kern (kerning_distance )
1112- elem .link = kern
1113- kern .link = next
1114- elem = next
1096+ new_children .append (kern )
1097+ self .children = new_children
11151098
11161099 def hpack (self , w = 0. , m = 'additional' ):
11171100 """The main duty of hpack is to compute the dimensions of the
@@ -1136,18 +1119,12 @@ def hpack(self, w=0., m='additional'):
11361119 x = 0.
11371120 total_stretch = [0. ] * 4
11381121 total_shrink = [0. ] * 4
1139- p = self .list_head
1140- while p is not None :
1141- # Layout characters in a tight inner loop (common case)
1142- while isinstance (p , Char ):
1122+ for p in self .children :
1123+ if isinstance (p , Char ):
11431124 x += p .width
11441125 h = max (h , p .height )
11451126 d = max (d , p .depth )
1146- p = p .link # Go to next node in list
1147- if p is None :
1148- break
1149-
1150- if isinstance (p , Box ):
1127+ elif isinstance (p , Box ):
11511128 x += p .width
11521129 if p .height is not None and p .depth is not None :
11531130 s = getattr (p , 'shift_amount' , 0. )
@@ -1160,7 +1137,6 @@ def hpack(self, w=0., m='additional'):
11601137 total_shrink [glue_spec .shrink_order ] += glue_spec .shrink
11611138 elif isinstance (p , Kern ):
11621139 x += p .width
1163- p = p .link # Go to next node in list
11641140 self .height = h
11651141 self .depth = d
11661142
@@ -1207,11 +1183,8 @@ def vpack(self, h=0., m='additional', l=float('inf')):
12071183 x = 0.
12081184 total_stretch = [0. ] * 4
12091185 total_shrink = [0. ] * 4
1210- p = self .list_head
1211- while p is not None :
1212- if isinstance (p , Char ):
1213- raise RuntimeError ("Internal mathtext error: Char node found in Vlist." )
1214- elif isinstance (p , Box ):
1186+ for p in self .children :
1187+ if isinstance (p , Box ):
12151188 x += d + p .height
12161189 d = p .depth
12171190 if p .width is not None :
@@ -1227,8 +1200,9 @@ def vpack(self, h=0., m='additional', l=float('inf')):
12271200 elif isinstance (p , Kern ):
12281201 x += d + p .width
12291202 d = 0.
1230- p = p .link
1231-
1203+ elif isinstance (p , Char ):
1204+ raise RuntimeError ("Internal mathtext error: Char node found in Vlist." )
1205+
12321206 self .width = w
12331207 if d > l :
12341208 x += d - l
@@ -1482,23 +1456,18 @@ def hlist_out(self, box):
14821456 cur_glue = 0.
14831457 glue_order = box .glue_order
14841458 glue_sign = box .glue_sign
1485- p = box .list_head
14861459 base_line = self .cur_v
14871460 left_edge = self .cur_h
14881461 self .cur_s += 1
14891462 self .max_push = max (self .cur_s , self .max_push )
14901463
1491- while p :
1492- while isinstance (p , Char ):
1464+ for p in box . children :
1465+ if isinstance (p , Char ):
14931466 p .render (self .cur_h + self .off_h , self .cur_v + self .off_v )
14941467 self .cur_h += p .width
1495- p = p .link
1496- if p is None :
1497- break
1498-
1499- if isinstance (p , List ):
1468+ elif isinstance (p , List ):
15001469 # @623
1501- if p . list_head is None :
1470+ if len ( p . children ) == 0 :
15021471 self .cur_h += p .width
15031472 else :
15041473 edge = self .cur_h
@@ -1542,26 +1511,22 @@ def hlist_out(self, box):
15421511 self .cur_h += rule_width
15431512 elif isinstance (p , Kern ):
15441513 self .cur_h += p .width
1545- p = p .link
15461514 self .cur_s -= 1
15471515
15481516 def vlist_out (self , box ):
15491517 cur_g = 0
15501518 cur_glue = 0.
15511519 glue_order = box .glue_order
15521520 glue_sign = box .glue_sign
1553- p = box .list_head
15541521 self .cur_s += 1
15551522 self .max_push = max (self .max_push , self .cur_s )
15561523 left_edge = self .cur_h
15571524 self .cur_v -= box .height
15581525 top_edge = self .cur_v
15591526
1560- while p :
1561- if isinstance (p , Char ):
1562- raise RuntimeError ("Internal mathtext error: Char node found in vlist" )
1563- elif isinstance (p , List ):
1564- if p .list_head is None :
1527+ for p in box .children :
1528+ if isinstance (p , List ):
1529+ if len (p .children ) == 0 :
15651530 self .cur_v += p .height + p .depth
15661531 else :
15671532 self .cur_v += p .height
@@ -1601,8 +1566,8 @@ def vlist_out(self, box):
16011566 self .cur_v += rule_height
16021567 elif isinstance (p , Kern ):
16031568 self .cur_v += p .width
1604-
1605- p = p . link
1569+ elif isinstance ( p , Char ):
1570+ raise RuntimeError ( "Internal mathtext error: Char node found in vlist" )
16061571 self .cur_s -= 1
16071572
16081573ship = Ship ()
@@ -1657,14 +1622,16 @@ class Parser(object):
16571622 _punctuation_symbols = Set (r', ; . ! \ldotp \cdotp' .split ())
16581623
16591624 _overunder_symbols = Set (r'''
1660- \sum \prod \int \ coprod \oint \bigcap \bigcup \bigsqcup \bigvee
1625+ \sum \prod \coprod \bigcap \bigcup \bigsqcup \bigvee
16611626 \bigwedge \bigodot \bigotimes \bigoplus \biguplus
16621627 ''' .split ()
16631628 )
16641629
16651630 _overunder_functions = Set (
16661631 r"lim liminf limsup sup max min" .split ()
16671632 )
1633+
1634+ _dropsub_symbols = Set (r'''\int \oint''' .split ())
16681635
16691636 def __init__ (self ):
16701637 # All forward declarations are here
@@ -1843,6 +1810,7 @@ def __init__(self):
18431810 def clear (self ):
18441811 self ._expr = None
18451812 self ._state_stack = None
1813+ self ._em_width_cache = {}
18461814
18471815 def parse (self , s , fonts_object , fontsize , dpi ):
18481816 self ._state_stack = [self .State (fonts_object , 'default' , fontsize , dpi )]
@@ -1898,10 +1866,14 @@ def non_math(self, s, loc, toks):
18981866 def _make_space (self , percentage ):
18991867 # All spaces are relative to em width
19001868 state = self .get_state ()
1901- metrics = state .font_output .get_metrics (
1902- state .font , 'm' , state .fontsize , state .dpi )
1903- em = metrics .advance
1904- return Kern (em * percentage )
1869+ key = (state .font , state .fontsize , state .dpi )
1870+ width = self ._em_width_cache .get (key )
1871+ if width is None :
1872+ metrics = state .font_output .get_metrics (
1873+ state .font , 'm' , state .fontsize , state .dpi )
1874+ width = metrics .advance
1875+ self ._em_width_cache [key ] = width
1876+ return Kern (width * percentage )
19051877
19061878 _space_widths = { r'\ ' : 0.3 ,
19071879 r'\,' : 0.4 ,
@@ -1919,17 +1891,19 @@ def space(self, s, loc, toks):
19191891 def symbol (self , s , loc , toks ):
19201892 # print "symbol", toks
19211893 c = toks [0 ]
1894+ try :
1895+ char = Char (c , self .get_state ())
1896+ except ValueError :
1897+ raise ParseFatalException ("Unknown symbol: %s" % c )
1898+
19221899 if c in self ._spaced_symbols :
19231900 return [Hlist ( [self ._make_space (0.2 ),
1924- Char ( c , self . get_state ()) ,
1901+ char ,
19251902 self ._make_space (0.2 )] )]
19261903 elif c in self ._punctuation_symbols :
1927- return [Hlist ( [Char ( c , self . get_state ()) ,
1904+ return [Hlist ( [char ,
19281905 self ._make_space (0.2 )] )]
1929- try :
1930- return [Char (toks [0 ], self .get_state ())]
1931- except ValueError :
1932- raise ParseFatalException ("Unknown symbol: %s" % c )
1906+ return [char ]
19331907
19341908 _accent_map = {
19351909 r'\hat' : r'\circumflexaccent' ,
@@ -2004,6 +1978,11 @@ def is_overunder(self, nucleus):
20041978 elif isinstance (nucleus , Hlist ) and hasattr (nucleus , 'function_name' ):
20051979 return nucleus .function_name in self ._overunder_functions
20061980 return False
1981+
1982+ def is_dropsub (self , nucleus ):
1983+ if isinstance (nucleus , Char ):
1984+ return nucleus .c in self ._dropsub_symbols
1985+ return False
20071986
20081987 def subsuperscript (self , s , loc , toks ):
20091988 assert (len (toks )== 1 )
@@ -2079,7 +2058,10 @@ def subsuperscript(self, s, loc, toks):
20792058 return [result ]
20802059
20812060 shift_up = nucleus .height - SUBDROP * xHeight
2082- shift_down = SUBDROP * xHeight
2061+ if self .is_dropsub (nucleus ):
2062+ shift_down = nucleus .depth + SUBDROP * xHeight
2063+ else :
2064+ shift_down = SUBDROP * xHeight
20832065 if super is None :
20842066 # @757
20852067 sub .shrink ()
@@ -2091,8 +2073,8 @@ def subsuperscript(self, s, loc, toks):
20912073 x .shift_amount = shift_down
20922074 else :
20932075 super .shrink ()
2094- x = Hlist ([super ])
2095- x .width += SCRIPT_SPACE * xHeight
2076+ x = Hlist ([super , Kern ( SCRIPT_SPACE * xHeight ) ])
2077+ # x.width += SCRIPT_SPACE * xHeight
20962078 clr = SUP1 * xHeight
20972079 shift_up = max (shift_up , clr )
20982080 clr = x .depth + (abs (xHeight ) / 4.0 )
@@ -2104,11 +2086,11 @@ def subsuperscript(self, s, loc, toks):
21042086 y = Hlist ([sub ])
21052087 y .width += SCRIPT_SPACE * xHeight
21062088 shift_down = max (shift_down , SUB1 * xHeight )
2107- clr = 4 .0 * rule_thickness - ((shift_up - x .depth ) - (y .height - shift_down ))
2089+ clr = 2 .0 * rule_thickness - ((shift_up - x .depth ) - (y .height - shift_down ))
21082090 if clr > 0. :
21092091 shift_up += clr
21102092 shift_down += clr
2111- x .shift_amount = DELTA * xHeight
2093+ x .shift_amount = DELTA * ( shift_up + shift_down )
21122094 x = Vlist ([x ,
21132095 Kern ((shift_up - x .depth ) - (y .height - shift_down )),
21142096 y ])
0 commit comments