Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b3cfa4d

Browse filesBrowse files
committed
Add language parameter to Text objects
1 parent b9e94e4 commit b3cfa4d
Copy full SHA for b3cfa4d

16 files changed

+123
-33
lines changed

‎lib/matplotlib/_text_helpers.py

Copy file name to clipboardExpand all lines: lib/matplotlib/_text_helpers.py
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def warn_on_missing_glyph(codepoint, fontnames):
4343
f"Matplotlib currently does not support {block} natively.")
4444

4545

46-
def layout(string, font, *, kern_mode=Kerning.DEFAULT):
46+
def layout(string, font, language, *, kern_mode=Kerning.DEFAULT):
4747
"""
4848
Render *string* with *font*.
4949
@@ -65,7 +65,7 @@ def layout(string, font, *, kern_mode=Kerning.DEFAULT):
6565
"""
6666
x = 0
6767
prev_glyph_idx = None
68-
char_to_font = font._get_fontmap(string)
68+
char_to_font = font._get_fontmap(string) # TODO: Pass in language.
6969
base_font = font
7070
for char in string:
7171
# This has done the fallback logic

‎lib/matplotlib/backend_bases.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backend_bases.py
+4-1Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,8 @@ def draw_tex(self, gc, x, y, s, prop, angle, *, mtext=None):
494494
"""
495495
self._draw_text_as_path(gc, x, y, s, prop, angle, ismath="TeX")
496496

497-
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
497+
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None,
498+
language=None):
498499
"""
499500
Draw a text instance.
500501
@@ -516,6 +517,8 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
516517
If True, use mathtext parser.
517518
mtext : `~matplotlib.text.Text`
518519
The original text object to be rendered.
520+
language : str or list[tuple[str, int, int]]
521+
The language of the text.
519522
520523
Notes
521524
-----

‎lib/matplotlib/backend_bases.pyi

Copy file name to clipboardExpand all lines: lib/matplotlib/backend_bases.pyi
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ class RendererBase:
116116
angle: float,
117117
ismath: bool | Literal["TeX"] = ...,
118118
mtext: Text | None = ...,
119+
language: str | list[tuple[str, int, int]] | None = ...,
119120
) -> None: ...
120121
def get_text_width_height_descent(
121122
self, s: str, prop: FontProperties, ismath: bool | Literal["TeX"]

‎lib/matplotlib/backends/backend_agg.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backends/backend_agg.py
+5-4Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,14 +182,15 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
182182
y = round(y - oy + yd)
183183
self._renderer.draw_text_image(font_image, x, y + 1, angle, gc)
184184

185-
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
185+
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None,
186+
language=None):
186187
# docstring inherited
187188
if ismath:
188189
return self.draw_mathtext(gc, x, y, s, prop, angle)
189190
font = self._prepare_font(prop)
190191
# We pass '0' for angle here, since it will be rotated (in raster
191192
# space) in the following call to draw_text_image).
192-
font.set_text(s, 0, flags=get_hinting_flag())
193+
font.set_text(s, 0, flags=get_hinting_flag(), language=language)
193194
font.draw_glyphs_to_bitmap(
194195
antialiased=gc.get_antialiased())
195196
d = font.get_descent() / 64.0
@@ -203,7 +204,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
203204
y = round(y + yo + yd)
204205
self._renderer.draw_text_image(font, x, y + 1, angle, gc)
205206

206-
def get_text_width_height_descent(self, s, prop, ismath):
207+
def get_text_width_height_descent(self, s, prop, ismath, language=None):
207208
# docstring inherited
208209

209210
_api.check_in_list(["TeX", True, False], ismath=ismath)
@@ -216,7 +217,7 @@ def get_text_width_height_descent(self, s, prop, ismath):
216217
return width, height, descent
217218

218219
font = self._prepare_font(prop)
219-
font.set_text(s, 0.0, flags=get_hinting_flag())
220+
font.set_text(s, 0.0, flags=get_hinting_flag(), language=language)
220221
w, h = font.get_width_height() # width and height of unrotated string
221222
d = font.get_descent()
222223
w /= 64.0 # convert from subpixels

‎lib/matplotlib/backends/backend_cairo.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backends/backend_cairo.py
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,8 @@ def draw_image(self, gc, x, y, im):
214214
ctx.paint()
215215
ctx.restore()
216216

217-
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
217+
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None,
218+
language=None): # TODO: Apply language tag, if possible.
218219
# docstring inherited
219220

220221
# Note: (x, y) are device/display coords, not user-coords, unlike other

