1
0
Files
PPTX/openspec/specs/font-theme/spec.md
lanyuanxiaoyao bd12fce14b feat: 实现字体主题系统和东亚字体支持
实现完整的字体主题系统,支持可复用字体配置、预设类别和扩展属性。
同时修复中文字体渲染问题,确保 Source Han Sans 等东亚字体正确显示。

核心功能:
- 字体主题配置:metadata.fonts 和 fonts_default
- 三种引用方式:整体引用、继承覆盖、独立定义
- 预设字体类别:sans、serif、mono、cjk-sans、cjk-serif
- 扩展字体属性:family、underline、strikethrough、line_spacing、
  space_before、space_after、baseline、caps
- 表格字体字段:font 和 header_font 替代旧的 style.font_size
- 引用循环检测和属性继承链
- 模板字体继承支持

东亚字体修复:
- 添加 _set_font_with_eastasian() 方法
- 同时设置拉丁字体、东亚字体和复杂脚本字体
- 修复中文字符使用默认字体的问题

测试:
- 58 个单元测试覆盖所有字体系统功能
- 3 个集成测试验证端到端场景
- 移除旧语法相关测试

文档:
- 更新 README.md 添加字体主题系统使用说明
- 更新 README_DEV.md 添加技术文档
- 创建 4 个示例 YAML 文件
- 同步 delta specs 到主 specs

归档:
- 归档 font-theme-system 变更到 openspec/changes/archive/

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-03-05 10:38:59 +08:00

7.1 KiB
Raw Blame History

Font Theme

Purpose

字体主题系统提供可复用的字体配置管理能力,允许用户在 metadata 中定义字体配置模板,通过引用方式应用到元素,实现统一的字体样式管理。

Requirements

Requirement: 系统必须支持在 metadata 中定义 fonts 字段

系统 SHALL 支持在 YAML metadata 中定义 fonts 字段,用于存储可复用的字体配置。

Scenario: 定义 fonts 字段

  • WHEN metadata 中定义 fonts 字段
  • THEN 系统成功解析并存储字体配置字典

Scenario: fonts 字段为空字典

  • WHEN metadata 中定义 fonts: {}
  • THEN 系统接受空的字体配置字典

Scenario: fonts 字段未定义

  • WHEN metadata 中未定义 fonts 字段
  • THEN 系统正常处理fonts 为空字典

Requirement: fonts 字段必须包含命名字体配置

fonts 字段 SHALL 包含一个或多个命名字体配置,每个配置是一个字体属性字典。

Scenario: 定义单个字体配置

  • WHEN fonts 中定义 title: {family: "Arial", size: 44, bold: true}
  • THEN 系统创建名为 title 的字体配置

Scenario: 定义多个字体配置

  • WHEN fonts 中定义 title、subtitle、body 等多个配置
  • THEN 系统为每个配置创建独立的字体对象

Requirement: 系统必须支持 fonts_default 字段

系统 SHALL 支持在 metadata 中定义可选的 fonts_default 字段,指定默认字体配置的引用。

Scenario: 定义 fonts_default 引用

  • WHEN metadata 中定义 fonts_default: "@body"
  • THEN 系统将 fonts_default 解析为对 fonts.body 的引用

Scenario: fonts_default 未定义

  • WHEN metadata 中未定义 fonts_default 字段
  • THEN 系统使用 python-pptx 的默认字体

Scenario: fonts_default 引用不存在的配置

  • WHEN fonts_default: "@undefined" 且 fonts.undefined 不存在
  • THEN 系统抛出 ERROR提示引用的字体配置不存在

Scenario: fonts_default 必须引用 fonts 中的配置

  • WHEN fonts_default: "Arial"(直接字体名称)
  • THEN 系统抛出 ERROR提示 fonts_default 必须是引用格式

Requirement: 元素 font 字段必须支持三种引用方式

元素 font 字段 SHALL 支持字符串引用(整体引用)、字典引用(继承覆盖或独立定义)两种形式。

Scenario: 字符串整体引用

  • WHEN 元素定义 font: "@title"
  • THEN 系统使用 fonts.title 的所有属性

Scenario: 字典继承覆盖

  • WHEN 元素定义 font: {parent: "@title", size: 60}
  • THEN 系统继承 fonts.title 的所有属性,覆盖 size 为 60

Scenario: 字典独立定义

  • WHEN 元素定义 font: {family: "SimSun", size: 24}
  • THEN 系统使用定义的属性,未定义的属性继承 fonts_default

