| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- #!/usr/bin/env python3
- # SPDX-License-Identifier: GPL-2.0-only
- # Copyright (C) Akira Yokosawa, 2024
- #
- # Ported to Python by (c) Mauro Carvalho Chehab, 2025
- """
- Detect problematic Noto CJK variable fonts
- ==========================================
- For ``make pdfdocs``, reports of build errors of translations.pdf started
- arriving early 2024 [1]_ [2]_. It turned out that Fedora and openSUSE
- tumbleweed have started deploying variable-font [3]_ format of "Noto CJK"
- fonts [4]_ [5]_. For PDF, a LaTeX package named xeCJK is used for CJK
- (Chinese, Japanese, Korean) pages. xeCJK requires XeLaTeX/XeTeX, which
- does not (and likely never will) understand variable fonts for historical
- reasons.
- The build error happens even when both of variable- and non-variable-format
- fonts are found on the build system. To make matters worse, Fedora enlists
- variable "Noto CJK" fonts in the requirements of langpacks-ja, -ko, -zh_CN,
- -zh_TW, etc. Hence developers who have interest in CJK pages are more
- likely to encounter the build errors.
- This script is invoked from the error path of "make pdfdocs" and emits
- suggestions if variable-font files of "Noto CJK" fonts are in the list of
- fonts accessible from XeTeX.
- .. [1] https://lore.kernel.org/r/8734tqsrt7.fsf@meer.lwn.net/
- .. [2] https://lore.kernel.org/r/1708585803.600323099@f111.i.mail.ru/
- .. [3] https://en.wikipedia.org/wiki/Variable_font
- .. [4] https://fedoraproject.org/wiki/Changes/Noto_CJK_Variable_Fonts
- .. [5] https://build.opensuse.org/request/show/1157217
- Workarounds for building translations.pdf
- -----------------------------------------
- * Denylist "variable font" Noto CJK fonts.
- - Create $HOME/deny-vf/fontconfig/fonts.conf from template below, with
- tweaks if necessary. Remove leading "".
- - Path of fontconfig/fonts.conf can be overridden by setting an env
- variable FONTS_CONF_DENY_VF.
- * Template::
- <?xml version="1.0"?>
- <!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
- <fontconfig>
- <!--
- Ignore variable-font glob (not to break xetex)
- -->
- <selectfont>
- <rejectfont>
- <!--
- for Fedora
- -->
- <glob>/usr/share/fonts/google-noto-*-cjk-vf-fonts</glob>
- <!--
- for openSUSE tumbleweed
- -->
- <glob>/usr/share/fonts/truetype/Noto*CJK*-VF.otf</glob>
- </rejectfont>
- </selectfont>
- </fontconfig>
- The denylisting is activated for "make pdfdocs".
- * For skipping CJK pages in PDF
- - Uninstall texlive-xecjk.
- Denylisting is not needed in this case.
- * For printing CJK pages in PDF
- - Need non-variable "Noto CJK" fonts.
- * Fedora
- - google-noto-sans-cjk-fonts
- - google-noto-serif-cjk-fonts
- * openSUSE tumbleweed
- - Non-variable "Noto CJK" fonts are not available as distro packages
- as of April, 2024. Fetch a set of font files from upstream Noto
- CJK Font released at:
- https://github.com/notofonts/noto-cjk/tree/main/Sans#super-otc
- and at:
- https://github.com/notofonts/noto-cjk/tree/main/Serif#super-otc
- then uncompress and deploy them.
- - Remember to update fontconfig cache by running fc-cache.
- .. caution::
- Uninstalling "variable font" packages can be dangerous.
- They might be depended upon by other packages important for your work.
- Denylisting should be less invasive, as it is effective only while
- XeLaTeX runs in "make pdfdocs".
- """
- import os
- import re
- import subprocess
- import textwrap
- import sys
- class LatexFontChecker:
- """
- Detect problems with CJK variable fonts that affect PDF builds for
- translations.
- """
- def __init__(self, deny_vf=None):
- if not deny_vf:
- deny_vf = os.environ.get('FONTS_CONF_DENY_VF', "~/deny-vf")
- self.environ = os.environ.copy()
- self.environ['XDG_CONFIG_HOME'] = os.path.expanduser(deny_vf)
- self.re_cjk = re.compile(r"([^:]+):\s*Noto\s+(Sans|Sans Mono|Serif) CJK")
- def description(self):
- """
- Returns module description.
- """
- return __doc__
- def get_noto_cjk_vf_fonts(self):
- """
- Get Noto CJK fonts.
- """
- cjk_fonts = set()
- cmd = ["fc-list", ":", "file", "family", "variable"]
- try:
- result = subprocess.run(cmd,stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- universal_newlines=True,
- env=self.environ,
- check=True)
- except subprocess.CalledProcessError as exc:
- sys.exit(f"Error running fc-list: {repr(exc)}")
- for line in result.stdout.splitlines():
- if 'variable=True' not in line:
- continue
- match = self.re_cjk.search(line)
- if match:
- cjk_fonts.add(match.group(1))
- return sorted(cjk_fonts)
- def check(self):
- """
- Check for problems with CJK fonts.
- """
- fonts = textwrap.indent("\n".join(self.get_noto_cjk_vf_fonts()), " ")
- if not fonts:
- return None
- rel_file = os.path.relpath(__file__, os.getcwd())
- msg = "=" * 77 + "\n"
- msg += 'XeTeX is confused by "variable font" files listed below:\n'
- msg += fonts + "\n"
- msg += textwrap.dedent(f"""
- For CJK pages in PDF, they need to be hidden from XeTeX by denylisting.
- Or, CJK pages can be skipped by uninstalling texlive-xecjk.
- For more info on denylisting, other options, and variable font, run:
- tools/docs/check-variable-fonts.py -h
- """)
- msg += "=" * 77
- return msg
|