HTML5 Paged-Media Import

THPDFHTMLImporter.RenderHTML5 converts tolerant HTML5 markup and print CSS into paginated PDF content whilst preserving the compact legacy RenderHTML path

CSS lengths and the importer's Margin, BaseFontSize, ListIndent and BlockSpacing are in points, so both renderers produce the same page whatever THotPDF.Resolution is set to; your own drawing before and after the import keeps using 1/Resolution inch

Declaration

function RenderHTML5(
  const HTML: WideString;
  const AuthorStyleSheet: WideString = ''
): Boolean;

function HPDFRenderHTML5Document(
  Doc: THotPDF;
  const HTML: WideString;
  const AuthorStyleSheet: WideString = '';
  MarginPt: Single = 72;
  const FontName: AnsiString = 'Arial';
  FontSize: Single = 12
): Boolean;

Profile contract

HTML5ProfileVersion returns 1 and HTML5ProfileMilestones reports parser and cascade, paged layout, tables and forms, and bounded resources

Measured paragraphs and direction

Paragraphs wrap using the current font's measured advances, including font changes, bold and italic runs, letter spacing, word spacing, explicit line breaks, and East Asian character boundaries; alignment and decoration apply separately to each resulting line

direction: ltr, direction: rtl, and the HTML dir attribute select paragraph direction; dir="auto" uses the first strong character's Unicode direction

On Windows, bidirectional script runs are resolved with Uniscribe and reordered across style boundaries, whilst the existing PDF text engine handles glyph shaping within each run; the document's direction, viewer preferences, and saved page text state are restored after the line

Inline direction overrides, bdi, and bdo currently use paragraph ordering and produce an hdkLayoutFallback diagnostic; unicode-bidi is outside this profile, and script shaping still follows the document's shaping configuration

Paragraph fragmentation

widows and orphans are inherited positive integers, both defaulting to 2; pagination uses the measured line boxes rather than an estimated number of characters

The importer moves a paragraph or adjusts its split to leave the requested minimum number of lines before and after a page break; break-inside: avoid keeps a paragraph together when it fits on a fresh page

When a page cannot hold the requested constraint, rendering makes progress by relaxing the constraint and recording hdkPaginationConstraint; each page fragment receives its own background and border

Optional hyphenation

hyphens: none suppresses discretionary breaks, and the default hyphens: manual uses U+00AD or ­; a visible hyphen is emitted only when the selected break is used

hyphens: auto additionally calls OnHyphenate with the word and inherited HTML lang value; without a callback it retains manual breaks and reports a layout fallback, because no language dictionary is bundled

Break positions count UTF-16 code units from the start of the word; invalid, out-of-range, surrogate-splitting, and basic combining-mark-splitting positions are ignored

THPDFHTMLHyphenationEvent = procedure(
  Sender: TObject;
  const WordText, Language: WideString;
  var BreakPositions: TArray<Integer>
) of object;

Bounded flex and grid boxes

display: flex supports row, row-reverse, column, and column-reverse; row children use explicit widths or share the remaining width, and positive flex-grow values weight additional space

Rows support justify-content start, end, centre, space-between, space-around, and space-evenly, plus start, end, centre, and stretch cross-axis alignment; column flow supports natural vertical layout and emits a diagnostic for unsupported fixed-height distribution or cross-axis alignment

display: grid supports positive fixed-length and fr column tracks, including bounded repeat(n, tracks) with up to 64 columns; cells are placed in source order, filling one row at a time

grid-column: span N and grid-column-end: span N allow a child to occupy consecutive tracks and their intervening gaps; an item that does not fit the current row moves to the next row, and spans larger than the track count produce a layout fallback

flex-wrap: wrap starts another line when the next item's explicit width and gap do not fit; each line independently applies flex-grow and justify-content, whilst row-reverse and RTL reverse positions within each line without moving items between lines

gap accepts one or two lengths, with independent row-gap and column-gap overrides; parallel rows stay on one page and are checked before painting

