@@ -1187,15 +1187,49 @@ def get_underline_thickness(self, font, fontsize, dpi):
1187
1187
# get any smaller
1188
1188
NUM_SIZE_LEVELS = 6
1189
1189
# Percentage of x-height of additional horiz. space after sub/superscripts
1190
- SCRIPT_SPACE = 0.2
1191
- # Percentage of x-height that sub/superscripts drop below the baseline
1192
- SUBDROP = 0.3
1193
- # Percentage of x-height that superscripts drop below the baseline
1194
- SUP1 = 0.5
1190
+ SCRIPT_SPACE = {'cm' : 0.075 ,
1191
+ 'stix' : 0.10 ,
1192
+ 'stixsans' : 0.05 ,
1193
+ 'arevsans' : 0.05 }
1194
+ ## Percentage of x-height that sub/superscripts drop below the baseline
1195
+ SUBDROP = {'cm' : 0.2 ,
1196
+ 'stix' : 0.4 ,
1197
+ 'stixsans' : 0.4 ,
1198
+ 'arevsans' : 0.4 }
1199
+ # Percentage of x-height that superscripts are raised from the baseline
1200
+ SUP1 = {'cm' : 0.45 ,
1201
+ 'stix' : 0.8 ,
1202
+ 'stixsans' : 0.8 ,
1203
+ 'arevsans' : 0.7 }
1195
1204
# Percentage of x-height that subscripts drop below the baseline
1196
- SUB1 = 0.0
1197
- # Percentage of x-height that superscripts are offset relative to the subscript
1198
- DELTA = 0.18
1205
+ SUB1 = {'cm' : 0.2 ,
1206
+ 'stix' : 0.3 ,
1207
+ 'stixsans' : 0.3 ,
1208
+ 'arevsans' : 0.3 }
1209
+ # Percentage of x-height that subscripts drop below the baseline when a
1210
+ # superscript is present
1211
+ SUB2 = {'cm' : 0.3 ,
1212
+ 'stix' : 0.6 ,
1213
+ 'stixsans' : 0.5 ,
1214
+ 'arevsans' : 0.5 }
1215
+ # Percentage of x-height that sub/supercripts are offset relative to the
1216
+ # nucleus edge for non-slanted nuclei
1217
+ DELTA = {'cm' : 0.075 ,
1218
+ 'stix' : 0.05 ,
1219
+ 'stixsans' : 0.025 ,
1220
+ 'arevsans' : 0.025 }
1221
+ # Additional percentage of last character height above 2/3 of the x-height that
1222
+ # supercripts are offset relative to the subscript for slanted nuclei
1223
+ DELTASLANTED = {'cm' : 0.3 ,
1224
+ 'stix' : 0.3 ,
1225
+ 'stixsans' : 0.6 ,
1226
+ 'arevsans' : 0.2 }
1227
+ # Percentage of x-height that supercripts and subscripts are offset for
1228
+ # integrals
1229
+ DELTAINTEGRAL = {'cm' : 0.3 ,
1230
+ 'stix' : 0.3 ,
1231
+ 'stixsans' : 0.3 ,
1232
+ 'arevsans' : 0.3 }
1199
1233
1200
1234
class MathTextWarning (Warning ):
1201
1235
pass
@@ -2628,9 +2662,21 @@ def is_slanted(self, nucleus):
2628
2662
return nucleus .is_slanted ()
2629
2663
return False
2630
2664
2665
+ def _get_fontset_name (self ):
2666
+ fs = rcParams ['mathtext.fontset' ]
2667
+ # If a custom fontset is used, check if it is Arev Sans, otherwise use
2668
+ # CM parameters.
2669
+ if fs == 'custom' :
2670
+ if (rcParams ['mathtext.rm' ] == 'sans' and
2671
+ rcParams ['font.sans-serif' ][0 ].lower () == 'Arev Sans' .lower ()):
2672
+ fs = 'arevsans'
2673
+ else :
2674
+ fs = 'cm'
2675
+
2676
+ return fs
2677
+
2631
2678
def subsuper (self , s , loc , toks ):
2632
2679
assert (len (toks )== 1 )
2633
- # print 'subsuper', toks
2634
2680
2635
2681
nucleus = None
2636
2682
sub = None
@@ -2726,48 +2772,87 @@ def subsuper(self, s, loc, toks):
2726
2772
result = Hlist ([vlist ])
2727
2773
return [result ]
2728
2774
2729
- # Handle regular sub/superscripts
2730
- shift_up = nucleus .height - SUBDROP * xHeight
2731
- if self .is_dropsub (nucleus ):
2732
- shift_down = nucleus .depth + SUBDROP * xHeight
2775
+ # We remove kerning on the last character for consistency (otherwise it
2776
+ # will compute kerning based on non-shrinked characters and may put them
2777
+ # too close together when superscripted)
2778
+ # We change the width of the last character to match the advance to
2779
+ # consider some fonts with weird metrics: e.g. stix's f has a width of
2780
+ # 7.75 and a kerning of -4.0 for an advance of 3.72, and we want to put
2781
+ # the superscript at the advance
2782
+ last_char = nucleus
2783
+ if isinstance (nucleus , Hlist ):
2784
+ new_children = nucleus .children
2785
+ if len (new_children ):
2786
+ # remove last kern
2787
+ if isinstance (new_children [- 1 ],Kern ):
2788
+ new_children = new_children [:- 1 ]
2789
+ last_char = new_children [- 1 ]
2790
+ last_char .width = last_char ._metrics .advance
2791
+ # create new Hlist without kerning
2792
+ nucleus = Hlist (new_children , do_kern = False )
2733
2793
else :
2734
- shift_down = SUBDROP * xHeight
2794
+ if isinstance (nucleus , Char ):
2795
+ last_char .width = last_char ._metrics .advance
2796
+ nucleus = Hlist ([nucleus ])
2797
+
2798
+ # Handle regular sub/superscripts
2799
+
2800
+ fs = self ._get_fontset_name ()
2801
+
2802
+ lc_height = last_char .height
2803
+ lc_baseline = 0
2804
+ if self .is_dropsub (last_char ):
2805
+ lc_baseline = last_char .depth
2806
+
2807
+ # Compute kerning for sub and super
2808
+ superkern = DELTA [fs ] * xHeight
2809
+ subkern = DELTA [fs ] * xHeight
2810
+ if self .is_slanted (last_char ):
2811
+ superkern += DELTA [fs ] * xHeight
2812
+ superkern += DELTASLANTED [fs ] * (lc_height - xHeight * 2. / 3. )
2813
+ if self .is_dropsub (last_char ):
2814
+ subkern = (3 * DELTA [fs ] - DELTAINTEGRAL [fs ]) * lc_height
2815
+ superkern = (3 * DELTA [fs ] + DELTAINTEGRAL [fs ]) * lc_height
2816
+ else :
2817
+ subkern = 0
2818
+
2735
2819
if super is None :
2736
2820
# node757
2737
- sub . shrink ( )
2738
- x = Hlist ([ sub ] )
2739
- # x.width += SCRIPT_SPACE * xHeight
2740
- shift_down = max ( shift_down , SUB1 )
2741
- clr = x . height - ( abs ( xHeight * 4.0 ) / 5.0 )
2742
- shift_down = max ( shift_down , clr )
2821
+ x = Hlist ([ Kern ( subkern ), sub ] )
2822
+ x . shrink ( )
2823
+ if self . is_dropsub ( last_char ):
2824
+ shift_down = lc_baseline + SUBDROP [ fs ] * xHeight
2825
+ else :
2826
+ shift_down = SUB1 [ fs ] * xHeight
2743
2827
x .shift_amount = shift_down
2744
2828
else :
2745
- super .shrink ()
2746
- x = Hlist ([super ])
2747
- # x.width += SCRIPT_SPACE * xHeight
2748
- clr = SUP1 * xHeight
2749
- shift_up = max (shift_up , clr )
2750
- clr = x .depth + (abs (xHeight ) / 4.0 )
2751
- shift_up = max (shift_up , clr )
2829
+ x = Hlist ([Kern (superkern ), super ])
2830
+ x .shrink ()
2831
+ if self .is_dropsub (last_char ):
2832
+ shift_up = lc_height - SUBDROP [fs ] * xHeight
2833
+ else :
2834
+ shift_up = SUP1 [fs ] * xHeight
2752
2835
if sub is None :
2753
2836
x .shift_amount = - shift_up
2754
2837
else : # Both sub and superscript
2755
- sub .shrink ()
2756
- y = Hlist ([sub ])
2757
- # y.width += SCRIPT_SPACE * xHeight
2758
- shift_down = max (shift_down , SUB1 * xHeight )
2838
+ y = Hlist ([Kern (subkern ),sub ])
2839
+ y .shrink ()
2840
+ if self .is_dropsub (last_char ):
2841
+ shift_down = lc_baseline + SUBDROP [fs ] * xHeight
2842
+ else :
2843
+ shift_down = SUB2 [fs ] * xHeight
2844
+ # If sub and superscript collide, move super up
2759
2845
clr = (2.0 * rule_thickness -
2760
2846
((shift_up - x .depth ) - (y .height - shift_down )))
2761
2847
if clr > 0. :
2762
2848
shift_up += clr
2763
- shift_down += clr
2764
- if self .is_slanted (nucleus ):
2765
- x .shift_amount = DELTA * (shift_up + shift_down )
2766
2849
x = Vlist ([x ,
2767
2850
Kern ((shift_up - x .depth ) - (y .height - shift_down )),
2768
2851
y ])
2769
2852
x .shift_amount = shift_down
2770
2853
2854
+ if not self .is_dropsub (last_char ):
2855
+ x .width += SCRIPT_SPACE [fs ] * xHeight
2771
2856
result = Hlist ([nucleus , x ])
2772
2857
return [result ]
2773
2858
0 commit comments