AcroForm relationship cache
HotPDF maintains a document-local bidirectional index across terminal AcroForm fields, qualified field names, widget annotations, widget ordinals, and page positions
Lookup behavior
Field index and qualified-name lookup use direct arrays and a case-insensitive open-addressed name map after the first build
A parent field may provide inherited /FT, /Ff, and /Opt entries without being a terminal field; named children such as group.a and group.b remain separate indexed fields
Named child fields are distinguished from unnamed widget children whether the field and widget share one dictionary or use separate dictionaries
GetLoadedFormFieldWidgetPageIndex resolves one widget ordinal to its page, while GetLoadedFormFieldIndexForAnnotation maps a page annotation back to its field and widget ordinal
Annotation-array membership takes precedence over a widget /P entry, and the first matching page in document order wins for malformed duplicate membership
Widgets omitted from /AcroForm /Fields are indexed as orphans for diagnostics but are not exposed as synthetic form fields
Construction and mutation
The cache is built lazily in one field-tree traversal plus one page-annotation traversal
Loaded field creation extends a valid cache incrementally, while field removal, renaming, widget movement, annotation removal, merge registration, XFA field merging, and page-table mutation invalidate it before the graph changes
The next relationship query rebuilds from the current object graph, including widgets whose /P entry is absent
Removing one terminal child removes its own widgets and field-tree entry while retaining its siblings and their inherited settings
Call InvalidateLoadedFormRelationshipCache after changing AcroForm, field, widget, page /Annots, /Parent, /Kids, or /P dictionaries through raw object APIs
Performance and ownership
The name and object maps keep their load factor below one half and provide expected constant-time warm lookup
A regression gate builds 10,000 loaded fields, proves linear traversal telemetry, and requires repeated name lookup to be at least 100 times faster than a cold build plus lookup on Win32 and Win64
The cache stores non-owning object pointers and loaded-document graph access remains caller-serialized
See also: GetLoadedFormFieldWidgetPageIndex, GetLoadedFormFieldIndexForAnnotation, InvalidateLoadedFormRelationshipCache, GetLoadedFormRelationshipCacheStatistics