原生富文本外部样式表

原生 XHTML 解码器把 XHTML link 元素和 CSS @import 规则引用的调用方 CSS 资源,应用到真实的富文本 run、保存的富值和字段外观

Options := THPDFHeadlessRichTextDecodeOptions.Default;
Options.DocumentURI := 'https://example.test/forms/order.xhtml';
SetLength(Options.StyleSheets, 2);
Options.StyleSheets[0].URI := 'css/main.css';
Options.StyleSheets[0].CSS := '@import "colors.css"; span.total { font-weight: bold }';
Options.StyleSheets[0].ContentType := 'text/css';
Options.StyleSheets[1].URI := 'css/colors.css';
Options.StyleSheets[1].CSS := 'span.total { color: #a02030 }';
Runs := HPDFDecodeHeadlessRichText(XHTML, Options);
<body xmlns="http://www.w3.org/1999/xhtml">
  <link rel="stylesheet" href="css/main.css" />
  <span class="total">Total</span>
</body>

资源身份与级联

相对引用使用 RFC 3986 路径合并和点段移除;query string 属于资源身份而 fragment 不属于,scheme 与 host 字母做大小写规范化而 userinfo 保留原大小写,百分号转义的十六进制字母比较时不区分大小写

每张导入的样式表针对自身 URI 解析进一步的 import,并拥有独立的 CSS 命名空间环境;导入一张样式表不会把它的 @namespace 声明泄漏给父级

import 接受带引号字符串和 url token(含 CSS 转义),位置在普通规则或命名空间声明之前;既有的 print/screen media query 求值器控制 link media 与 import 条件

导入的声明按真实源位置进入级联,importance 与 specificity 照常;循环引用仅在该资源处于活动状态时被跳过,因此稍后重复引用可以再次生效

缺失资源、非法编写引用和非 CSS 内容类型不贡献声明;调用方提供的非法资源集合抛出 EHPDFHeadlessRichTextCodecError

XHTML 引用与选中集合

stylesheet 关系 token 比较不区分 ASCII 大小写;被禁用的 link 被忽略,media 和 type 属性决定被引用样式表是否参与

内联 style 元素和链接样式表共享同样的区分大小写的 title 集合;无标题的持久样式表保持启用

没有显式 StyleSheetTitle 时,第一个符合条件的带标题内联 style 或非 alternate link 选出 preferred 集合;解码器在收集声明之前确定该标题,因此带选中标题的较早 alternate 会在其原始级联位置参与

显式 StyleSheetTitle 选中匹配标题的内联与链接样式表,alternate 也包括;没有匹配样式表的标题只保留持久样式表启用

preferred 标题扫描接受空 type 或 text/css,跳过禁用或 alternate 的 link;资源可用性与 media 条件不改变选中的标题,声明仍服从各自的 media、type 与资源检查

HTML 与 XML base 解析

XHTML head 内第一个带 href 的 XHTML base 元素,把 href 对照 DocumentURI 解析后作为文档基准;base 元素或其祖先上的 xml:base 不影响这次查找

解码器随后从该文档基准出发,逐层应用每个祖先的 xml:base 来解析 link 引用和内联 import;链接或导入的样式表针对自己的资源 URI 解析自身的 import

例如 DocumentURI=https://example.test/docs/form.xhtml、根 xml:base="a/"、head base href="b/"、link href="main.css",解析为 https://example.test/docs/b/a/main.css

第一个 base href 为空时使用回退文档 URI;第一个 base href 非法时同样保留回退并消耗第一 base 的位置,后续 base 元素无法替换

这个次序定义了原生解码器的 HTML/XML 组合 profile;XML Base 本身并未定义该如何与独立的 HTML base 机制结合

Form 数据与 JSON 操作

通过原生文档方法导入 FDF RV 或 XFDF value-richtext 时,在 THPDFHeadlessFormDataOptions 上设置 RichTextDocumentURI、RichTextStyleSheetTitle 和 RichTextStyleSheets

Windows 文件作业、Windows execute-json-v1 和版本化原生 Linux C ABI 都在 forms.import 上接受同样的可选 richTextResources 对象

{
  "schemaVersion": 1,
  "type": "forms.import",
  "format": "xfdf",
  "richTextResources": {
    "documentURI": "https://example.test/forms/order.xhtml",
    "styleSheetTitle": "Print",
    "styleSheets": [
      {"uri": "css/main.css", "css": "span.total { color: red }", "contentType": "text/css"}
    ]
  }
}

每个 JSON 资源的 URI 必填且非空;css 和 contentType 是可选字符串,documentURI 和 styleSheetTitle 同样可选;提供的字符串不得包含 NUL

资源是宿主提供的 Unicode CSS 文本;URI 标识符不请求文件系统访问、网络访问,也不改动回调记录布局

外围导入事务在资源畸形、取消、预算失败或发布失败时保留先前文档;语义等价的重复导入保留既有的字节一致 no-op 行为

可复用的非 GUI 验收

Tests/Linux/ExternalStyleSheets/Run.py 检查真实解码 run、设界失败行为、保存外观以及独立的 PDF 几何与像素;其 Callbacks 目录演练真实的 FDF/XFDF 导入、no-op 字节和发布失败事务

Tests/Linux/ExternalStyleSheets/Supplement/Run.py 检查共享的内联/链接 title 集合、组合 HTML/XML base 解析、每个实测自动标题取消边界,以及深度失败后成功重试

supplement 接受显式源目录和编译器配置,记录真实源与依赖身份,并要求每次执行使用新的输出目录

边界与剩余工作

资源数至多 256,每个解析后 URI 至多 4096 个 UTF-16 code unit,每个标题或内容类型至多 256;样式表文本同样服从 MaxCodeUnits,聚合扫描与匹配计入既有的节点、总 code unit、深度和取消限制

Form 数据绑定使用 MaxValueCodeUnits、MaxTotalCodeUnits、MaxObjects、MaxDepth 和操作的 cancellation token 作为对应解码器限制

导入层、更多 CSS 布局、表格、图像和更广的 HTML 资源加载仍是独立工作

选择器与内部样式表 · media profile · Form 数据选项

原生 supports 查询用受支持的声明与选择器 profile 接纳 @supports 组和 supports() 导入,共享边界并支持取消后恢复