Bounded XFA FormCalc and JavaScript
HotPDF evaluates XFA calculate scripts while flattening a form, with an always-available bounded FormCalc path and a broader QuickJS path that remains disabled until the application explicitly enables it
Extended FormCalc
FormCalc expressions support arithmetic, strings, booleans, comparison operators, short-circuit And, Or, and Not, plus the lazy If(condition, whenTrue, whenFalse) branch
Sum, Avg, Min, Max, and Count accept mixed scalar and SOM node-set arguments using rooted, direct, indexed, wildcard, or descendant paths such as $record.rows[*].amount; only the selected branch of If is evaluated, so an unused invalid branch does not reject the calculation
Nested calls can combine numeric, string, and node-set results, with deterministic support for At, Choose, Concat, LTrim, RTrim, Str, Stuff, Null, Sign, Exp, Log, Sin, Cos, Tan, Deg2Rad, Rad2Deg, Within, and Oneof
User-defined functions, loops, assignment, locale picture clauses, and network functions remain outside the native subset and fail closed
InstanceAdd(name, count) and InstanceRemove(name, index) dispatch through OnXFAInstanceAction only after argument and operation-budget validation
Optional JavaScript
Set THotPDF.XFAJavaScriptEnabled to True before ApplyXFAAsAcroForm or FlattenLoadedXFA to run scripts whose contentType selects JavaScript
The runtime supports normal JavaScript control flow and native typed arrays such as Float64Array, but receives no file, process, network, browser, or application object; fetch, XMLHttpRequest, WebSocket, require, process, and Deno are unavailable
var
Budgets: THPDFXFAFormScriptBudgets;
begin
Budgets := THPDFXFAFormScriptBudgets.Default;
Budgets.MaxElapsedMilliseconds := 100;
Budgets.JavaScriptMemoryBytes := 8 * 1024 * 1024;
PDF.XFAFormScriptBudgets := Budgets;
PDF.XFAJavaScriptEnabled := True;
PDF.OnXFAInstanceAction := HandleXFAInstanceAction;
PDF.ApplyXFAAsAcroForm(XDPBytes, False);
end;
Script context
JavaScript receives a mutable this.rawValue, an event.value, and a frozen xfa facade
xfa.get(name, index)reads one collected data valuexfa.values(name)returns a frozen copy of every repeated valuexfa.resolveNode(name)andxfa.resolveNodes(name)expose read-only raw-value viewsxfa.addInstance(name, count)andxfa.removeInstance(name, index)queue validated host callbacks
Budgets and telemetry
THPDFXFAFormScriptBudgets bounds script bytes, FormCalc operations, elapsed time, expression depth, repeated-array items, value bytes, instance operations, JavaScript memory, JavaScript stack use, and interrupt checks
The stack budget provides the recursion boundary, while the time and interrupt budgets stop non-terminating loops; scripts that cross any boundary fail closed and append a diagnostic to XFAFlattenWarnings
XFAFlattenScriptsEvaluated, XFAFlattenScriptsRejected, and XFAFlattenInstanceOperations report the latest flattening pass
Direct runtime integration
The extended HPDFXFAFlatten overload accepts TXFAFormScriptOptions and TXFAFormInstanceAction directly; assign TXFAFormScriptOptions.JavaScriptEvaluator to adapt the static QuickJS binding or another application-owned evaluator while retaining the same wrapper and budgets
See TXFAFormScriptOptions, TXFAFormScriptLimits, THPDFXFAFormScriptBudgets, and THPDFXFAInstanceAction