‎lib/matplotlib/backends/backend_pdf.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backends/backend_pdf.py
+5-3Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2327,7 +2327,8 @@ def encode_string(self, s, fonttype):
23272327
return s.encode('cp1252', 'replace')
23282328
return s.encode('utf-16be', 'replace')
23292329

2330-
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
2330+
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None,
2331+
language=None):
23312332
# docstring inherited
23322333

23332334
# TODO: combine consecutive texts into one BT/ET delimited section
@@ -2347,7 +2348,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
23472348
fonttype = mpl.rcParams['pdf.fonttype']
23482349

23492350
if gc.get_url() is not None:
2350-
font.set_text(s)
2351+
font.set_text(s, language=language)
23512352
width, height = font.get_width_height()
23522353
self.file._annotations[-1][1].append(_get_link_annotation(
23532354
gc, x, y, width / 64, height / 64, angle))
@@ -2381,7 +2382,8 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
23812382
multibyte_glyphs = []
23822383
prev_was_multibyte = True
23832384
prev_font = font
2384-
for item in _text_helpers.layout(s, font, kern_mode=Kerning.UNFITTED):
2385+
for item in _text_helpers.layout(s, font, language,
2386+
kern_mode=Kerning.UNFITTED):
23852387
if _font_supports_glyph(fonttype, ord(item.char)):
23862388
if prev_was_multibyte or item.ft_object != prev_font:
23872389
singlebyte_chunks.append((item.ft_object, item.x, []))

‎lib/matplotlib/backends/backend_pgf.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backends/backend_pgf.py
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,8 @@ def draw_tex(self, gc, x, y, s, prop, angle, *, mtext=None):
673673
# docstring inherited
674674
self.draw_text(gc, x, y, s, prop, angle, ismath="TeX", mtext=mtext)
675675

676-
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
676+
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None,
677+
language=None): # TODO: Implement language if possible.
677678
# docstring inherited
678679

679680
# prepare string for tex

‎lib/matplotlib/backends/backend_ps.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backends/backend_ps.py
+3-2Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,8 @@ def draw_tex(self, gc, x, y, s, prop, angle, *, mtext=None):
758758
self.textcnt += 1
759759

760760
@_log_if_debug_on
761-
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
761+
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None,
762+
language=None):
762763
# docstring inherited
763764

764765
if self._is_transparent(gc.get_rgb()):
@@ -795,7 +796,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
795796
else:
796797
font = self._get_font_ttf(prop)
797798
self._character_tracker.track(font, s)
798-
for item in _text_helpers.layout(s, font):
799+
for item in _text_helpers.layout(s, font, language):
799800
ps_name = (item.ft_object.postscript_name
800801
.encode("ascii", "replace").decode("ascii"))
801802
glyph_name = item.ft_object.get_glyph_name(item.glyph_idx)

‎lib/matplotlib/backends/backend_svg.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backends/backend_svg.py
+8-5Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,7 +1035,8 @@ def _update_glyph_map_defs(self, glyph_map_new):
10351035
def _adjust_char_id(self, char_id):
10361036
return char_id.replace("%20", "_")
10371037

1038-
def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath, mtext=None):
1038+
def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath, mtext=None,
1039+
language=None):
10391040
# docstring inherited
10401041
writer = self.writer
10411042

@@ -1106,7 +1107,8 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath, mtext=None):
11061107

11071108
writer.end('g')
11081109

1109-
def _draw_text_as_text(self, gc, x, y, s, prop, angle, ismath, mtext=None):
1110+
def _draw_text_as_text(self, gc, x, y, s, prop, angle, ismath, mtext=None,
1111+
language=None):
11101112
# NOTE: If you change the font styling CSS, then be sure the check for
11111113
# svg.fonttype = none in `lib/matplotlib/testing/compare.py::convert` remains in
11121114
# sync. Also be sure to re-generate any SVG using this mode, or else such tests
@@ -1263,7 +1265,8 @@ def _get_all_quoted_names(prop):
12631265

12641266
writer.end('g')
12651267

1266-
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
1268+
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None,
1269+
language=None):
12671270
# docstring inherited
12681271

12691272
clip_attrs = self._get_clip_attrs(gc)
@@ -1276,9 +1279,9 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
12761279
self.writer.start('a', {'xlink:href': gc.get_url()})
12771280

12781281
if mpl.rcParams['svg.fonttype'] == 'path':
1279-
self._draw_text_as_path(gc, x, y, s, prop, angle, ismath, mtext)
1282+
self._draw_text_as_path(gc, x, y, s, prop, angle, ismath, mtext, language)
12801283
else:
1281-
self._draw_text_as_text(gc, x, y, s, prop, angle, ismath, mtext)
1284+
self._draw_text_as_text(gc, x, y, s, prop, angle, ismath, mtext, language)
12821285

