Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/lib/python/kdoc/latex_fonts.py
122941 views
1
#!/usr/bin/env python3
2
# SPDX-License-Identifier: GPL-2.0-only
3
# Copyright (C) Akira Yokosawa, 2024
4
#
5
# Ported to Python by (c) Mauro Carvalho Chehab, 2025
6
7
"""
8
Detect problematic Noto CJK variable fonts
9
==========================================
10
11
For ``make pdfdocs``, reports of build errors of translations.pdf started
12
arriving early 2024 [1]_ [2]_. It turned out that Fedora and openSUSE
13
tumbleweed have started deploying variable-font [3]_ format of "Noto CJK"
14
fonts [4]_ [5]_. For PDF, a LaTeX package named xeCJK is used for CJK
15
(Chinese, Japanese, Korean) pages. xeCJK requires XeLaTeX/XeTeX, which
16
does not (and likely never will) understand variable fonts for historical
17
reasons.
18
19
The build error happens even when both of variable- and non-variable-format
20
fonts are found on the build system. To make matters worse, Fedora enlists
21
variable "Noto CJK" fonts in the requirements of langpacks-ja, -ko, -zh_CN,
22
-zh_TW, etc. Hence developers who have interest in CJK pages are more
23
likely to encounter the build errors.
24
25
This script is invoked from the error path of "make pdfdocs" and emits
26
suggestions if variable-font files of "Noto CJK" fonts are in the list of
27
fonts accessible from XeTeX.
28
29
.. [1] https://lore.kernel.org/r/[email protected]/
30
.. [2] https://lore.kernel.org/r/[email protected]/
31
.. [3] https://en.wikipedia.org/wiki/Variable_font
32
.. [4] https://fedoraproject.org/wiki/Changes/Noto_CJK_Variable_Fonts
33
.. [5] https://build.opensuse.org/request/show/1157217
34
35
Workarounds for building translations.pdf
36
-----------------------------------------
37
38
* Denylist "variable font" Noto CJK fonts.
39
40
- Create $HOME/deny-vf/fontconfig/fonts.conf from template below, with
41
tweaks if necessary. Remove leading "".
42
43
- Path of fontconfig/fonts.conf can be overridden by setting an env
44
variable FONTS_CONF_DENY_VF.
45
46
* Template::
47
48
<?xml version="1.0"?>
49
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
50
<fontconfig>
51
<!--
52
Ignore variable-font glob (not to break xetex)
53
-->
54
<selectfont>
55
<rejectfont>
56
<!--
57
for Fedora
58
-->
59
<glob>/usr/share/fonts/google-noto-*-cjk-vf-fonts</glob>
60
<!--
61
for openSUSE tumbleweed
62
-->
63
<glob>/usr/share/fonts/truetype/Noto*CJK*-VF.otf</glob>
64
</rejectfont>
65
</selectfont>
66
</fontconfig>
67
68
The denylisting is activated for "make pdfdocs".
69
70
* For skipping CJK pages in PDF
71
72
- Uninstall texlive-xecjk.
73
Denylisting is not needed in this case.
74
75
* For printing CJK pages in PDF
76
77
- Need non-variable "Noto CJK" fonts.
78
79
* Fedora
80
81
- google-noto-sans-cjk-fonts
82
- google-noto-serif-cjk-fonts
83
84
* openSUSE tumbleweed
85
86
- Non-variable "Noto CJK" fonts are not available as distro packages
87
as of April, 2024. Fetch a set of font files from upstream Noto
88
CJK Font released at:
89
90
https://github.com/notofonts/noto-cjk/tree/main/Sans#super-otc
91
92
and at:
93
94
https://github.com/notofonts/noto-cjk/tree/main/Serif#super-otc
95
96
then uncompress and deploy them.
97
- Remember to update fontconfig cache by running fc-cache.
98
99
.. caution::
100
Uninstalling "variable font" packages can be dangerous.
101
They might be depended upon by other packages important for your work.
102
Denylisting should be less invasive, as it is effective only while
103
XeLaTeX runs in "make pdfdocs".
104
"""
105
106
import os
107
import re
108
import subprocess
109
import textwrap
110
import sys
111
112
class LatexFontChecker:
113
"""
114
Detect problems with CJK variable fonts that affect PDF builds for
115
translations.
116
"""
117
118
def __init__(self, deny_vf=None):
119
if not deny_vf:
120
deny_vf = os.environ.get('FONTS_CONF_DENY_VF', "~/deny-vf")
121
122
self.environ = os.environ.copy()
123
self.environ['XDG_CONFIG_HOME'] = os.path.expanduser(deny_vf)
124
125
self.re_cjk = re.compile(r"([^:]+):\s*Noto\s+(Sans|Sans Mono|Serif) CJK")
126
127
def description(self):
128
"""
129
Returns module description.
130
"""
131
return __doc__
132
133
def get_noto_cjk_vf_fonts(self):
134
"""
135
Get Noto CJK fonts.
136
"""
137
138
cjk_fonts = set()
139
cmd = ["fc-list", ":", "file", "family", "variable"]
140
try:
141
result = subprocess.run(cmd,stdout=subprocess.PIPE,
142
stderr=subprocess.PIPE,
143
universal_newlines=True,
144
env=self.environ,
145
check=True)
146
147
except subprocess.CalledProcessError as exc:
148
sys.exit(f"Error running fc-list: {repr(exc)}")
149
150
for line in result.stdout.splitlines():
151
if 'variable=True' not in line:
152
continue
153
154
match = self.re_cjk.search(line)
155
if match:
156
cjk_fonts.add(match.group(1))
157
158
return sorted(cjk_fonts)
159
160
def check(self):
161
"""
162
Check for problems with CJK fonts.
163
"""
164
165
fonts = textwrap.indent("\n".join(self.get_noto_cjk_vf_fonts()), " ")
166
if not fonts:
167
return None
168
169
rel_file = os.path.relpath(__file__, os.getcwd())
170
171
msg = "=" * 77 + "\n"
172
msg += 'XeTeX is confused by "variable font" files listed below:\n'
173
msg += fonts + "\n"
174
msg += textwrap.dedent(f"""
175
For CJK pages in PDF, they need to be hidden from XeTeX by denylisting.
176
Or, CJK pages can be skipped by uninstalling texlive-xecjk.
177
178
For more info on denylisting, other options, and variable font, run:
179
180
tools/docs/check-variable-fonts.py -h
181
""")
182
msg += "=" * 77
183
184
return msg
185
186