mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-10-14 19:27:09 -04:00
* Support CJK text with the device's own fonts The Linux runtime's rootfs ships DejaVu alone, which has no CJK glyphs, so Chinese, Japanese and Korean text in Steam Big Picture and on the LXQt desktop draws as tofu boxes (issues #118, #206, #249). Bind the device's own CJK fonts - Android's world-readable Noto CJK .ttc, or DroidSansFallback / Source Han - into the guest under /usr/share/fonts/droiddeck-cjk, so nothing is added to the ~790 MB runtime image and the coverage follows the device. A new droiddeck-fonts script, run by droiddeck-session before any program that queries fontconfig, links the default rules, writes local.conf with DejaVu first and the CJK families after it, and rebuilds the fontconfig cache once per set of font files. The desktop's own fontconfig block moves there, so every mode gets it. * Fix CJK and Thai: bind the device font directory, not one file at a time The first cut bound each device font with its own proot -b host:guest. A per-file binding into a plain directory is not applied here: the guest sees a zero-byte placeholder where the font should be (stat size=0, fc-scan empty), so Chinese stayed tofu even though the app had "bound" the font. A directory binding is what the rest of the runtime relies on, so bind /system/fonts as a whole under /usr/share/fonts/droiddeck-device. That also brings Thai, Arabic, Devanagari and the emoji fonts, which the runtime did not have either. Verified on the AYN Thor: the session's fontconfig probe reports sans=DejaVu Sans, zh=Noto Sans CJK SC, th=Noto Serif Thai, and Steam Big Picture in Simplified Chinese renders without tofu (screenshot under docs/development/evidence/). --------- Co-authored-by: xXJsonDeruloXx <[email protected]>
77 lines
3.3 KiB
Python
77 lines
3.3 KiB
Python
import subprocess
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
|
|
FONTS = Path(__file__).resolve().parents[1] / "linuxfs/overlay/usr/local/bin/droiddeck-fonts"
|
|
SESSION = Path(__file__).resolve().parents[1] / "linuxfs/overlay/usr/local/bin/droiddeck-session"
|
|
|
|
|
|
class DroidDeckFontsTest(unittest.TestCase):
|
|
def setUp(self):
|
|
temporary = tempfile.TemporaryDirectory()
|
|
self.addCleanup(temporary.cleanup)
|
|
self.root = Path(temporary.name)
|
|
defaults = self.root / "usr/share/fontconfig/conf.default"
|
|
defaults.mkdir(parents=True)
|
|
(defaults / "60-latin.conf").write_text("<fontconfig/>")
|
|
dejavu = self.root / "usr/share/fonts/truetype/dejavu"
|
|
dejavu.mkdir(parents=True)
|
|
(dejavu / "DejaVuSans.ttf").write_text("dejavu")
|
|
|
|
def run_fonts(self):
|
|
subprocess.run(["bash", str(FONTS), str(self.root)], check=True, capture_output=True)
|
|
|
|
def local_conf(self):
|
|
return (self.root / "etc/fonts/local.conf").read_text()
|
|
|
|
def owned_conf(self):
|
|
return (self.root / "etc/fonts/conf.d/65-droiddeck-default-fonts.conf").read_text()
|
|
|
|
def test_default_rules_linked_and_dejavu_is_the_default(self):
|
|
self.run_fonts()
|
|
self.assertTrue((self.root / "etc/fonts/conf.d/60-latin.conf").is_symlink())
|
|
text = self.owned_conf()
|
|
self.assertIn("<family>sans-serif</family><prefer><family>DejaVu Sans</family>", text)
|
|
self.assertIn("<family>monospace</family><prefer><family>DejaVu Sans Mono</family>", text)
|
|
self.assertNotIn("Noto Sans CJK", text)
|
|
self.assertFalse((self.root / "etc/fonts/local.conf").exists())
|
|
|
|
def test_an_existing_conf_d_rule_is_not_replaced(self):
|
|
conf_d = self.root / "etc/fonts/conf.d"
|
|
conf_d.mkdir(parents=True)
|
|
(conf_d / "60-latin.conf").write_text("mine")
|
|
self.run_fonts()
|
|
self.assertFalse((conf_d / "60-latin.conf").is_symlink())
|
|
self.assertEqual("mine", (conf_d / "60-latin.conf").read_text())
|
|
|
|
def test_custom_local_conf_survives_and_device_language_fallback_remains_configured(self):
|
|
custom = self.root / "etc/fonts/local.conf"
|
|
custom.parent.mkdir(parents=True, exist_ok=True)
|
|
custom.write_text("<fontconfig><rescan><int>45</int></rescan></fontconfig>")
|
|
self.run_fonts()
|
|
self.assertEqual("<fontconfig><rescan><int>45</int></rescan></fontconfig>", self.local_conf())
|
|
session = SESSION.read_text()
|
|
self.assertIn('device_fonts=/usr/local/share/fonts/android', session)
|
|
self.assertIn('zh-cn=Noto Sans CJK SC', session)
|
|
self.assertIn('ja=Noto Sans CJK JP', session)
|
|
self.assertIn('ko=Noto Sans CJK KR', session)
|
|
self.assertIn('th=Noto Sans Thai', session)
|
|
|
|
def test_unchanged_fonts_do_not_rewrite_owned_conf(self):
|
|
self.run_fonts()
|
|
owned = self.root / "etc/fonts/conf.d/65-droiddeck-default-fonts.conf"
|
|
before = owned.stat().st_mtime_ns
|
|
self.run_fonts()
|
|
self.assertEqual(before, owned.stat().st_mtime_ns)
|
|
|
|
def test_the_session_runs_the_bootstrap_before_it_starts_a_program(self):
|
|
text = SESSION.read_text()
|
|
self.assertIn("/usr/local/bin/droiddeck-fonts", text)
|
|
self.assertLess(text.index("droiddeck-fonts"), text.index("droiddeck-steam-install"))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|