跳到正文

ADR-0007:进阶布局与字体组缺字策略 ​

背景 ​

基础分页与组件已形成闭环,但报告需要标题层级、富文本、混合纸张、合并表格、脚注、嵌套续页和中文可编辑字段。调用方还要求按字体或字体组明确选择缺字报错,或显示占位符并返回警告。

模型仍须独立于字体句柄、绘制和 PDFBox;布局核心不能反向依赖组件实现。新增能力必须有可运行输出与独立验证。

决策 ​

  1. 模型增加分页策略、行内样式、命名样式、标题、显式分页、分节与语义引用。字体角色在布局入口解析,真实粗斜体使用真实字体资源。
  2. 字体模块以 FontGroup 携带有序成员与缺字策略。默认 ERROR,显式 PLACEHOLDER_WITH_WARNING 才能替换;先遍历整组。占位符也缺字、非法 Unicode、复杂塑形仍失败。
  3. 文本层同时保留绘制码点与原文码点,替换不改变原 UTF-16 来源范围。返回结构化 WARNING,日志输出由调用方负责。所有正文、目录、页区和标准嵌套组件传递同一组策略。
  4. 核心增加 PageableComponent SPI,扩展一次测量返回有序片段;首片段可使用当前剩余高度。标准组件负责 FlowColumn、FlowText、Row 和合并 GridTable;核心只依赖接口。
  5. 每节从新页开始,首页/奇偶模板预留最大页区。分离物理页索引与可重置显示页码;目录、引用和交互均在最终物理页确定后解析。
  6. 编号与题注在组件编排层降低为段落,引用使用固定单行区域。脚注采用每节最大区域的单调预留,最多 32 次,接受保守留白;尾注追加至最后一节。
  7. 图像由显式字节有界解码,保留 alpha。SVG 只支持离线白名单矢量子集,对未知特性明确失败,并裁剪至 viewBox。
  8. 中文表单完整嵌入一个显式字体;下拉框与单选组保留规范字段树、值和外观。表单不使用正文的缺字替换策略,避免改变填写数据。

考虑的替代方案 ​

  • 默认替换缺字会隐藏排版质量问题,因此保留严格默认值;系统字体扫描会破坏可复现性,因此仍只使用显式字体。
  • 在核心直接实现全部组件会产生反向依赖,因此分页组件通过 SPI 接入。
  • 引用文字依赖分页且可反过来改变分页,采用固定区域避免无上限重排;溢出明确失败。
  • 按每页精确脚注高度反复重排可能振荡,首版采用单调的全节预留;未来可独立扩展更紧凑的算法。
  • 表单仅嵌入初始字形会阻止后续新字符编辑,因此使用完整字体并执行输出预算。
  • 完整 SVG、复杂塑形与 Word 兼容需要独立契约和测试集,不以当前子集替代。

影响 ​

保留常用旧构造器和字体列表重载,但 record 结构、新枚举与 sealed 成员变化不保证已有二进制、反射序列化或 exhaustive switch 兼容。模型仍为 JDK-only,公共 API 不泄漏第三方类型。

GridTable 的跨行连通组不可拆分,Row 整体不可拆分;脚注可能引入留白;引用不自动扩展区域。库返回诊断,不自动打印日志。自定义组件是可信 Java 代码,不属于执行沙箱。

验证 ​

JUnit 覆盖最低行数、保持链、分页推进、富文本来源、字体组策略、嵌套片段、合并组、分节页码、最终目标、脚注、Unicode 表单和透明图像。综合示例以 pypdf 检查结构及保存重开,用 Poppler 与 PDFium 渲染全部页面,并保存经人工检查的像素基线。基准记录 5,000 段落布局,指标与限制见进阶验收记录。