Skip to content

feat(fontconfig): 字体发现 —— 七个生成物全部由 build.mcpp 产出 - #310

Merged
Sunrisepeak merged 2 commits into
mainfrom
feat/fontconfig
Aug 30, 2026
Merged

feat(fontconfig): 字体发现 —— 七个生成物全部由 build.mcpp 产出#310
Sunrisepeak merged 2 commits into
mainfrom
feat/fontconfig

Conversation

@Sunrisepeak

Copy link
Copy Markdown
Member

freetype 光栅化字形、harfbuzz 整形一段文字,但两者都答不了**「给我一个带 CJK 的无衬线字体」**。那是 fontconfig,而 cairo 和 pango 都要它。

配套 fork:mcpplibs/fontconfig(新建,CI 绿)。

七个生成物,零 python / 零 sh / 零 gperf

上游 meson 用 python 和 gperf 产出七个。七个全是对 tarball 里已有文件的文本变换,所以 build.mcpp(mcpp 编译并运行的 C++)把它们全做了。

生成物 验证
fcstdint.h
fcalias.h / fcaliastail.h 复刻 makealias.py,含分组顺序
fcftalias.h / fcftaliastail.h 同上
fcobjshash.h 二分查找替掉 gperf 完美哈希
fclang.h 4897 行,与上游逐字节一致
fccase.h 368 行,与上游逐字节一致
src/fontconfig.cppm 模块包装

fork CI 每次重跑上游的 python 再 diff —— 转写只有被拿去和原件对照才值得有。

fcobjshash.h 是判断而非转写:上游跑 C 预处理器 + gperf 做 72 条目的完美哈希,而唯一消费者 fcobjs.cFcObjectTypeLookup(str, strlen(str)) 只读一个字段。排序表 + 二分查找语义相同,少两个工具、少一遍预处理。

⚠ 两个 freetype 探测项关掉了

HAVE_FT_GET_BDF_PROPERTYHAVE_FT_GET_PS_FONT_INFO 缺席,因为 compat.freetype 不编 BDF 和 Type1 模块。声明了能编过,链接时八个未定义引用 —— 探测答案必须描述这一套 freetype,不是上游默认构建。

丢的是 BDF 属性和 PostScript FontInfo 两个元数据源,而它们对应的格式 compat.freetype 本来也不解码,所以配对是一致的。

运行期路径留空

五条(FC_DEFAULT_FONTS / FC_FONTPATH / FC_CACHEDIR / CONFIGDIR / FONTCONFIG_PATH)—— 上游指向构建前缀,重定位后是宿主的字体与配置。FONTCONFIG_FILE / FONTCONFIG_PATH / FONTCONFIG_SYSROOT 是环境出口,和 XKB_CONFIG_ROOT 同一形状。

测试

直打三张生成表:

FcNameParse("Arial:pixelsize=12:slant=100")   family=Arial pixelsize=12 slant=100   ok
lang en    ->   72 codepoints      lang ru -> 66      lang zh-cn -> 6765
…and English and Russian are different sets                                        ok
…and English covers 'A' / Russian covers U+0416 / English does not                 ok
downcase("ABC") = abc      downcase(U+0410) = U+0430                               ok
0 check(s) failed

只改了 pkgs/tests/examples/

freetype 光栅化字形、harfbuzz 整形一段文字,但两者都答不了「给我一个带 CJK 的
无衬线字体」。那是 fontconfig,而 cairo 和 pango 都要它。

上游 meson 用 python 和 gperf 产出七个生成物,七个全是对 tarball 里已有文件的
文本变换,所以 fork 的 build.mcpp(mcpp 编译并运行的 C++)把它们全做了。这个包
不需要 python3、sh 或 gperf。

两个大的与上游**逐字节一致**,fork CI 每次重跑上游脚本再 diff:
    fclang.h  4897 行   281 个 .orth -> charset 位图
    fccase.h   368 行   Unicode 大小写折叠
转写只有被拿去和原件对照才值得有。

fcobjshash.h 是**判断**而非转写:上游跑 C 预处理器 + gperf 做 72 条目的完美哈希,
而唯一消费者 fcobjs.c 只调 FcObjectTypeLookup 读一个字段。排序表 + 二分查找语义
相同,少两个工具、少一遍预处理。

五条运行期路径留空(FC_DEFAULT_FONTS / FC_FONTPATH / FC_CACHEDIR / CONFIGDIR /
FONTCONFIG_PATH)——上游指向构建前缀,重定位后是宿主的字体与配置。
FONTCONFIG_FILE / FONTCONFIG_PATH / FONTCONFIG_SYSROOT 是环境出口。

⚠ HAVE_FT_GET_BDF_PROPERTY 与 HAVE_FT_GET_PS_FONT_INFO **关掉**,因为
compat.freetype 不编 BDF 和 Type1 模块。声明了能编过,链接时八个未定义引用。
探测答案必须描述**这一套** freetype,不是上游默认构建。

测试直打三张生成表:FcNameParse 走对象表、FcLangGetCharSet 走 fclang
(zh-cn 6765 码点、ru 与 en 不同集)、FcStrDowncase 走 fccase(含西里尔两字节折叠)。

只改 pkgs/ 与 tests/examples/。
    error: implicit instantiation of undefined template
           'std::basic_istringstream<char>'

libstdc++ 通过 <fstream> 传递包含了它,libc++ 没有。这正是 validate.yml 注释里
说的「gcc 腿结构上看不见的一类 bug」。

重发 tarball(mcpp3),并在重发前用 mcpp toolchain default llvm 在本地跑过一遍
clang——免得再耗一轮 CI 才发现下一个同类问题。
@Sunrisepeak
Sunrisepeak merged commit ad060ce into main Aug 30, 2026
11 checks passed
@Sunrisepeak
Sunrisepeak deleted the feat/fontconfig branch August 30, 2026 14:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant