Native rich-text external style sheets

The native XHTML decoder applies caller-supplied CSS resources referenced by XHTML link elements and CSS @import rules to actual rich-text runs, saved rich values and field appearances

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>

Resource identity and cascade

Relative references use RFC 3986 path merging and dot-segment removal; query strings remain part of resource identity, fragments do not, scheme and host letters are normalised whilst user information retains its case, and percent-escape hex letters compare without case

Each imported sheet resolves further imports against its own URI and has an independent CSS namespace environment; importing a sheet does not leak that sheet's @namespace declarations into its parent

Imports accept quoted strings and url tokens, including CSS escapes, before ordinary rules or namespace declarations; the existing print/screen media query evaluator controls link media and import conditions

Imported declarations enter the cascade at their actual source position with normal importance and specificity; a cyclic reference is skipped only whilst that resource is active, so later repeated references can contribute again

Missing resources, invalid authored references and non-CSS content types contribute no declarations; invalid caller-supplied resource collections raise EHPDFHeadlessRichTextCodecError

XHTML references and selected sets

Stylesheet relation tokens compare without ASCII case; disabled links are ignored, and media and type attributes control whether a referenced stylesheet participates

Inline style elements and linked sheets share the same case-sensitive title sets; untitled persistent sheets remain enabled

Without an explicit StyleSheetTitle, the first eligible titled inline style or non-alternate link selects the preferred set; the decoder determines that title before collecting declarations, so an earlier alternate with the selected title participates at its original cascade position

An explicit StyleSheetTitle selects matching titled inline and linked sheets, including alternates; a title that has no matching sheet leaves only persistent sheets enabled

The preferred-title scan accepts an empty type or text/css and skips disabled or alternate links; resource availability and media conditions do not change the chosen title, and declarations still obey their own media, type and resource checks

HTML and XML base resolution

The first XHTML base element with href inside an XHTML head supplies the document base by resolving its href against DocumentURI; xml:base on the base element or its ancestors does not alter that lookup

The decoder then applies each ancestor xml:base once, starting from that document base, to resolve link references and inline imports; a linked or imported sheet resolves its own imports against its resource URI

For example, DocumentURI=https://example.test/docs/form.xhtml, root xml:base="a/", head base href="b/" and link href="main.css" resolve to https://example.test/docs/b/a/main.css

An empty first base href uses the fallback document URI; an invalid first base href also retains that fallback and consumes the first-base position, so later base elements do not replace it

This ordering defines the native decoder's combined HTML/XML profile; XML Base does not itself define how a separate HTML base mechanism should be combined with it

Form data and JSON operations

Set RichTextDocumentURI, RichTextStyleSheetTitle and RichTextStyleSheets on THPDFHeadlessFormDataOptions when importing FDF RV or XFDF value-richtext through native document methods

Windows file jobs, Windows execute-json-v1 and the versioned native Linux C ABI accept the same optional richTextResources object on forms.import

{
  "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"}
    ]
  }
}

URI is required and nonempty for each JSON resource; css and contentType are optional strings, as are documentURI and styleSheetTitle; supplied strings must not contain NUL

Resources are Unicode CSS text supplied by the host; URI identifiers do not request filesystem access, network access or changes to callback record layouts

The surrounding import transaction preserves its prior document on malformed resources, cancellation, budget failure or publication failure; exact equivalent imports keep the existing byte-identical no-op behaviour

Reusable non-GUI acceptance

Tests/Linux/ExternalStyleSheets/Run.py checks actual decoded runs, bounded failure behaviour, saved appearances and independent PDF geometry and pixels; its Callbacks directory exercises actual FDF/XFDF imports, no-op bytes and failed-publication transactions

Tests/Linux/ExternalStyleSheets/Supplement/Run.py checks shared inline/link title sets, combined HTML/XML base resolution, every measured automatic-title cancellation boundary and depth failure followed by successful retry

The supplement accepts an explicit source directory and compiler configuration, records the actual source and dependency identities, and requires a new output directory for each execution

Bounds and remaining work

The resource count is at most 256, each resolved URI at most 4096 UTF-16 code units, and each title or content type at most 256; stylesheet text also obeys MaxCodeUnits, with aggregate scans and matching charged to the existing node, total-code-unit, depth and cancellation limits

Form-data bindings use MaxValueCodeUnits, MaxTotalCodeUnits, MaxObjects, MaxDepth and the operation's cancellation token for the corresponding decoder limits

Import layers, additional CSS layout, tables, images and broader HTML resource loading remain separate work

Selectors and internal style sheets · Media profiles · Form-data options

Native support queries admit @supports groups and supports() imports using the supported declaration and selector profile, with shared bounds and cancellation recovery