Skip to content

Commit 23a1cc5

Browse files
committed
Merge branch 'libraqm-vector' into libraqm-full
2 parents 3e5b592 + 70ab582 commit 23a1cc5

File tree

7 files changed

+184
-70
lines changed

7 files changed

+184
-70
lines changed

lib/matplotlib/_text_helpers.py

Lines changed: 10 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,21 @@
44

55
from __future__ import annotations
66

7-
import dataclasses
7+
from collections.abc import Iterator
88

99
from . import _api
10-
from .ft2font import FT2Font, GlyphIndexType, Kerning, LoadFlags
10+
from .ft2font import FT2Font, CharacterCodeType, LayoutItem, LoadFlags
1111

1212

13-
@dataclasses.dataclass(frozen=True)
14-
class LayoutItem:
15-
ft_object: FT2Font
16-
char: str
17-
glyph_index: GlyphIndexType
18-
x: float
19-
prev_kern: float
20-
21-
22-
def warn_on_missing_glyph(codepoint, fontnames):
13+
def warn_on_missing_glyph(codepoint: CharacterCodeType, fontnames: str):
2314
_api.warn_external(
2415
f"Glyph {codepoint} "
2516
f"({chr(codepoint).encode('ascii', 'namereplace').decode('ascii')}) "
2617
f"missing from font(s) {fontnames}.")
2718

2819

29-
def layout(string, font, *, features=None, kern_mode=Kerning.DEFAULT, language=None):
20+
def layout(string: str, font: FT2Font, *, features=None,
21+
language=None) -> Iterator[LayoutItem]:
3022
"""
3123
Render *string* with *font*.
3224
@@ -41,8 +33,6 @@ def layout(string, font, *, features=None, kern_mode=Kerning.DEFAULT, language=N
4133
The font.
4234
features : tuple of str, optional
4335
The font features to apply to the text.
44-
kern_mode : Kerning
45-
A FreeType kerning mode.
4636
language : str, optional
4737
The language of the text in a format accepted by libraqm, namely `a BCP47
4838
language code <https://www.w3.org/International/articles/language-tags/>`_.
@@ -51,20 +41,8 @@ def layout(string, font, *, features=None, kern_mode=Kerning.DEFAULT, language=N
5141
------
5242
LayoutItem
5343
"""
54-
x = 0
55-
prev_glyph_idx = None
56-
char_to_font = font._get_fontmap(string) # TODO: Pass in features and language.
57-
base_font = font
58-
for char in string:
59-
# This has done the fallback logic
60-
font = char_to_font.get(char, base_font)
61-
glyph_idx = font.get_char_index(ord(char))
62-
kern = (
63-
base_font.get_kerning(prev_glyph_idx, glyph_idx, kern_mode) / 64
64-
if prev_glyph_idx is not None else 0.
65-
)
66-
x += kern
67-
glyph = font.load_glyph(glyph_idx, flags=LoadFlags.NO_HINTING)
68-
yield LayoutItem(font, char, glyph_idx, x, kern)
69-
x += glyph.linearHoriAdvance / 65536
70-
prev_glyph_idx = glyph_idx
44+
for raqm_item in font._layout(string, LoadFlags.NO_HINTING,
45+
features=features, language=language):
46+
raqm_item.ft_object.load_glyph(raqm_item.glyph_index,
47+
flags=LoadFlags.NO_HINTING)
48+
yield raqm_item

lib/matplotlib/backends/backend_pdf.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
from matplotlib.figure import Figure
3636
from matplotlib.font_manager import get_font, fontManager as _fontManager
3737
from matplotlib._afm import AFM
38-
from matplotlib.ft2font import FT2Font, FaceFlags, Kerning, LoadFlags, StyleFlags
38+
from matplotlib.ft2font import FT2Font, FaceFlags, LoadFlags, StyleFlags
3939
from matplotlib.transforms import Affine2D, BboxBase
4040
from matplotlib.path import Path
4141
from matplotlib.dates import UTC
@@ -2355,7 +2355,6 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
23552355
fonttype = 1
23562356
else:
23572357
font = self._get_font_ttf(prop)
2358-
self.file._character_tracker.track(font, s)
23592358
fonttype = mpl.rcParams['pdf.fonttype']
23602359