12831286
if gc.get_url() is not None:
12841287
self.writer.end('a')

‎lib/matplotlib/backends/backend_template.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backends/backend_template.py
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ def draw_path(self, gc, path, transform, rgbFace=None):
7979
def draw_image(self, gc, x, y, im):
8080
pass
8181

82-
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
82+
def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None,
83+
language=None):
8384
pass
8485

8586
def flipy(self):

‎lib/matplotlib/text.py

Copy file name to clipboardExpand all lines: lib/matplotlib/text.py
+47-3Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
"""
44

55
import functools
6+
import inspect
67
import logging
78
import math
89
from numbers import Real
10+
import warnings
911
import weakref
1012

1113
import numpy as np
@@ -136,6 +138,7 @@ def __init__(self,
136138
super().__init__()
137139
self._x, self._y = x, y
138140
self._text = ''
141+
self._language = None
139142
self._reset_visual_defaults(
140143
text=text,
141144
color=color,
@@ -791,6 +794,7 @@ def draw(self, renderer):
791794

792795
angle = self.get_rotation()
793796

797+
lang = self._language # TODO: Split this by line.
794798
for line, wh, x, y in info:
795799

796800
mtext = self if len(info) == 1 else None
@@ -812,9 +816,19 @@ def draw(self, renderer):
812816
self._fontproperties, angle,
813817
mtext=mtext)
814818
else:
815-
textrenderer.draw_text(gc, x, y, clean_line,
816-
self._fontproperties, angle,
817-
ismath=ismath, mtext=mtext)
819+
params = inspect.signature(textrenderer.draw_text).parameters
820+
if 'language' in params:
821+
textrenderer.draw_text(gc, x, y, clean_line,
822+
self._fontproperties, angle,
823+
ismath=ismath, mtext=mtext,
824+
language=lang)
825+
else:
826+
warnings.warn(
827+
f'{textrenderer.__class__.__name__} missing language '
828+
f'parameter to draw_text method')
829+
textrenderer.draw_text(gc, x, y, clean_line,
830+
self._fontproperties, angle,
831+
ismath=ismath, mtext=mtext)
818832

819833
gc.restore()
820834
renderer.close_group('text')
@@ -1410,6 +1424,36 @@ def _va_for_angle(self, angle):
14101424
return 'baseline' if anchor_at_left else 'top'
14111425
return 'top' if anchor_at_left else 'baseline'
14121426

1427+
def get_language(self):
1428+
"""Return the language this Text is in."""
1429+
return self._language
1430+
1431+
def set_language(self, language):
1432+
"""
1433+
Set the language of the text.
1434+
1435+
Parameters
1436+
----------
1437+
language : str or list[tuple[str, int, int]]
1438+
1439+
"""
1440+
_api.check_isinstance((list, str, None), language=language)
1441+
if isinstance(language, list):
1442+
for val in language:
1443+
if not isinstance(val, tuple) or len(val) != 3:
1444+
raise ValueError('language must be list of tuple, not {language!r}')
1445+
sublang, start, end = val
1446+
if not isinstance(sublang, str):
1447+
raise ValueError(
1448+
'sub-language specifcation must be str, not {sublang!r}')
1449+
if not isinstance(start, int):
1450+
raise ValueError('start location must be int, not {start!r}')
1451+
if not isinstance(end, int):
1452+
raise ValueError('end location must be int, not {end!r}')
1453+
1454+
self._language = language
1455+
self.stale = True
1456+
14131457

14141458
class OffsetFrom:
14151459
"""Callable helper class for working with `Annotation`."""

‎lib/matplotlib/text.pyi

Copy file name to clipboardExpand all lines: lib/matplotlib/text.pyi
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ class Text(Artist):
108108
def set_antialiased(self, antialiased: bool) -> None: ...
109109
def _ha_for_angle(self, angle: Any) -> Literal['center', 'right', 'left'] | None: ...
110110
def _va_for_angle(self, angle: Any) -> Literal['center', 'top', 'baseline'] | None: ...
111+
def get_language(self) -> str | list[tuple[str, int, int]] | None: ...
112+
def set_language(self, language: str | list[tuple[str, int, int]] | None) -> None: ...
111113

112114
class OffsetFrom:
113115
def __init__(

‎lib/matplotlib/textpath.py

Copy file name to clipboardExpand all lines: lib/matplotlib/textpath.py
+7-6Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def _get_char_id(self, font, ccode):
4545
"""
4646
return urllib.parse.quote(f"{font.postscript_name}-{ccode:x}")
4747