Parallel children support text blocks with inline styling, recursively nested ordinary block containers with padding, borders and backgrounds, nested flex and grid containers, images, and static or native form controls

Images use callback-supplied or data URI bytes, retain their intrinsic aspect ratio when no height is specified, and are decoded once per DOM node; preflight and fallback reuse the same cached image without consuming another resource request

All child boxes are measured before any parallel row is painted, so unsupported or oversized content falls back to vertical page flow without repeating previously painted rows; nested planning is bounded to 64 levels and consumes the existing layout-operation budget

Wrapping children without an explicit width occupy one complete line; tables and lists inside parallel children, flex basis and shrink, wrap-reverse, intrinsic track sizing, grid row tracks and row spans, and explicit grid placement remain outside this profile and produce observable diagnostics

Unsupported CSS diagnostics

Diagnostics exposes records containing Kind, Subject, Value, and MessageText; OnDiagnostic receives the same information during rendering

Unknown properties, unsupported values, unsupported selectors, and unsupported at-rules are ignored with a diagnostic, including declarations in otherwise unused stylesheet rules; pseudo selectors are skipped rather than treated as ordinary type selectors

StrictCSS, disabled by default, raises EHPDFHTMLUnsupportedCSS on a diagnostic; prior content may already have been emitted, so callers requiring all-or-nothing import should use a separate document

MaxDiagnostics defaults to 256 and bounds retained records; DiagnosticCount and callback delivery remain observable after the storage limit is reached, and a non-positive limit disables record storage

Bounded resources

External stylesheets, images, and @font-face fonts are disabled unless OnResource supplies their bytes, so HTML import never opens a file or network connection implicitly

@font-face supports one url(...) source, optional format('truetype') or format('opentype'), a family alias, normal or italic style, and normal, bold, 400, or 700 weight; font-display accepts the standard policies because offline import loads resources synchronously

Fonts must be embeddable TrueType or OpenType sfnt resources with an ASCII Windows family name of at most 31 characters; WOFF, font collections, local(...), variable descriptors, and source lists produce diagnostics

Accepted fonts are registered privately in process memory on Windows and remain owned by the document until it is destroyed, so freeing the importer before EndDoc does not invalidate deferred font embedding

data: resources and callback results share MaxResources, MaxResourceBytes, and MaxTotalResourceBytes limits

MaxDecodedImageBytes defaults to 128 MiB and independently bounds the decoded image cache at four bytes per pixel; BMP and PNG dimensions are checked before decoding, and every accepted picture is checked before it is retained

MaxDOMNodes, MaxCSSRules, and MaxLayoutOperations independently bound parsing, cascade construction, and layout work

THPDFHTMLResourceEvent = procedure(
  Sender: TObject;
  const URI: WideString;
  ResourceKind: THPDFHTMLResourceKind;
  var Data: TBytes;
  var ContentType: string;
  var Handled: Boolean
) of object;

Statistics

THPDFHTMLImportStatistics reports the profile version, parsed nodes, CSS rules, layout operations, page breaks, tables, form controls, resource requests, accepted and rejected loads, accepted resource bytes, measured text lines, hyphenated lines, diagnostics, flex containers, and grid containers

OnLineLayout receives the line's zero-based page and paragraph line indices, origin, measured width and height, logical text, direction, and hyphenation flag after the actual PDF text has been emitted

Every RenderHTML5 call resets the statistics record, and budget violations raise EHPDFHTMLImportBudget

Example

Importer := THPDFHTMLImporter.Create(Doc);
try
  Importer.CreateAcroForms := True;
  Importer.MaxResources := 16;
  Importer.RenderHTML5(
    '<style>@page { margin: 36pt } ' +
    'table { width: 100% }</style>' +
    '<h1>Invoice</h1>' +
    '<table><tr><td>Total</td><td>42</td></tr></table>' +
    '<input name="approved" type="checkbox">'
  );
finally
  Importer.Free;
end;

See also: THPDFPage.TextOutHTML, Declarative Layout DOM, AcroForm Support