diff --git a/lib/matplotlib/_mathtext.py b/lib/matplotlib/_mathtext.py
index 79f8e1a1d3b5..938475c8d6c5 100644
--- a/lib/matplotlib/_mathtext.py
+++ b/lib/matplotlib/_mathtext.py
@@ -220,7 +220,7 @@ def _get_info(self, fontname, font_class, sym, fontsize, dpi):
if bunch is not None:
return bunch
- font, num, slanted = self._get_glyph(
+ font, num, slanted, substituted_glyph = self._get_glyph(
fontname, font_class, sym, fontsize)
font.set_size(fontsize, dpi)
@@ -239,7 +239,8 @@ def _get_info(self, fontname, font_class, sym, fontsize, dpi):
ymax = ymax+offset,
# iceberg is the equivalent of TeX's "height"
iceberg = glyph.horiBearingY/64.0 + offset,
- slanted = slanted
+ slanted = slanted,
+ substituted_glyph = substituted_glyph
)
result = self.glyphd[key] = types.SimpleNamespace(
@@ -323,7 +324,7 @@ def _get_glyph(self, fontname, font_class, sym, fontsize):
if font is not None:
num = ord(sym)
if font is not None and font.get_char_index(num) != 0:
- return font, num, slanted
+ return font, num, slanted, False
else:
return self._stix_fallback._get_glyph(
fontname, font_class, sym, fontsize)
@@ -448,6 +449,8 @@ def _get_glyph(self, fontname, font_class, sym, fontsize):
found_symbol = False
_log.warning("No TeX to Unicode mapping for {!a}.".format(sym))
+ substituted_glyph = False
+
fontname, uniindex = self._map_virtual_font(
fontname, font_class, uniindex)
@@ -499,8 +502,9 @@ def _get_glyph(self, fontname, font_class, sym, fontsize):
font = self._get_font('rm')
uniindex = 0xA4 # currency char, for lack of anything better
slanted = False
+ substituted_glyph = True
- return font, uniindex, slanted
+ return font, uniindex, slanted, substituted_glyph
def get_sized_alternatives_for_symbol(self, fontname, sym):
if self._fallback_font:
@@ -935,6 +939,9 @@ def _update_metrics(self):
def is_slanted(self):
return self._metrics.slanted
+ def is_substituted(self):
+ return self._metrics.substituted_glyph
+
def get_kerning(self, next):
"""
Return the amount of kerning between this and the given character.
@@ -2011,7 +2018,7 @@ def unknown_symbol(self, s, loc, toks):
raise ParseFatalException(s, loc, f"Unknown symbol: {toks['name']}")
_accent_map = {
- r'hat': r'\circumflexaccent',
+ r'hat': r'\combiningcircumflexaccent',
r'breve': r'\combiningbreve',
r'bar': r'\combiningoverline',
r'grave': r'\combininggraveaccent',
@@ -2027,10 +2034,13 @@ def unknown_symbol(self, s, loc, toks):
r"'": r'\combiningacuteaccent',
r'~': r'\combiningtilde',
r'.': r'\combiningdotabove',
- r'^': r'\circumflexaccent',
- r'overrightarrow': r'\rightarrow',
- r'overleftarrow': r'\leftarrow',
- r'mathring': r'\circ',
+ r'^': r'\combiningcircumflexaccent',
+ r'overrightarrow': r'\combiningrightarrowabove',
+ r'overleftarrow': r'\combiningleftarrowabove',
+ r'mathring': r'\combiningringabove',
+ r'=': r'\combiningmacron',
+ r'H': r'\combiningdoubleacuteaccent',
+ r'check': r'\combiningcaron',
}
_wide_accents = set(r"widehat widetilde widebar".split())
@@ -2050,10 +2060,27 @@ def accent(self, s, loc, toks):
accent_box = AutoWidthChar(
'\\' + accent, sym.width, state, char_class=Accent)
else:
+ # Check if accent and character can be combined
+ a = get_unicode_index(self._accent_map[accent])
+ if isinstance(sym, Char):
+ c = sym.c
+ else:
+ c = sym.children[0].c
+ if c == chr(305): # Dotless i, but normal i combines
+ c = 'i'
+ comb = unicodedata.normalize('NFC', c + chr(a))
+ if len(comb) == 1: # Check that they did combine
+ newsym = Char(comb, state)
+ # Check that glyph exists
+ if not newsym.is_substituted():
+ return newsym
+ if c == 'i': # Turn i into dotless i
+ sym = Char(chr(305), state)
+ if sym.is_substituted():
+ # Dotless i does not exist
+ sym = Char('i', state)
+ # Cannot be combined
accent_box = Accent(self._accent_map[accent], state)
- if accent == 'mathring':
- accent_box.shrink()
- accent_box.shrink()
centered = HCentered([Hbox(sym.width / 4.0), accent_box])
centered.hpack(sym.width, 'exactly')
return Vlist([
@@ -2137,9 +2164,6 @@ def is_slanted(self, nucleus):
return nucleus.is_slanted()
return False
- def is_between_brackets(self, s, loc):
- return False
-
def subsuper(self, s, loc, toks):
nucleus = toks.get("nucleus", Hbox(0))
subsuper = toks.get("subsuper", [])
diff --git a/lib/matplotlib/_mathtext_data.py b/lib/matplotlib/_mathtext_data.py
index 8dac9301ed81..3df66edbf6fe 100644
--- a/lib/matplotlib/_mathtext_data.py
+++ b/lib/matplotlib/_mathtext_data.py
@@ -117,13 +117,18 @@
'\\Upsilon' : ('cmr10', 0xa8),
'\\Xi' : ('cmr10', 0xa5),
'\\circumflexaccent' : ('cmr10', 0x5e),
+ '\\combiningcircumflexaccent' : ('cmr10', 0x5e),
'\\combiningacuteaccent' : ('cmr10', 0xb6),
'\\combiningbreve' : ('cmr10', 0xb8),
'\\combiningdiaeresis' : ('cmr10', 0xc4),
'\\combiningdotabove' : ('cmr10', 0x5f),
'\\combininggraveaccent' : ('cmr10', 0xb5),
'\\combiningoverline' : ('cmr10', 0xb9),
+ '\\combiningmacron' : ('cmr10', 0x16),
+ '\\combiningringabove' : ('cmr10', 0x15),
+ '\\combiningcaron' : ('cmr10', 0x14),
'\\combiningtilde' : ('cmr10', 0x7e),
+ '\\combiningdoubleacuteaccent' : ('cmr10', 0x7d),
'\\leftbracket' : ('cmr10', 0x5b),
'\\leftparen' : ('cmr10', 0x28),
'\\rightbracket' : ('cmr10', 0x5d),
@@ -994,14 +999,20 @@
'circumflexaccent' : 770,
'combiningbreve' : 774,
'combiningoverline' : 772,
+ 'combiningmacron' : 773,
'combininggraveaccent' : 768,
'combiningacuteaccent' : 769,
'combiningdiaeresis' : 776,
'combiningtilde' : 771,
'combiningrightarrowabove' : 8407,
+ 'combiningleftarrowabove' : 8406,
'combiningdotabove' : 775,
+ 'combiningringabove' : 778,
'combiningthreedotsabove' : 8411,
'combiningfourdotsabove' : 8412,
+ 'combiningdoubleacuteaccent' : 779,
+ 'combiningcaron' : 780,
+ 'combiningcircumflexaccent' : 770,
'to' : 8594,
'succeq' : 8829,
'emptyset' : 8709,
diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.pdf
new file mode 100644
index 000000000000..79a90506a70e
Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.pdf differ
diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.png
new file mode 100644
index 000000000000..53c60279aa17
Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.png differ
diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.svg
new file mode 100644
index 000000000000..5ee071517f59
--- /dev/null
+++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.svg
@@ -0,0 +1,770 @@
+
+
+
diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.pdf
new file mode 100644
index 000000000000..fa0df1d359cb
Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.pdf differ
diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.png
new file mode 100644
index 000000000000..054ff4f0ee1f
Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.png differ
diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.svg
new file mode 100644
index 000000000000..8156a604bb21
--- /dev/null
+++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.svg
@@ -0,0 +1,617 @@
+
+
+
diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.pdf
new file mode 100644
index 000000000000..5e8a4d53f20b
Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.pdf differ
diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.png
new file mode 100644
index 000000000000..ea0868cae9a3
Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.png differ
diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.svg
new file mode 100644
index 000000000000..fec22d7c4a04
--- /dev/null
+++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.svg
@@ -0,0 +1,662 @@
+
+
+
diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.pdf
new file mode 100644
index 000000000000..7e84ff37aae7
Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.pdf differ
diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.png
new file mode 100644
index 000000000000..df0746cc3e9e
Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.png differ
diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.svg
new file mode 100644
index 000000000000..164417504719
--- /dev/null
+++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.svg
@@ -0,0 +1,674 @@
+
+
+
diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.pdf
new file mode 100644
index 000000000000..a50c8060a4ed
Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.pdf differ
diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.png
new file mode 100644
index 000000000000..e2fcb2eafd65
Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.png differ
diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.svg
new file mode 100644
index 000000000000..a412d8918b40
--- /dev/null
+++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.svg
@@ -0,0 +1,615 @@
+
+
+
diff --git a/lib/matplotlib/tests/test_mathtext.py b/lib/matplotlib/tests/test_mathtext.py
index 9d4b00bb5126..194a238668d9 100644
--- a/lib/matplotlib/tests/test_mathtext.py
+++ b/lib/matplotlib/tests/test_mathtext.py
@@ -115,6 +115,9 @@
r'$,$ $.$ $1{,}234{, }567{ , }890$ and $1,234,567,890$', # github issue 5799
r'$\left(X\right)_{a}^{b}$', # github issue 7615
r'$\dfrac{\$100.00}{y}$', # github issue #1888
+ r'$\={M}\H{a}\check{t}\hat{p}\overleftarrow{l}\overrightarrow{o}\"{t}'
+ r'\.{l}\mathring{i}\~{b}$ $\breve{M}\bar{a}\grave{t}\acute{p}\vec{l}'
+ r'\dddot{o}\ddddot{t}\^{l}\ddot{i}\overline{b}$'
]
# 'svgastext' tests switch svg output to embed text as text (rather than as
# paths).
diff --git a/tutorials/text/mathtext.py b/tutorials/text/mathtext.py
index 9e9abfc52344..19119477e802 100644
--- a/tutorials/text/mathtext.py
+++ b/tutorials/text/mathtext.py
@@ -306,7 +306,7 @@
Command Result
============================== =================================
``\acute a`` or ``\'a`` :mathmpl:`\acute a`
- ``\bar a`` :mathmpl:`\bar a`
+ ``\bar a`` or ``\= a`` :mathmpl:`\bar a`
``\breve a`` :mathmpl:`\breve a`
``\dot a`` or ``\.a`` :mathmpl:`\dot a`
``\ddot a`` or ``\''a`` :mathmpl:`\ddot a`
@@ -316,6 +316,8 @@
``\hat a`` or ``\^a`` :mathmpl:`\hat a`
``\tilde a`` or ``\~a`` :mathmpl:`\tilde a`
``\vec a`` :mathmpl:`\vec a`
+ ``\check a`` :mathmpl:`\check a`
+ ``\H a`` :mathmpl:`\H a`
``\overline{abc}`` :mathmpl:`\overline{abc}`
============================== =================================