48-
def get_text_width_height_descent(self, s, prop, ismath):
48+
def get_text_width_height_descent(self, s, prop, ismath, language=None):
4949
fontsize = prop.get_size_in_points()
5050

5151
if ismath == "TeX":
@@ -61,15 +61,15 @@ def get_text_width_height_descent(self, s, prop, ismath):
6161
return width * scale, height * scale, descent * scale
6262

6363
font = self._get_font(prop)
64-
font.set_text(s, 0.0, flags=LoadFlags.NO_HINTING)
64+
font.set_text(s, 0.0, flags=LoadFlags.NO_HINTING, language=language)
6565
w, h = font.get_width_height()
6666
w /= 64.0 # convert from subpixels
6767
h /= 64.0
6868
d = font.get_descent()
6969
d /= 64.0
7070
return w * scale, h * scale, d * scale
7171

72-
def get_text_path(self, prop, s, ismath=False):
72+
def get_text_path(self, prop, s, ismath=False, language=None):
7373
"""
7474
Convert text *s* to path (a tuple of vertices and codes for
7575
matplotlib.path.Path).
@@ -109,7 +109,8 @@ def get_text_path(self, prop, s, ismath=False):
109109
glyph_info, glyph_map, rects = self.get_glyphs_tex(prop, s)
110110
elif not ismath:
111111
font = self._get_font(prop)
112-
glyph_info, glyph_map, rects = self.get_glyphs_with_font(font, s)
112+
glyph_info, glyph_map, rects = self.get_glyphs_with_font(font, s,
113+
language=language)
113114
else:
114115
glyph_info, glyph_map, rects = self.get_glyphs_mathtext(prop, s)
115116

@@ -130,7 +131,7 @@ def get_text_path(self, prop, s, ismath=False):
130131
return verts, codes
131132

132133
def get_glyphs_with_font(self, font, s, glyph_map=None,
133-
return_new_glyphs_only=False):
134+
return_new_glyphs_only=False, language=None):
134135
"""
135136
Convert string *s* to vertices and codes using the provided ttf font.
136137
"""
@@ -145,7 +146,7 @@ def get_glyphs_with_font(self, font, s, glyph_map=None,
145146

146147
xpositions = []
147148
glyph_ids = []
148-
for item in _text_helpers.layout(s, font):
149+
for item in _text_helpers.layout(s, font, language):
149150
char_id = self._get_char_id(item.ft_object, ord(item.char))
150151
glyph_ids.append(char_id)
151152
xpositions.append(item.x)

‎src/ft2font.cpp

Copy file name to clipboardExpand all lines: src/ft2font.cpp
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,8 @@ void FT2Font::set_kerning_factor(int factor)
399399
}
400400

401401
void FT2Font::set_text(
402-
std::u32string_view text, double angle, FT_Int32 flags, std::vector<double> &xys)
402+
std::u32string_view text, double angle, FT_Int32 flags, LanguageType languages,
403+
std::vector<double> &xys)
403404
{
404405
FT_Matrix matrix; /* transformation matrix */
405406

‎src/ft2font.h

Copy file name to clipboardExpand all lines: src/ft2font.h
+5-1Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#ifndef MPL_FT2FONT_H
77
#define MPL_FT2FONT_H
88

9+
#include <optional>
910
#include <set>
1011
#include <string>
1112
#include <string_view>
@@ -70,6 +71,9 @@ class FT2Font
7071
typedef void (*WarnFunc)(FT_ULong charcode, std::set<FT_String*> family_names);
7172

7273
public:
74+
using LanguageRange = std::tuple<std::string, int, int>;
75+
using LanguageType = std::optional<std::vector<LanguageRange>>;
76+
7377
FT2Font(FT_Open_Args &open_args, long hinting_factor,
7478
std::vector<FT2Font *> &fallback_list, WarnFunc warn);
7579
virtual ~FT2Font();
@@ -78,7 +82,7 @@ class FT2Font
7882
void set_charmap(int i);
7983
void select_charmap(unsigned long i);
8084
void set_text(std::u32string_view codepoints, double angle, FT_Int32 flags,
81-
std::vector<double> &xys);
85+
LanguageType languages, std::vector<double> &xys);
8286
int get_kerning(FT_UInt left, FT_UInt right, FT_Kerning_Mode mode, bool fallback);
8387
int get_kerning(FT_UInt left, FT_UInt right, FT_Kerning_Mode mode, FT_Vector &delta);
8488
void set_kerning_factor(int factor);

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.