動態 XFA 實例呈現
Unit: HPDFXFAPresentation
TXFAInstancePresentation 持有獨立的 TXFAWidgetRuntime,為含單一 datasets 記錄的 XDP packet 文件加入有界的實例呈現設定檔
用 SetPresence('row[1]', 'hidden') 把某個出現位置從流中移除,invisible 保留空間但隱藏其 widget,visible 則還原;索引是資料出現位置中以零起算的序號,包括被隱藏的出現
版面解析器分別量測每個出現位置,壓實存留的垂直偏移,並在放置後續內容前保留完整的重複範圍;固定高度、內容推導高度與表格列都參與重排
穩定識別與持久化
Widget ID 結合不透明的 template 與 datasets 識別,在前面的列被隱藏或移除、儲存後重新載入,以及存留欄位保持焦點或待定編輯時都維持穩定
輔助器把帶命名空間限定的識別屬性與實例覆寫存進 form packet 內的外部命名空間擴充,使用 urn:hotpdf:xfa:instance-presentation:1;新增的列取得新識別與 template 預設值,被移除的列無法把待定編輯轉移給替補的列
SaveToBytes 回傳完整 XDP,包括更新後的 datasets、識別與呈現狀態;用 THotPDF.SetXFADocument 把它持久化進 PDF,寫動態表單時設定 XFANeedsRendering := True
PDF 重新載入後,先用 THotPDF.CreateLoadedXFAWidgetRuntime.SaveToBytes 取得完整 XDP,再從那些 bytes 建構 TXFAInstancePresentation 來還原此設定檔
此命名空間擴充由本輔助器解讀;原生 HPDFXFAFlatten、預設的已載入 runtime 工廠與外部 XFA 檢視器不會自動套用其逐實例覆寫,因此持久儲存設定檔並不保證其他閱讀器有一致的呈現
明確綁定與實例操作
重複 subform 可用 <bind match="dataRef" ref="$record.lines.entry[*]"/> 綁定到不同名稱的 dataset 群組;絕對 $record 與 $data 根和相對路徑支援未帶索引的父群組,以及位於最後的重複群組
每個出現位置內的欄位使用原生綁定值解析器,包括 ref="label" 這類明確的相對欄位綁定
AddInstance 與 RemoveInstance 更新選取的資料群組、強制 occur 最小與最大值、套用建立上限,並在發布前重排;新列的欄位值來自 template,而不是複製上一列輸入的值
選擇器使用唯一的 template 名稱加選填的出現索引,例如 row[1];重複的 template 名稱、缺少的群組、無效索引,以及在模糊重複父層之下的變更都會拒絕交易
SetAccess 支援 open、readOnly、protected 與 nonInteractive;實例限制會被後代繼承,並阻止透過自有 runtime 編輯
條件事件
DispatchConditionalEvent 找出符合、內容類型為 JavaScript 的欄位事件,並直接解析有界設定檔;Execute 對既有 widget ID 執行明確 script
if(this.rawValue=="hide"){
row[1].presence="hidden";
}else{
row[1].presence="visible";
}
row.instanceManager.addInstance();
row.instanceManager.removeInstance(0);
條件接受 this.rawValue 與未跳脫帶引號常值之間的相等或不相等比較;巢狀大括號 if 與選填 else 區塊受 MaxDepth 約束
指派支援 presence 與 access;所有分支都做語法檢查,包括未執行的分支,不支援的操作會拒絕整個批次
this.rawValue 讀取已提交的 widget 值;在分派應該觀察到待定編輯的事件之前,先透過 Runtime.CommitEdit 提交
原始 Runtime.DispatchEvent 保留其受限的常值操作行為,拒絕條件與帶索引實例語法;本輔助器不提供一般 JavaScript 或 FormCalc 直譯器、瀏覽器 API、網路存取或自動 XFA 生命週期分派
交易與預算
變更透過 TXFAWidgetRuntime.UpdateDocument 執行,連同原生計算與有界穩定重排;失敗會還原序列化 XDP、焦點、待定編輯、驗證狀態、計算與重排計數器,以及警告計數
焦點、版面與 widget 失效回呼只在成功後發布;回溯解析會抑制耗盡的輔助工作與取消檢查,同時保留原生版面與 widget 邊界,讓取消無法阻止還原
以 Default 初始化 TXFAPresentationOptions;預設值為 200,000 個操作、4,096 個呈現狀態、每群組 10,000 個建立實例、32 MiB 輸入與文件信封、65,536 script bytes、32 層條件巢狀與 5,000 毫秒
MaxInputBytes 也會在每次版面與發布過程前約束保守的跳脫 XML 信封,包括識別屬性、命名空間宣告、文字與 datasets 變更;合法 XML 可能在其序列化 byte 數達到相同值之前就先到達這個保守上限
Cancelled 是選填的物件方法回呼,於有界工作期間檢查;內嵌 Runtime 選項繼續約束 widget、值、計算、版面、重排與原生 script 工作
Host 繪製與無障礙
Accessibility 回傳可見 widget 記錄,含穩定 ID、role、標題或欄位名稱、提示描述、已提交值、頁面與邊界、焦點、有效性、唯讀與必填狀態,以及選項標籤;密碼值會省略
PaintPage 把可見 widget 快照與對應的無障礙記錄交付給 TXFAHostWidgetPainter;自訂 host 可實作自己的控制項或繪製表面
TXFACanvasWidgetPainter 為 widget 邊框、文字、密碼遮罩、核取方塊與選鈕記號、選項指示器、按鈕與焦點提供實際的 VCL 與 LCL canvas 繪製,支援正縮放與選填偏移;它會裁剪每個 widget 並還原 canvas 樣式
canvas 配接器只繪製 widget,不繪製完整的靜態 XFA 圖形樹;host 自行提供頁面背景、靜態圖形、事件路由、選取呈現,以及通往其平台的無障礙橋接
runtime 與輔助器是單執行緒物件;回呼必須遵守 host 的執行緒所有權,並避免在活動交易期間遞迴變更
C++Builder 呼叫端必須提供所有 canvas painter 建構子參數,例如 new TXFACanvasWidgetPainter(canvas, 1, 0, 0);產生的標頭不保留這些浮點預設參數
驗證
驗收涵蓋每種架構 106 個 Delphi 案例、兩種 Windows 架構的全新 FPC 編譯、Win32 與 Win64x 的 C++Builder 公開標頭編譯,以及實際 PDF/XDP 輸出的獨立驗證
Tests/Fixtures/XFAInstancePresentation/explicit-invoice.xdp 包含獨立的資料名稱、三行重複發票列、一個條件事件、無障礙中繼資料與後續頁尾
Run-XFAInstancePresentationTests.ps1 執行輔助器檢查與既有的 XFA 事件、runtime、scripting、SOM、DOM 與解析迴歸 fixtures,不使用 GUI 或外部 PDF 閱讀器
獨立的 verify_saved_invoice.py 用 pypdf 讀取產生的 PDF,檢查真實 XDP 資料列、唯一持久識別、隱藏出現狀態、初始化預設值與重新載入識別
powershell -File Tests/Delphi/Run-XFAInstancePresentationTests.ps1 -Platform Win32 -CheckCppHeaders
powershell -File Tests/Delphi/Run-XFAInstancePresentationTests.ps1 -Platform Win64 -CheckCppHeaders
python Tests/Fixtures/XFAInstancePresentation/verify_saved_invoice.py
相容的基礎 runtime 與原生編輯合約見 Interactive XFA Widget Runtime