Runtime de widget XFA dinâmico interativo
TXFAWidgetRuntime oferece um modelo de interação neutro em relação ao host para formulários XFA dinâmicos, sem convertê-los em campos AcroForm nem achatar seu conteúdo
O runtime expõe limites e estado de widgets de forma determinística, para que um desktop, um serviço ou um renderer customizado forneça a própria entrada, pintura, acessibilidade e event loop dele
Criar um runtime
Crie o runtime diretamente a partir de bytes XDP ou chame THotPDF.CreateLoadedXFAWidgetRuntime depois de carregar um PDF cujo AcroForm contenha uma entrada /XFA de stream único ou array de pacotes
var
Runtime: TXFAWidgetRuntime;
State: TXFAWidgetState;
begin
Runtime := PDF.CreateLoadedXFAWidgetRuntime;
try
if (Runtime <> nil) and (Runtime.WidgetCount > 0) then
begin
State := Runtime.Widgets[0];
Runtime.FocusWidget(State.ID);
Runtime.BeginEdit(State.ID);
Runtime.ReplaceSelection(0, Length(State.Value), 'Updated value');
if not Runtime.CommitEdit then
raise Exception.Create(Runtime.LastDiagnostic);
end;
finally
Runtime.Free;
end;
end;
A factory de documento carregado é somente leitura em relação ao grafo de objetos do PDF e aos XFAFlattenWarnings existentes; salvar o documento mantém as entradas originais /XFA e /NeedsRendering
Modelo de interação
FocusWidgeteClearFocusmantêm um único widget em foco, executam scripts enter/exit e publicam callbacks ordenados depois do commitBeginEdit,ReplaceSelection,CancelEditeCommitEditpreservam texto Unicode, inclusive espaços à esquerda e à direitaHitTestmapeia coordenadas de página para o widget visível mais acima na pilhaOnWidgetInvalidated,OnLayoutChangedeOnFocusChangedpermitem que o host atualize apenas o estado afetado
Commits interativos sincronizam valores scalar nativos existentes em aliases hidden e invisible, incluindo escopos reais de dados repetidos e rollback exato em bytes
Validação e cálculo atômicos
Um commit resolve vínculos SOM explícitos e o contexto de dados atual de linhas repetidas antes de executar os scripts de validate e calculate
O valor editado, os valores calculados, os nodes de dados, o modelo de widget, o estado de foco e edição, os avisos e os contadores de passagens são publicados em conjunto somente depois que a validação e o layout se estabilizam
Scripts rejeitados, orçamentos esgotados, limites de seleção UTF-16 inválidos e exceções de layout ou de medição do host restauram o estado anterior completo e definem LastDiagnostic
Orçamentos
TXFAWidgetRuntimeOptions limita a contagem de widgets, o comprimento do valor editado, as passagens de cálculo, as passagens de reflow, as operações de layout, as operações de script, o tempo decorrido de script e outros recursos de FormCalc ou JavaScript
O teto de widgets se aplica enquanto itens de layout e fragmentos de paginação são acrescentados, enquanto a descompressão do XFA carregado e a montagem de packets param no limite de entrada do XFA DOM antes da análise
MaxLayoutOperations tem padrão 200000 e limita tanto o percurso do documento quanto o trabalho de layout; a profundidade de layout é limitada a 128, a profundidade de alvo de evento e de inicialização de instância a 64, e o despacho recursivo de eventos é rejeitado
Eventos dinâmicos literais default
DispatchEvent aceita operações literais separadas por ponto e vírgula em scripts de eventos de campo correspondentes, com content types FormCalc ou JavaScript; essas operações são analisadas diretamente e não exigem uma DLL de JavaScript
row.instanceManager.addInstance(true);
row.instanceManager.removeInstance(0);
target.presence = "hidden";
addInstance anexa uma instância e aceita true, false, 1 ou 0 como argumento de merge; um argumento omitido usa true, e a forma abreviada _row.addInstance(1) também é aceita
O modelo suportado vincula todo data group de mesmo nome existente, então uma instância nova recebe um data group novo inicializado com os defaults do template para qualquer argumento de merge; a criação de instância não clona os valores digitados da linha anterior
removeInstance usa um índice inteiro de base zero entre os data groups de mesmo nome do subform selecionado; o subform precisa ter um element occur com máximo repetível, e ambas as operações impõem o mínimo e o máximo dele, incluindo max="-1"
A mutação de instâncias exige binding implícito de dataset nomeado e nomes de dados ASCII no XML; binding explícito por referência de dados e contextos de parent ambíguos são rejeitados antes de publicar a transação
Alvos resolvem por meio de filhos nomeados do template nos escopos que envolvem o evento, incluindo paths com pontos e this.parent; um manager aninhado em um escopo repetido usa o próprio data group do evento
presence aceita visible, hidden e invisible em fields, draws, subforms e exclusion groups do template; conteúdo hidden não ocupa espaço de fluxo, enquanto conteúdo invisible retém o espaço dele e é omitido dos widgets e da saída do flatten
Com o parser literal default, mudanças de presence se aplicam ao node de template selecionado e, portanto, a todas as ocorrências repetidas dele; presence indexada por instância, inactive, expressões arbitrárias, variáveis, condicionais, loops e outras operações de script de evento exigem um event host adicional
Um lote de eventos publica mudanças de dados, cálculos, layout, foco e estado de edição juntos depois que o reflow se estabiliza; qualquer operação rejeitada ou orçamento esgotado de entrada, operações, instâncias, valores, widgets, layout ou tempo decorrido restaura o estado completo anterior do documento e da interação
Remover uma linha preserva o foco e as edições pendentes dos data groups sobreviventes mesmo quando os índices de widget deles mudam; remover ou ocultar o widget em foco limpa o foco e publica o callback de foco correspondente depois do sucesso
Execução de eventos gerais em JavaScript e FormCalc
Defina TXFAWidgetRuntimeOptions.ScriptOptions.EnableJavaScript para habilitar a ponte QuickJS limitada embarcada na execução de eventos; eventos JavaScript então suportam funções, closures, arrays, condições, loops e exceções em vez da gramática literal default
Options := TXFAWidgetRuntimeOptions.Default;
Options.ScriptOptions.EnableJavaScript := True;
Runtime := TXFAWidgetRuntime.Create(XDPBytes, 595, 842, Options);
O event host expõe this, fields e subforms nomeados envolventes, parent, rawValue gravável, presence e access, instanceManager.count/min/max, addInstance, removeInstance, insertInstance, moveInstance e setInstances, xfa.resolveNode, xfa.resolveNodes, resolução por node e xfa.layout.relayout
Listas de nodes suportam indexação numérica, length e item; valores de campos repetidos retêm os próprios alvos de dataset, e paths SOM aceitam filhos nomeados com índices numéricos ou wildcard para nodes vivos do host
const values = xfa.resolveNodes("main.row[*].amount[*]");
let total = 0;
for (const field of values) total += Number(field.rawValue);
xfa.resolveNode("main.total").rawValue = total;
if (total > 100) this.parent.warning.presence = "visible";
Cada subform repetido tem o próprio objeto vivo e os campos filhos dele; index, getters de filhos do parent e queries SOM subsequentes seguem operações de insert, move e remove imediatamente dentro do script
addInstance e insertInstance retornam uma subárvore viva inicializada com os defaults do template, de modo que o script pode escrever os valores de campos dela antes de o evento publicar; handles removidos rejeitam leituras ou escritas subsequentes
Mudanças gerais de presence e access de scripts persistem no packet form XFA padrão por ocorrência, enquanto valores de campos e operações de repetição persistem em datasets; insert, move e remove mantêm o estado de form correspondente alinhado com os data groups
Com o mesmo opt-in, scripts de eventos FormCalc compilam para a engine limitada e suportam var, if/elseif/else, for com upto ou downto, while, foreach, func com resultados implícitos, aritmética e comparações, concatenação de strings, agregação de nodes wildcard e atribuição implícita de valores de campos
A biblioteca de funções de eventos inclui Sum, Count, Avg, Min, Max, Round, funções matemáticas comuns, fatiamento de strings, conversão de caixa, trimming, substituição, HasValue, Exists, Within, Oneof e Choose; nomes built-in não diferenciam maiúsculas, At(source, search) segue a ordem de argumentos do XFA incluindo o comportamento de busca vazia, funções financeiras seguem a ordem de parâmetros do XFA, e os catálogos de datas e finanças são descritos em FormCalc Functions
Mutações de scripts são gravadas dentro da engine, validadas e reproduzidas dentro da transação do runtime; exceções, interrupção, Unicode inválido, operações de host inválidas e orçamentos esgotados não publicam mudanças parciais no documento
A execução geral de scripts permanece desligada por default, não usa browser nem processo externo e não expõe APIs de filesystem, rede ou aplicação; o chamador pode fornecer JavaScriptEvaluator em vez da ponte
Script objects persistentes
Objetos script JavaScript dentro do element variables de um subform expõem as variáveis e funções deles pelo nome do script; variáveis lexicais, estado de objetos e closures aninhadas permanecem vivos pela sessão do runtime, com shadowing lexical normal e diretivas strict preservados
<variables>
<script name="Helpers" contentType="application/x-javascript"><![CDATA[
let count = 0;
const nextPrivate = (() => { let value = 0; return () => ++value; })();
function next() { return ++count + ":" + nextPrivate(); }
]]></script>
</variables>
Código de eventos pode chamar Helpers.next(); ocorrências repetidas de subforms têm script objects independentes, e funções resolvem campos nomeados contra o contexto vivo atual do formulário
Nodes de campos e managers capturados seguem identidade estável de dados entre movimentos e a publicação de instâncias recém-criadas; acessar um node removido rejeita o evento e desfaz o estado do módulo dele
Scripts gerais de calculate e validate compartilham a sessão e os script objects; JavaScript suporta completion values implícitos e return explícito, enquanto FormCalc retorna a expressão final dele
Transações que falham restauram o estado lexical e de closures reproduzindo o journal virtual commitado, com tempo e entradas aleatórias gravados; replay e execução atual compartilham o prazo da transação, e os limites default do journal são 64 MiB de scripts/resultados e 8192 entradas
O estado de script objects vive na sessão do runtime e é inicializado de novo depois do reload do XDP; valores padrão do documento e overrides de formulário continuam persistindo por meio de SaveToBytes
Callbacks customizados de JavaScriptEvaluator retêm o envelope nativo existente de calculate/validate; a sessão persistente é fornecida pela engine embarcada
Configurar host transport explícito
Defina HostTransport e o OnHostTransactionCompleted opcional em TXFAWidgetRuntimeOptions para executar dialogs de host, impressão, navegação, submission e transferência de dados por meio de callbacks da aplicação
Explicit XFA Host Transport fornece xfa.host.messageBox, response, beep, print, gotoURL, submitForm, importData, exportData e FormCalc Get, Post e Put; a aplicação retorna resultados tipados e controla os efeitos externos
Retries e replay de sessão usam responses gravadas, de modo que callbacks executam uma vez por request despachada; a conclusão de falha permite à aplicação descartar efeitos preparados ou compensar operações reversíveis
HostTransportLimits positivos limitam a contagem de requests, a contagem de argumentos e os bytes agregados de request/response dentro da transação envolvente do runtime
Execução de locales e pictures
Eventos FormCalc gerais e scripts de calculate e validate suportam funções de locale e picture, incluindo Format, Parse, conversões localizadas de data/hora, unidades, encoding, UUIDs e palavras de números em inglês
Dynamic FormCalc Eval executa cálculos fornecidos dinamicamente com variáveis e funções isoladas, acesso relativo a campos, compilação nativa, responses gravadas e rollback transacional
Referências FormCalc explícitas suportam atribuição write-through, rebind, desanexação de null, argumentos de funções e handles estáveis retidos por script objects entre movimentos de instâncias repetidas
Live SOM paths suportam índices de ocorrência inferidos, absolutos e relativos, selectors de class e de descendentes, contêineres transparentes, predicates de candidates e atribuição indexada direta em FormCalc
O Data DOM nativo expõe datasets por meio de $data e $record, sincroniza leituras e escritas de formulários vinculados imediatamente, espelha instâncias repetidas e preserva referências de dados retidas por meio da publicação nativa de identidade
O Property DOM nativo expõe filhos declarados de value, fonte, UI e outras propriedades, sincroniza valores tipados de campos e persiste atributos por instância usados pela medição de fontes e pelo styling de flatten suportado
O node em execução herda o atributo de locale mais próximo dele; entradas de localeSet do documento sobrepõem símbolos e patterns do sistema, enquanto nomes de locale computados são resolvidos por requests internas limitadas e preservados no journal da sessão
Num2Date sem picture agora usa o pattern default de data ambiente; forneça YYYY-MM-DD explicitamente quando a saída ISO for exigida
Host model com estado
XFA Host Model fornece metadados da aplicação, contagem real de páginas, navegação de páginas, título Unicode, flags de calculation/validation, reset com escopo e foco de campo com lifecycle transacional de enter/exit
TXFAWidgetRuntimeOptions.HostModel configura o estado inicial da aplicação; TXFAWidgetRuntime.HostModel retorna o estado atual, e eventos que falham o restauram junto com os snapshots de documento e de interação
Um movimento de foco sem script enter/exit, edição pendente ou lifecycle inicializado muda o foco sem iniciar cálculo de scripts nem processamento de prazos; foco roteado por scripts e commits de edições pendentes ainda usam orçamentos transacionais, validação e recálculo
Advanced picture clauses executam pelas mesmas transações de runtime, journal de retry de locale e lifecycle de cálculo, com parsing composto limitado
Inicializar e manter o lifecycle
Chame InitializeForm depois de configurar o runtime e os callbacks para executar eventos initialize na ordem do template, depois calculate e validate, eventos form-ready e eventos layout-ready; a chamada é idempotente depois do sucesso
Instâncias novas criadas pela inicialização ou por eventos ready recebem os próprios eventos initialize antes dos handlers ready delas; a execução de layout-ready se repete apenas quando o layout muda, dentro dos orçamentos de reflow e de transação
Depois da inicialização, despacho de eventos bem-sucedido e commit de edição inicializam instâncias recém-criadas e executam calculate, validate e layout-ready; ocorrências existentes retêm o estado de inicialização delas entre movimentos e rollback de transações
Falhas de lifecycle desfazem bytes do documento, interação de widgets e bookkeeping de inicialização juntos, e os callbacks publicam apenas depois que a transação envolvente tem sucesso
Salvar o formulário atualizado
SaveToBytes retorna o XDP completo atualizado do runtime, incluindo datasets modificados e estado padrão de form por instância; mudanças de presence do parser literal continuam sendo atributos de template; use esses bytes com SetXFADocument ao gravar um PDF ou com HPDFXFAFlatten para a saída de flatten atualizada
A factory de documento carregado cria um runtime independente, então eventos do runtime não modificam automaticamente o grafo de objetos do PDF de origem
Profile opcional de instance presentation
Dynamic XFA Instance Presentation adiciona bindings repetidos explícitos, IDs estáveis por instância, presence e acesso indexados, eventos condicionais limitados, pintura em canvas do host e acessibilidade por meio de um helper independente; o runtime default e a gramática de eventos restrita dele permanecem compatíveis
UpdateDocument fornece actions de documentos transacionais; callbacks opcionais de propriedade de runtime, binding-scope, identidade, resolution-started e validação de documentos suportam o helper, enquanto defaults nil preservam os chamadores existentes
APIs de eventos e de formulário de nível mais baixo
HPDFXFACompileFormCalcEvent compila sintaxe de eventos; HPDFXFAExecuteJavaScriptEvent executa o contexto virtual descrito por TXFAEventBinding e TXFAEventBindings
TXFAJavaScriptSession fornece execução persistente e checkpoints limitados para chamadores de nível mais baixo
Valores TXFAEventAction retornados usam TXFAEventActionKind; o replay transacional é fornecido pelo runtime
HPDFXFAResolveFormInstanceNode e HPDFXFAResolveFormInstanceProperty fornecem lookup limitado de form packets padrão
Fronteiras atuais
O runtime é um objeto de host single-thread; GUI e pintura continuam sendo responsabilidade do host ou do helper de presentation opcional
O host state suportado, o form DOM vivo e o lifecycle ainda não cobrem toda propriedade de host do Acrobat, pictures de dígitos de eras alternativas e localizadas, queries síncronas de reflow dinâmico nem todo operador SOM
Veja Bounded XFA FormCalc and JavaScript, XFA Packet DOM e Interactive Document Processing