Scenario: font 字段未定义

  • WHEN 元素未定义 font 字段
  • THEN 元素使用 fonts_default 或系统默认字体

Requirement: parent 字段必须引用 fonts 中的配置

font 字典中的 parent 字段 SHALL 引用 fonts 中已定义的配置名称。

Scenario: parent 引用存在的配置

  • WHEN parent: "@title" 且 fonts.title 存在
  • THEN 系统成功继承 fonts.title 的属性

Scenario: parent 引用不存在的配置

  • WHEN parent: "@undefined" 且 fonts.undefined 不存在
  • THEN 系统抛出 ERROR提示引用的字体配置不存在

Scenario: parent 必须是引用格式

  • WHEN parent: "Arial"(直接字体名称)
  • THEN 系统抛出 ERROR提示 parent 必须是引用格式

Requirement: 系统必须检测并拒绝引用循环

系统 SHALL 在解析字体引用时检测循环引用,检测到循环时抛出 ERROR。

Scenario: 直接循环引用

  • WHEN fonts.title.parent: "@title"(引用自身)
  • THEN 系统抛出 ERROR提示检测到自引用

Scenario: 间接循环引用

  • WHEN fonts.a.parent: "@b" 且 fonts.b.parent: "@a"
  • THEN 系统抛出 ERROR显示完整的引用循环路径

Scenario: 深层循环引用

  • WHEN 引用链深度超过 10 层
  • THEN 系统抛出 ERROR提示引用深度超限

Scenario: 错误信息包含引用路径

  • WHEN 系统检测到循环引用
  • THEN 错误信息包含完整的引用路径,如 "fonts.title -> fonts.subtitle -> fonts.title"

Requirement: 系统必须支持属性继承链

字体属性解析 SHALL 按照优先级顺序继承parent → 当前定义 → fonts_default → 系统默认。

Scenario: parent 定义了基础属性

  • WHEN fonts.title 定义 size: 44元素定义 font: {parent: "@title", bold: true}
  • THEN 元素使用 size: 44继承、bold: true覆盖

Scenario: parent 未定义的属性继承 fonts_default

  • WHEN fonts_default 定义 size: 18元素定义 font: {parent: "@title"} 且 title 未定义 size
  • THEN 元素使用 size: 18从 fonts_default 继承)

Scenario: 当前定义覆盖 parent

  • WHEN parent 定义 size: 44当前定义 size: 60
  • THEN 元素使用 size: 60当前定义覆盖 parent

Requirement: 模板元素必须支持继承 fonts_default

模板中未定义 font 的元素 SHALL 继承 metadata.fonts_default 配置。

Scenario: 模板元素未定义 font

  • WHEN 模板元素未定义 font 字段
  • THEN 元素继承 metadata.fonts_default 的配置

Scenario: 模板元素定义了 font

  • WHEN 模板元素定义 font: "@title"
  • THEN 元素使用 font: "@title",不继承 fonts_default

Scenario: fonts_default 未定义时模板元素行为

  • WHEN 模板元素未定义 font 且 metadata 未定义 fonts_default
  • THEN 元素使用系统默认字体

Requirement: 表格元素必须支持 font 和 header_font 字段

表格元素 SHALL 支持 font 和 header_font 字段,分别控制数据单元格和表头的字体样式。

Scenario: 表格定义整体字体

  • WHEN 表格定义 font: {family: "Arial", size: 14}
  • THEN 数据单元格和表头都应用该字体(表头可被 header_font 覆盖)

Scenario: 表格定义表头字体

  • WHEN 表格定义 header_font: {bold: true, color: "#ffffff"}
  • THEN 表头应用该字体,数据单元格继承 font 或 fonts_default

Scenario: 表头字体继承表格字体

  • WHEN 表格定义 font: {size: 14} 且 header_font: {parent: "@font", bold: true}
  • THEN 表头继承 size: 14覆盖 bold: true

Scenario: 表格仅定义 header_font

  • WHEN 表格仅定义 header_font: {bold: true}
  • THEN 表头应用 bold: true数据单元格继承 fonts_default

Requirement: 系统必须移除旧的表格字体语法

系统 SHALL 移除 style.font_size 和 style.header_color 字段的处理逻辑。

Scenario: 旧语法字段不再生效

  • WHEN 表格定义 style: {font_size: 14, header_color: "#fff"}
  • THEN 系统忽略这些字段,使用 font 和 header_font 替代

Scenario: style 字段保留用于非字体属性

  • WHEN 表格定义 style: {header_bg: "#4a90e2"}
  • THEN 系统正常处理背景色等非字体属性