23612360
if gc.get_url() is not None:
@@ -2367,6 +2366,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
23672366
# If fonttype is neither 3 nor 42, emit the whole string at once
23682367
# without manual kerning.
23692368
if fonttype not in [3, 42]:
2369+
self.file._character_tracker.track(font, s)
23702370
self.file.output(Op.begin_text,
23712371
self.file.fontName(prop), fontsize, Op.selectfont)
23722372
self._setup_textpos(x, y, angle)
@@ -2394,8 +2394,9 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
23942394
prev_was_multibyte = True
23952395
prev_font = font
23962396
for item in _text_helpers.layout(s, font, features=features,
2397-
kern_mode=Kerning.UNFITTED,
23982397
language=language):
2398+
self.file._character_tracker.track_glyph(item.ft_object,
2399+
item.glyph_index)
23992400
if _font_supports_glyph(fonttype, ord(item.char)):
24002401
if prev_was_multibyte or item.ft_object != prev_font:
24012402
singlebyte_chunks.append((item.ft_object, item.x, []))
@@ -2431,15 +2432,15 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
24312432
prev_start_x = start_x
24322433
self.file.output(Op.end_text)
24332434
# Then emit all the multibyte characters, one at a time.
2434-
for ft_object, start_x, glyph_idx in multibyte_glyphs:
2435+
for ft_object, start_x, glyph_index in multibyte_glyphs:
24352436
self._draw_xobject_glyph(
2436-
ft_object, fontsize, glyph_idx, start_x, 0
2437+
ft_object, fontsize, glyph_index, start_x, 0
24372438
)
24382439
self.file.output(Op.grestore)
24392440

