feat(client): 字体改本地打包(拉丁全量 + Noto Sans SC GB2312 子集)

生产 PangolinFonts.useBundled=true,离线可用,不再运行时拉 google_fonts;
中文经 fontFamilyFallback=[Noto Sans SC] 兜底,子集外字符再兜系统 CJK 字体。
- 拉丁:Sora/Manrope/JetBrains Mono 静态权重(复用 test/fonts)。
- 中文:Noto Sans SC 变量字体 instance 到 Regular + subset 到 GB2312 6763 字
  (单权重,粗体引擎合成),client/fonts 合计约 3.4MB。
- tools/fonts/make-cjk-subset.sh 可复现生成(GB2312 字表无需联网)。
- 新增 test/unit/fonts_test.dart 锁定接线;golden 因 notdef 占位字形微调已更新。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-22 07:48:21 +08:00
parent 14498a3ccd
commit 6fc032bac8
19 changed files with 163 additions and 7 deletions
+54
View File
@@ -0,0 +1,54 @@
// fonts_test.dart — 本地打包字体接线回归。
//
// 锁定 Task 3 的字体改造:生产走 bundled family(非 google_fonts 运行时拉取),
// 且每个字体函数都把中文兜到 Noto Sans SCfontFamilyFallback: [cjk])。
// flutter_test_config.dart 在测试启动已置 PangolinFonts.useBundled = true。
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:pangolin_vpn/pangolin_theme.dart';
void main() {
group('PangolinFonts 本地打包接线', () {
test('测试态(useBundled=true)由 flutter_test_config 设置', () {
// 该 hook 由 test/flutter_test_config.dart 在所有测试前置 true
// 生产代码默认值也是 true(见 pangolin_theme.dart)。
expect(PangolinFonts.useBundled, isTrue);
});
test('cjk family 为 Noto Sans SC(与 pubspec fonts: 段一致)', () {
expect(PangolinFonts.cjk, 'Noto Sans SC');
});
test('sora() 用 bundled display family 且中文兜底到 cjk', () {
final s = PangolinFonts.sora(fontSize: 16);
expect(s.fontFamily, PangolinFonts.display);
expect(s.fontFamilyFallback, contains(PangolinFonts.cjk));
});
test('manrope() 用 bundled sans family 且中文兜底到 cjk', () {
final s = PangolinFonts.manrope(fontSize: 16);
expect(s.fontFamily, PangolinFonts.sans);
expect(s.fontFamilyFallback, contains(PangolinFonts.cjk));
});
test('jetBrainsMono() 用 bundled mono family 且中文兜底到 cjk', () {
final s = PangolinFonts.jetBrainsMono(fontSize: 14);
expect(s.fontFamily, PangolinFonts.mono);
expect(s.fontFamilyFallback, contains(PangolinFonts.cjk));
});
test('manropeTextTheme 应用 sans family 且中文兜底到 cjk', () {
const base = TextTheme(bodyMedium: TextStyle(fontSize: 16));
final t = PangolinFonts.manropeTextTheme(base);
expect(t.bodyMedium?.fontFamily, PangolinFonts.sans);
expect(t.bodyMedium?.fontFamilyFallback, contains(PangolinFonts.cjk));
});
test('PangolinText 标度经由 bundled 接线(中文兜底存在)', () {
// 抽查几个常用标度,确保未绕过 PangolinFonts 封装。
expect(PangolinText.h1.fontFamilyFallback, contains(PangolinFonts.cjk));
expect(PangolinText.body.fontFamilyFallback, contains(PangolinFonts.cjk));
expect(PangolinText.mono.fontFamilyFallback, contains(PangolinFonts.cjk));
});
});
}