LiquidGlass UI 2.4.5 / SDK

文本渲染:DPI 原生覆盖与 SDF

原来的模糊来源

旧版按固定三倍逻辑字号生成灰度字形,再用线性纹理采样缩到最终尺寸。它并不等于对所有源像素做正确的面积缩小滤波;当字形落在非整数物理像素、控件处于细小缩放动画中,或实际 DPI 与缓存倍率不同,边缘可能额外发软。

抗锯齿本身也不是“越模糊越正确”。本次没有在文字上叠加全屏后处理,而是分别处理字形缓存、最终像素位置和边缘重建。

三种模式

ui.theme().textMode(TextMode.AUTO);      // 默认
ui.theme().textMode(TextMode.COVERAGE);  // 固定尺寸小字
ui.theme().textMode(TextMode.SDF);       // 缩放与较大文字

AUTO:物理字号不超过 24 像素时使用 DPI 原生灰度覆盖;更大文字或相对 1.0 超过 1.8% 的缩放使用 SDF。覆盖字形和相应 SDF 会在首次需要时预热,按压动画不按每个小数缩放值重新栅格化。自动路径在阈值处可能有小幅字形观感差别;持续缩放的大标题可以固定 SDF 模式。

COVERAGE:按实际物理像素字号缓存系统字体。静止且 scale 约等于 1 时,可以将文本起点、基线和字形位置对齐物理像素;没有把整行布局整数化,字距仍使用真实 advance 和可选 tracking。

SDF:字形轮廓先在 64 像素 em 的本地缓存中栅格化,再通过精确的分离平方欧氏距离变换生成单通道有符号距离。shader 从距离、屏幕导数及可配置对比度重建边缘。它不是把 alpha 模糊后宣称 SDF,也没有实现多通道边缘着色的 MSDF。细小字形/复杂尖角不保证比所有字体 hinting 方案更好。

控制项

Theme t = ui.theme();
t.antialiasing(Antialiasing.HIGH);
t.textMode(TextMode.AUTO);
t.pixelSnap(true);
t.textContrast(1.05f);       // 0.5..2,边缘重建对比度,不是字体粗细
 t.letterSpacing(0.25f);     // 逻辑单位;绘制和 textWidth 都生效
 t.fonts("Segoe UI", "Microsoft YaHei UI");

Label.weight(400/500/600)、Painter.textWeight() 和 textWeightScaled() 继续支持字重。tracking 不替代复杂 shaping / kerning 引擎。输入框选区和文字布局沿用当前测量结果。

宿主显式传入 DPI:

painter.begin(logicalWidth, logicalHeight, pixelWidth, pixelHeight);
ui.render(painter, logicalWidth, logicalHeight, elapsedSeconds);
painter.flush(framebufferId, colorAttachment, pixelWidth, pixelHeight,
              ui.theme().sigma, mouseX, mouseY);

新的 DesktopWindow 和 HostIntegration 示例已经使用该重载。旧的 begin(width,height) 仍兼容,但只能沿用上一次 flush 的缩放,第一次绘制或 DPI 切换那一帧可能不准确。

字体与缓存边界

根据本机实际安装情况分别选择拉丁/CJK 字体。名称不存在会回退,日志显示实际字体。既支持 Theme.fonts,也保留 -Dliquidglass.font=... / -Dliquidglass.cjkFont=...。不联网下载,不打包字体文件。

字形图集为 2048² RGBA 页,最多 12 页 / 18,000 条缓存项。大量不断变化的字号或字体组合仍可能达到上限;此版本没有无限增长或隐式驱逐。SDF 生成只发生在字形缓存未命中时,在 CPU 上执行;每帧显示和 SDF 边缘重建在 GPU 上。玻璃曲线、折射和背景模糊不在 CPU 上逐像素计算。

文本仍不是完整双向/复杂文字 shaping 系统。普通中英文混排与输入已测试,不据此宣称所有文字系统、Windows 原生 IME 或屏幕阅读器支持完整。