2440-
def _draw_xobject_glyph(self, font, fontsize, glyph_idx, x, y):
2441+
def _draw_xobject_glyph(self, font, fontsize, glyph_index, x, y):
24412442
"""Draw a multibyte character from a Type 3 font as an XObject."""
2442-
glyph_name = font.get_glyph_name(glyph_idx)
2443+
glyph_name = font.get_glyph_name(glyph_index)
24432444
name = self.file._get_xobject_glyph_name(font.fname, glyph_name)
24442445
self.file.output(
24452446
Op.gsave,

lib/matplotlib/backends/backend_ps.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -797,20 +797,19 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
797797
else:
798798
features = language = None
799799
font = self._get_font_ttf(prop)
800-
self._character_tracker.track(font, s)
801800
for item in _text_helpers.layout(s, font, features=features,
802801
language=language):
802+
self._character_tracker.track_glyph(item.ft_object, item.glyph_index)
803803
ps_name = (item.ft_object.postscript_name
804804
.encode("ascii", "replace").decode("ascii"))
805805
glyph_name = item.ft_object.get_glyph_name(item.glyph_index)
806-
stream.append((ps_name, item.x, glyph_name))
806+
stream.append((ps_name, item.x, item.y, glyph_name))
807807
self.set_color(*gc.get_rgb())
808808

809-
for ps_name, group in itertools. \
810-
groupby(stream, lambda entry: entry[0]):
809+
for ps_name, group in itertools.groupby(stream, lambda entry: entry[0]):
811810
self.set_font(ps_name, prop.get_size_in_points(), False)
812-
thetext = "\n".join(f"{x:g} 0 m /{name:s} glyphshow"
813-
for _, x, name in group)
811+
thetext = "\n".join(f"{x:g} {y:g} m /{name:s} glyphshow"
812+
for _, x, y, name in group)
814813
self._pswriter.write(f"""\
815814
gsave
816815
{self._get_clip_cmd(gc)}

lib/matplotlib/textpath.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,15 +147,16 @@ def get_glyphs_with_font(self, font, s, glyph_map=None,
147147
glyph_map_new = glyph_map
148148

149149
xpositions = []
150+
ypositions = []
150151
glyph_ids = []
151152
for item in _text_helpers.layout(s, font, features=features, language=language):
152153
glyph_id = self._get_glyph_id(item.ft_object, item.glyph_index)
153154
glyph_ids.append(glyph_id)
154155
xpositions.append(item.x)
156+
ypositions.append(item.y)
155157
if glyph_id not in glyph_map:
156158
glyph_map_new[glyph_id] = item.ft_object.get_path()
157159

158-
ypositions = [0] * len(xpositions)
159160
sizes = [1.] * len(xpositions)
160161

161162
rects = []

src/ft2font.cpp

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -318,29 +318,13 @@ void FT2Font::set_kerning_factor(int factor)
318318
}
319319
}
320320

321-
void FT2Font::set_text(
322-
std::u32string_view text, double angle, FT_Int32 flags,
321+
std::vector<raqm_glyph_t> FT2Font::layout(
322+
std::u32string_view text, FT_Int32 flags,
323323
std::optional<std::vector<std::string>> features, LanguageType languages,
324-
std::vector<double> &xys)
324+
std::set<FT_String*>& glyph_seen_fonts)
325325
{
326-
FT_Matrix matrix; /* transformation matrix */
327-
328-
angle = angle * (2 * M_PI / 360.0);
329-
330-
// this computes width and height in subpixels so we have to multiply by 64
331-
double cosangle = cos(angle) * 0x10000L;
332-
double sinangle = sin(angle) * 0x10000L;
333-
334-
matrix.xx = (FT_Fixed)cosangle;
335-
matrix.xy = (FT_Fixed)-sinangle;
336-
matrix.yx = (FT_Fixed)sinangle;
337-
matrix.yy = (FT_Fixed)cosangle;
338-
339326
clear();
340327

341-
bbox.xMin = bbox.yMin = 32000;
342-
bbox.xMax = bbox.yMax = -32000;
343-
344328
auto rq = raqm_create();
345329
if (!rq) {
346330
throw std::runtime_error("failed to compute text layout");
@@ -387,7 +371,6 @@ void FT2Font::set_text(
387371
}
388372

389373
std::vector<std::pair<size_t, const FT_Face&>> face_substitutions;
390-
std::set<FT_String*> glyph_seen_fonts;
391374
glyph_seen_fonts.insert(face->family_name);
392375

393376
// Attempt to use fallback fonts if necessary.
@@ -474,9 +457,34 @@ void FT2Font::set_text(
474457
size_t num_glyphs = 0;
475458
auto const& rq_glyphs = raqm_get_glyphs(rq, &num_glyphs);
476459

477-
for (size_t i = 0; i < num_glyphs; i++) {
478-
auto const& rglyph = rq_glyphs[i];
460+
return std::vector<raqm_glyph_t>(rq_glyphs, rq_glyphs + num_glyphs);
461+
}
462+
463+
void FT2Font::set_text(
464+
std::u32string_view text, double angle, FT_Int32 flags,
465+
std::optional<std::vector<std::string>> features, LanguageType languages,
466+
std::vector<double> &xys)
467+
{
468+
FT_Matrix matrix; /* transformation matrix */
469+
470+
angle = angle * (2 * M_PI / 360.0);
471+
472+
// this computes width and height in subpixels so we have to multiply by 64
473+
double cosangle = cos(angle) * 0x10000L;
474+
double sinangle = sin(angle) * 0x10000L;
475+
476+
matrix.xx = (FT_Fixed)cosangle;
477+
matrix.xy = (FT_Fixed)-sinangle;
478+
matrix.yx = (FT_Fixed)sinangle;
479+
matrix.yy = (FT_Fixed)cosangle;
480+
481+
bbox.xMin = bbox.yMin = 32000;
482+
bbox.xMax = bbox.yMax = -32000;
483+
484+
std::set<FT_String*> glyph_seen_fonts;
485+
auto rq_glyphs = layout(text, flags, features, languages, glyph_seen_fonts);
479486

487+
for (auto const& rglyph : rq_glyphs) {
480488
// Warn for missing glyphs.
481489
if (rglyph.index == 0) {
482490
ft_glyph_warn(text[rglyph.cluster], glyph_seen_fonts);

src/ft2font.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ class FT2Font
113113
void set_size(double ptsize, double dpi);
114114
void set_charmap(int i);
115115
void select_charmap(unsigned long i);
116+
std::vector<raqm_glyph_t> layout(std::u32string_view text, FT_Int32 flags,
117+
std::optional<std::vector<std::string>> features,
118+
LanguageType languages,
119+
std::set<FT_String*>& glyph_seen_fonts);
116120
void set_text(std::u32string_view codepoints, double angle, FT_Int32 flags,
117121
std::optional<std::vector<std::string>> features,
118122
LanguageType languages, std::vector<double> &xys);

0 commit comments

Comments
 (0)