Embedpdf/feature/forms - #31

Merged
bobsingor merged 13 commits into
embedpdf/feature/read-purityfrom
embedpdf/feature/forms
Jul 20, 2026
Merged

Embedpdf/feature/forms#31
bobsingor merged 13 commits into
embedpdf/feature/read-purityfrom
embedpdf/feature/forms

Conversation

@bobsingor

Copy link
Copy Markdown
Contributor

No description provided.

Introduce runtime-registered font support and per-annotation font subsetting for FreeText appearance generation. Adds CPDF_AnnotFontMap and CPDF_AnnotFontSubset to route fallback lookups to CFX_FontRegistry, create marker font entries in the AcroForm DR, and produce subsetted Type0/CIDFont dictionaries (using HarfBuzz) that embed only glyphs used by an annotation/layer. Update CPDF_Font::FallbackFontFromCharcode to prefer registered fonts and create runtime fallbacks, and switch FreeText AP generation to use CPDF_AnnotFontMap so resources include any registered fallback/subset fonts actually used. Expose UpdateDefaultAppearanceRegisteredFont to set a DA referencing a registered runtime font. Update BUILD.gn to include the new files and third_party/harfbuzz-ng, and add supporting CFX_FontRegistry and public/epdf_font glue.
Persist registered-font identity in marker font dictionaries and make font registry behavior robust.
- Store registered font id in marker font dict (key "EmbedPDFRegisteredFontId") and add CPDF_AnnotFontSubset::GetRegisteredFontIdFromMarkerFontDict to read it. CPDF_AnnotFontMap now checks the marker dict for identity instead of inferring from BaseFont/resource alias.
- Create marker font dicts with the new id field; make subset base-name comment deterministic.
- Prevent CFX_FontRegistry::ClearRegisteredFonts from resetting next_font_id to avoid reusing ids that may still be referenced by existing document markers.
- Update CPVT_FontMap unicode/charcode logic to use CharCodeFromUnicode checks and safe numeric conversions; preserve upstream appearance font selection behavior.
- Add/adjust tests and helpers in fpdfsdk to validate stable appearance streams, alias-suffix survival, fallback rendering, checksums, and related utilities.
- Update public API docs for font registration to clarify thread/ownership rules and ClearRegisteredFonts semantics.
Also includes small cleanup/refactors and added includes needed by new code and tests.
Prefer registered-font mapping when generating appearance streams for persistent form widgets: if the target is persistent and there are registered fallback fonts or the font dict indicates a registered subset, create a CPDF_AnnotFontMap with registered fallbacks and embed the corresponding Font resources. Refactor duplicated AP generation into a lambda to reduce code duplication and preserve the previous CPVT_FontMap path for non-registered cases. Add CFX_FontRegistry::HasFallbackFonts() and its declaration. Add tests and a DroidSansFallbackFull.ttf test font, plus helpers to register and assert registered fallback behaviour for FreeText, TextField, ComboBox, and ListBox Korean glyphs. Also include small test fixes (initializer_list include, wchar_t usage).
Introduce a session-free EPDF form snapshot API and related utilities to support EmbedPDF use-cases. Adds a large new implementation (fpdfsdk/epdf_form.cpp) and public/epdf_form.h plus embedder tests and test PDF resources. Extend CPDF_InteractiveForm with ResolveCurrentDict and ReconcileWidget to rebind dictionaries to a document's current view and recover widgets reachable from page /Annots but missing from /AcroForm /Fields. Make ExportToFDF honor a skip_empty_required flag to preserve historic omit-empty-required behavior. Add whitespace-exact XML serialization APIs (CFX_XMLNode::SaveCompact and CFX_XMLElement::SaveCompact) to avoid corrupting xml:space="preserve" payloads, and unconditionally include CFX_MemoryStream in the build. Numerous helper routines implement form snapshotting, write transactions (toggles, text, choice), FDF/XFDF import/export, and layer-correctness rules. Update BUILD.gn files to expose new sources and tests. Tests/resources for recovered/orphan widgets and toggle fields are added.
Introduce EmbedPDF PieceInfo support: add public header and full implementation for namespace-scoped document/page PieceInfo metadata (typed values, last-modified timestamps, arrays, clear operations, and page/document variants). Add embedder tests covering save/reload and layer/delta flows. Update BUILD.gn and fpdfsdk/BUILD.gn to expose the new header and include the new sources, and switch component("pdfium") to shared_library("pdfium") while adding resources.rc to its sources.
Introduce EmbedPDF APIs and implementations: adds detached, read-only action model (epdf_action.* + helpers + public/epdf_action.h) with embedder tests; implements layer-safe selective annotation/page flattening (epdf_flatten.cpp) and test resources. Plumbing and API changes: expose CPDF_AnnotContext::GetAnnotIndex(), add CPDF_GenerateAP::GenerateFormAPWithValueOverride and thread value_override through AP generation to allow regenerating widget appearances without changing /V, and adjust CPDF_GenerateAP::GenerateFormAP calls. Fix CPDF_InteractiveForm export logic for skip_empty_required to correctly treat missing/null/array values. Update BUILD.gn entries and public headers to export new APIs and add fpdfsdk build sources and tests. Adds test PDFs/resources for flattening.
Compute the true painted bounds of /InkList by accumulating all ink points into an ink_bounds rectangle and inflating it by half the border width. Only expand the annotation /Rect when the painted bounds would otherwise be clipped, and only then persist the change for persistent targets. This prevents unconditional inflation of /Rect on every regeneration (which could cause unbounded growth) and makes appearance updates idempotent.
Add EmbedPDF attachment extraction APIs and file-attachment appearance generation. Implement EPDFDoc_GetAttachmentKey and EPDFDoc_GetAttachmentIndexByKey, the EPDFAttachmentExtractStatus enum, EPDFAttachment_ExtractFile and EPDFAttachment_ExtractFileToOwnedBuffer, and wire them into the public header. Introduce a streaming inflate helper FlateModule::FlateDecodeToSink (and its SinkDecodeStatus) to decode large/Flate-compressed embedded files without materializing the full output; add corresponding unit tests. Implement ExtractAttachmentFileToSink and supporting logic in fpdfsdk/fpdf_attachment.cpp (filter classification, sink-based and in-memory paths, size capping and error mapping). Add GenerateFileAttachmentSymbolAP/GenerateFileAttachmentAP and rotation/float-handling fixes in cpdf_generateap.cpp so file-attachment icons render correctly. Update API test checks and add extensive embedder tests for the new extraction APIs. Misc: include and build fixes and small helper utilities.
Expose a way to resolve a destination to its page dictionary object number. Implements CPDF_Dest::GetPageObjectNumber (handles numeric page indexes and page dictionary references, validates page visibility and XFA/extension cases) and exports EPDFDest_GetPageObjectNumber in the public API. Adds unit tests covering numeric and dictionary destinations and invalid references, updates headers and includes, and makes minor formatting/whitespace fixes in the C API test harness.
Retain action dictionaries on ActionNodeRecord so node payloads can be read on demand. Implement EPDFAction_GetNodeDest, EPDFAction_GetNodeURI, EPDFAction_GetNodeFilePath and EPDFAction_GetNodeName (with header docs) to expose goto/URI/file/name payloads; these getters consult the retained dictionary and may require the originating FPDF_DOCUMENT for name resolution. Update AppendAction to keep the dictionary alive. Make EPDFAnnot_SetAction remove any direct /Dest (ISO 32000-1 compliance) and add EPDFAnnot_RemoveAction and EPDFAnnot_RemoveDest with a shared RemoveLinkDictEntry helper. Add unit tests covering URI, destination, file path and named-action payloads and a missing include required by the tests.
Avoid resource-pruning bugs when content streams are appended by tracking whether this pass regenerated every existing content stream (CPDF_PageContentGenerator: CountExistingContentStreams + UpdateResourcesDict(regenerated_all_streams)).
Rewrite redaction appearance generation to synthesize/flatten a final overlay form when no /RO is present: add helpers to get redact regions/BBox, build Form XObjects (MakeRedactFormStream / BuildRedactOverlayForm), layout overlay text with /DA and /Repeat, and emit overlay ops (AppendRedactOverlayOps). Update GenerateRedactAP to use the new overlay form and commonize resources.
Simplify the public redaction APIs and internal reporting: remove the complex removed-annotation report buffers and replace them with an optional out_removed_annot_count that returns the number of non-REDACT annotations removed as a side-effect. Ensure pages are parsed before applying redactions and resolve overlays (pre-baked /RO wins, otherwise synthesize). Update public header signatures accordingly and add a test PDF (testing/resources/redact_inherited_colorspace.pdf) for inherited colorspace cases.
Misc: minor include cleanups and refactors.
Allow appearance generation for non-persistent targets by creating an ephemeral AcroForm view instead of failing when the document lacks /AcroForm. Relax DR (/DR) handling so a missing or font-less /DR does not veto generation: persistent targets seed or mutate the document's DR/Font to add a fallback, while ephemeral targets use a direct fallback font dict without mutating the doc.
Introduce a reconciled form view and related helpers in epdf_form.cpp: BuildReconciledForm, FinishTxnControl, CollectRawTxnControls, ReconciledFieldByObjNum, CollectReconciledTxnControls and an overload of CollectTxnControls that accepts an optional reconciled CPDF_InteractiveForm. Transactional control collection now prefers the reconciled (merged) widget set and falls back to the raw /Kids walk when needed. Update callers to accept and pass the reconciled view where appropriate (including using a fresh reconciled form during repair/bake steps). These changes improve correctness for multi-plane documents (e.g. recovered fields, twin widgets) and avoid unnecessary document mutation for ephemeral operations.
Add MirrorFieldValueToTwinControls to copy /V, /I and /RV from a promoted field to same-FQN twin control dictionaries (same-name twins living in their own plane) and call it from ApplyTextValue, ApplyChoiceValues and EPDFForm_ResetField so appearance generation sees the value. Update form/embedder tests by adding a two_plane_form.pdf fixture and a TwoPlaneTwinWidgetsFillTogether test that verifies toggles, text commits, and /DR seeding cover both twins. Adjust annotation appearance-related expectations (rect/BBox inflation) and refactor many fpdfsdk tests: rename MemoryFontFileAccess->MemoryFileAccess, replace detailed redaction-report helpers with simpler removed-count helpers, add bitmap/render helpers and numerous redaction overlay tests, and modernize action/form test usage (ScopedPage, null-model handling, widget creation via annot+field attach). Also tweak DestGetPageObjectNumber behavior for out-of-range legacy Dests and various minor test cleanups.
@bobsingor
bobsingor merged commit a39fb54 into embedpdf/feature/read-purityJul 20, 2026
@bobsingor
bobsingor deleted the embedpdf/feature/forms branch August 5, 2026 11:05
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@bobsingor
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Embedpdf/feature/forms - #31

Merged
bobsingor merged 13 commits into
embedpdf/feature/read-purityfrom
embedpdf/feature/forms
Jul 20, 2026
Merged

Embedpdf/feature/forms#31
bobsingor merged 13 commits into
embedpdf/feature/read-purityfrom
embedpdf/feature/forms

Conversation

@bobsingor

Copy link
Copy Markdown
Contributor

No description provided.

Introduce runtime-registered font support and per-annotation font subsetting for FreeText appearance generation. Adds CPDF_AnnotFontMap and CPDF_AnnotFontSubset to route fallback lookups to CFX_FontRegistry, create marker font entries in the AcroForm DR, and produce subsetted Type0/CIDFont dictionaries (using HarfBuzz) that embed only glyphs used by an annotation/layer. Update CPDF_Font::FallbackFontFromCharcode to prefer registered fonts and create runtime fallbacks, and switch FreeText AP generation to use CPDF_AnnotFontMap so resources include any registered fallback/subset fonts actually used. Expose UpdateDefaultAppearanceRegisteredFont to set a DA referencing a registered runtime font. Update BUILD.gn to include the new files and third_party/harfbuzz-ng, and add supporting CFX_FontRegistry and public/epdf_font glue.
Persist registered-font identity in marker font dictionaries and make font registry behavior robust.
- Store registered font id in marker font dict (key "EmbedPDFRegisteredFontId") and add CPDF_AnnotFontSubset::GetRegisteredFontIdFromMarkerFontDict to read it. CPDF_AnnotFontMap now checks the marker dict for identity instead of inferring from BaseFont/resource alias.
- Create marker font dicts with the new id field; make subset base-name comment deterministic.
- Prevent CFX_FontRegistry::ClearRegisteredFonts from resetting next_font_id to avoid reusing ids that may still be referenced by existing document markers.
- Update CPVT_FontMap unicode/charcode logic to use CharCodeFromUnicode checks and safe numeric conversions; preserve upstream appearance font selection behavior.
- Add/adjust tests and helpers in fpdfsdk to validate stable appearance streams, alias-suffix survival, fallback rendering, checksums, and related utilities.
- Update public API docs for font registration to clarify thread/ownership rules and ClearRegisteredFonts semantics.
Also includes small cleanup/refactors and added includes needed by new code and tests.
Prefer registered-font mapping when generating appearance streams for persistent form widgets: if the target is persistent and there are registered fallback fonts or the font dict indicates a registered subset, create a CPDF_AnnotFontMap with registered fallbacks and embed the corresponding Font resources. Refactor duplicated AP generation into a lambda to reduce code duplication and preserve the previous CPVT_FontMap path for non-registered cases. Add CFX_FontRegistry::HasFallbackFonts() and its declaration. Add tests and a DroidSansFallbackFull.ttf test font, plus helpers to register and assert registered fallback behaviour for FreeText, TextField, ComboBox, and ListBox Korean glyphs. Also include small test fixes (initializer_list include, wchar_t usage).
Introduce a session-free EPDF form snapshot API and related utilities to support EmbedPDF use-cases. Adds a large new implementation (fpdfsdk/epdf_form.cpp) and public/epdf_form.h plus embedder tests and test PDF resources. Extend CPDF_InteractiveForm with ResolveCurrentDict and ReconcileWidget to rebind dictionaries to a document's current view and recover widgets reachable from page /Annots but missing from /AcroForm /Fields. Make ExportToFDF honor a skip_empty_required flag to preserve historic omit-empty-required behavior. Add whitespace-exact XML serialization APIs (CFX_XMLNode::SaveCompact and CFX_XMLElement::SaveCompact) to avoid corrupting xml:space="preserve" payloads, and unconditionally include CFX_MemoryStream in the build. Numerous helper routines implement form snapshotting, write transactions (toggles, text, choice), FDF/XFDF import/export, and layer-correctness rules. Update BUILD.gn files to expose new sources and tests. Tests/resources for recovered/orphan widgets and toggle fields are added.
Introduce EmbedPDF PieceInfo support: add public header and full implementation for namespace-scoped document/page PieceInfo metadata (typed values, last-modified timestamps, arrays, clear operations, and page/document variants). Add embedder tests covering save/reload and layer/delta flows. Update BUILD.gn and fpdfsdk/BUILD.gn to expose the new header and include the new sources, and switch component("pdfium") to shared_library("pdfium") while adding resources.rc to its sources.
Introduce EmbedPDF APIs and implementations: adds detached, read-only action model (epdf_action.* + helpers + public/epdf_action.h) with embedder tests; implements layer-safe selective annotation/page flattening (epdf_flatten.cpp) and test resources. Plumbing and API changes: expose CPDF_AnnotContext::GetAnnotIndex(), add CPDF_GenerateAP::GenerateFormAPWithValueOverride and thread value_override through AP generation to allow regenerating widget appearances without changing /V, and adjust CPDF_GenerateAP::GenerateFormAP calls. Fix CPDF_InteractiveForm export logic for skip_empty_required to correctly treat missing/null/array values. Update BUILD.gn entries and public headers to export new APIs and add fpdfsdk build sources and tests. Adds test PDFs/resources for flattening.
Compute the true painted bounds of /InkList by accumulating all ink points into an ink_bounds rectangle and inflating it by half the border width. Only expand the annotation /Rect when the painted bounds would otherwise be clipped, and only then persist the change for persistent targets. This prevents unconditional inflation of /Rect on every regeneration (which could cause unbounded growth) and makes appearance updates idempotent.
Add EmbedPDF attachment extraction APIs and file-attachment appearance generation. Implement EPDFDoc_GetAttachmentKey and EPDFDoc_GetAttachmentIndexByKey, the EPDFAttachmentExtractStatus enum, EPDFAttachment_ExtractFile and EPDFAttachment_ExtractFileToOwnedBuffer, and wire them into the public header. Introduce a streaming inflate helper FlateModule::FlateDecodeToSink (and its SinkDecodeStatus) to decode large/Flate-compressed embedded files without materializing the full output; add corresponding unit tests. Implement ExtractAttachmentFileToSink and supporting logic in fpdfsdk/fpdf_attachment.cpp (filter classification, sink-based and in-memory paths, size capping and error mapping). Add GenerateFileAttachmentSymbolAP/GenerateFileAttachmentAP and rotation/float-handling fixes in cpdf_generateap.cpp so file-attachment icons render correctly. Update API test checks and add extensive embedder tests for the new extraction APIs. Misc: include and build fixes and small helper utilities.
Expose a way to resolve a destination to its page dictionary object number. Implements CPDF_Dest::GetPageObjectNumber (handles numeric page indexes and page dictionary references, validates page visibility and XFA/extension cases) and exports EPDFDest_GetPageObjectNumber in the public API. Adds unit tests covering numeric and dictionary destinations and invalid references, updates headers and includes, and makes minor formatting/whitespace fixes in the C API test harness.
Retain action dictionaries on ActionNodeRecord so node payloads can be read on demand. Implement EPDFAction_GetNodeDest, EPDFAction_GetNodeURI, EPDFAction_GetNodeFilePath and EPDFAction_GetNodeName (with header docs) to expose goto/URI/file/name payloads; these getters consult the retained dictionary and may require the originating FPDF_DOCUMENT for name resolution. Update AppendAction to keep the dictionary alive. Make EPDFAnnot_SetAction remove any direct /Dest (ISO 32000-1 compliance) and add EPDFAnnot_RemoveAction and EPDFAnnot_RemoveDest with a shared RemoveLinkDictEntry helper. Add unit tests covering URI, destination, file path and named-action payloads and a missing include required by the tests.
Avoid resource-pruning bugs when content streams are appended by tracking whether this pass regenerated every existing content stream (CPDF_PageContentGenerator: CountExistingContentStreams + UpdateResourcesDict(regenerated_all_streams)).
Rewrite redaction appearance generation to synthesize/flatten a final overlay form when no /RO is present: add helpers to get redact regions/BBox, build Form XObjects (MakeRedactFormStream / BuildRedactOverlayForm), layout overlay text with /DA and /Repeat, and emit overlay ops (AppendRedactOverlayOps). Update GenerateRedactAP to use the new overlay form and commonize resources.
Simplify the public redaction APIs and internal reporting: remove the complex removed-annotation report buffers and replace them with an optional out_removed_annot_count that returns the number of non-REDACT annotations removed as a side-effect. Ensure pages are parsed before applying redactions and resolve overlays (pre-baked /RO wins, otherwise synthesize). Update public header signatures accordingly and add a test PDF (testing/resources/redact_inherited_colorspace.pdf) for inherited colorspace cases.
Misc: minor include cleanups and refactors.
Allow appearance generation for non-persistent targets by creating an ephemeral AcroForm view instead of failing when the document lacks /AcroForm. Relax DR (/DR) handling so a missing or font-less /DR does not veto generation: persistent targets seed or mutate the document's DR/Font to add a fallback, while ephemeral targets use a direct fallback font dict without mutating the doc.
Introduce a reconciled form view and related helpers in epdf_form.cpp: BuildReconciledForm, FinishTxnControl, CollectRawTxnControls, ReconciledFieldByObjNum, CollectReconciledTxnControls and an overload of CollectTxnControls that accepts an optional reconciled CPDF_InteractiveForm. Transactional control collection now prefers the reconciled (merged) widget set and falls back to the raw /Kids walk when needed. Update callers to accept and pass the reconciled view where appropriate (including using a fresh reconciled form during repair/bake steps). These changes improve correctness for multi-plane documents (e.g. recovered fields, twin widgets) and avoid unnecessary document mutation for ephemeral operations.
Add MirrorFieldValueToTwinControls to copy /V, /I and /RV from a promoted field to same-FQN twin control dictionaries (same-name twins living in their own plane) and call it from ApplyTextValue, ApplyChoiceValues and EPDFForm_ResetField so appearance generation sees the value. Update form/embedder tests by adding a two_plane_form.pdf fixture and a TwoPlaneTwinWidgetsFillTogether test that verifies toggles, text commits, and /DR seeding cover both twins. Adjust annotation appearance-related expectations (rect/BBox inflation) and refactor many fpdfsdk tests: rename MemoryFontFileAccess->MemoryFileAccess, replace detailed redaction-report helpers with simpler removed-count helpers, add bitmap/render helpers and numerous redaction overlay tests, and modernize action/form test usage (ScopedPage, null-model handling, widget creation via annot+field attach). Also tweak DestGetPageObjectNumber behavior for out-of-range legacy Dests and various minor test cleanups.
@bobsingor
bobsingor merged commit a39fb54 into embedpdf/feature/read-purityJul 20, 2026
@bobsingor
bobsingor deleted the embedpdf/feature/forms branch August 5, 2026 11:05
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@bobsingor
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Embedpdf/feature/forms - #31

Merged
bobsingor merged 13 commits into
embedpdf/feature/read-purityfrom
embedpdf/feature/forms
Jul 20, 2026
Merged

Embedpdf/feature/forms#31
bobsingor merged 13 commits into
embedpdf/feature/read-purityfrom
embedpdf/feature/forms

Conversation

@bobsingor

Copy link
Copy Markdown
Contributor

No description provided.

Introduce runtime-registered font support and per-annotation font subsetting for FreeText appearance generation. Adds CPDF_AnnotFontMap and CPDF_AnnotFontSubset to route fallback lookups to CFX_FontRegistry, create marker font entries in the AcroForm DR, and produce subsetted Type0/CIDFont dictionaries (using HarfBuzz) that embed only glyphs used by an annotation/layer. Update CPDF_Font::FallbackFontFromCharcode to prefer registered fonts and create runtime fallbacks, and switch FreeText AP generation to use CPDF_AnnotFontMap so resources include any registered fallback/subset fonts actually used. Expose UpdateDefaultAppearanceRegisteredFont to set a DA referencing a registered runtime font. Update BUILD.gn to include the new files and third_party/harfbuzz-ng, and add supporting CFX_FontRegistry and public/epdf_font glue.
Persist registered-font identity in marker font dictionaries and make font registry behavior robust.
- Store registered font id in marker font dict (key "EmbedPDFRegisteredFontId") and add CPDF_AnnotFontSubset::GetRegisteredFontIdFromMarkerFontDict to read it. CPDF_AnnotFontMap now checks the marker dict for identity instead of inferring from BaseFont/resource alias.
- Create marker font dicts with the new id field; make subset base-name comment deterministic.
- Prevent CFX_FontRegistry::ClearRegisteredFonts from resetting next_font_id to avoid reusing ids that may still be referenced by existing document markers.
- Update CPVT_FontMap unicode/charcode logic to use CharCodeFromUnicode checks and safe numeric conversions; preserve upstream appearance font selection behavior.
- Add/adjust tests and helpers in fpdfsdk to validate stable appearance streams, alias-suffix survival, fallback rendering, checksums, and related utilities.
- Update public API docs for font registration to clarify thread/ownership rules and ClearRegisteredFonts semantics.
Also includes small cleanup/refactors and added includes needed by new code and tests.
Prefer registered-font mapping when generating appearance streams for persistent form widgets: if the target is persistent and there are registered fallback fonts or the font dict indicates a registered subset, create a CPDF_AnnotFontMap with registered fallbacks and embed the corresponding Font resources. Refactor duplicated AP generation into a lambda to reduce code duplication and preserve the previous CPVT_FontMap path for non-registered cases. Add CFX_FontRegistry::HasFallbackFonts() and its declaration. Add tests and a DroidSansFallbackFull.ttf test font, plus helpers to register and assert registered fallback behaviour for FreeText, TextField, ComboBox, and ListBox Korean glyphs. Also include small test fixes (initializer_list include, wchar_t usage).
Introduce a session-free EPDF form snapshot API and related utilities to support EmbedPDF use-cases. Adds a large new implementation (fpdfsdk/epdf_form.cpp) and public/epdf_form.h plus embedder tests and test PDF resources. Extend CPDF_InteractiveForm with ResolveCurrentDict and ReconcileWidget to rebind dictionaries to a document's current view and recover widgets reachable from page /Annots but missing from /AcroForm /Fields. Make ExportToFDF honor a skip_empty_required flag to preserve historic omit-empty-required behavior. Add whitespace-exact XML serialization APIs (CFX_XMLNode::SaveCompact and CFX_XMLElement::SaveCompact) to avoid corrupting xml:space="preserve" payloads, and unconditionally include CFX_MemoryStream in the build. Numerous helper routines implement form snapshotting, write transactions (toggles, text, choice), FDF/XFDF import/export, and layer-correctness rules. Update BUILD.gn files to expose new sources and tests. Tests/resources for recovered/orphan widgets and toggle fields are added.
Introduce EmbedPDF PieceInfo support: add public header and full implementation for namespace-scoped document/page PieceInfo metadata (typed values, last-modified timestamps, arrays, clear operations, and page/document variants). Add embedder tests covering save/reload and layer/delta flows. Update BUILD.gn and fpdfsdk/BUILD.gn to expose the new header and include the new sources, and switch component("pdfium") to shared_library("pdfium") while adding resources.rc to its sources.
Introduce EmbedPDF APIs and implementations: adds detached, read-only action model (epdf_action.* + helpers + public/epdf_action.h) with embedder tests; implements layer-safe selective annotation/page flattening (epdf_flatten.cpp) and test resources. Plumbing and API changes: expose CPDF_AnnotContext::GetAnnotIndex(), add CPDF_GenerateAP::GenerateFormAPWithValueOverride and thread value_override through AP generation to allow regenerating widget appearances without changing /V, and adjust CPDF_GenerateAP::GenerateFormAP calls. Fix CPDF_InteractiveForm export logic for skip_empty_required to correctly treat missing/null/array values. Update BUILD.gn entries and public headers to export new APIs and add fpdfsdk build sources and tests. Adds test PDFs/resources for flattening.
Compute the true painted bounds of /InkList by accumulating all ink points into an ink_bounds rectangle and inflating it by half the border width. Only expand the annotation /Rect when the painted bounds would otherwise be clipped, and only then persist the change for persistent targets. This prevents unconditional inflation of /Rect on every regeneration (which could cause unbounded growth) and makes appearance updates idempotent.
Add EmbedPDF attachment extraction APIs and file-attachment appearance generation. Implement EPDFDoc_GetAttachmentKey and EPDFDoc_GetAttachmentIndexByKey, the EPDFAttachmentExtractStatus enum, EPDFAttachment_ExtractFile and EPDFAttachment_ExtractFileToOwnedBuffer, and wire them into the public header. Introduce a streaming inflate helper FlateModule::FlateDecodeToSink (and its SinkDecodeStatus) to decode large/Flate-compressed embedded files without materializing the full output; add corresponding unit tests. Implement ExtractAttachmentFileToSink and supporting logic in fpdfsdk/fpdf_attachment.cpp (filter classification, sink-based and in-memory paths, size capping and error mapping). Add GenerateFileAttachmentSymbolAP/GenerateFileAttachmentAP and rotation/float-handling fixes in cpdf_generateap.cpp so file-attachment icons render correctly. Update API test checks and add extensive embedder tests for the new extraction APIs. Misc: include and build fixes and small helper utilities.
Expose a way to resolve a destination to its page dictionary object number. Implements CPDF_Dest::GetPageObjectNumber (handles numeric page indexes and page dictionary references, validates page visibility and XFA/extension cases) and exports EPDFDest_GetPageObjectNumber in the public API. Adds unit tests covering numeric and dictionary destinations and invalid references, updates headers and includes, and makes minor formatting/whitespace fixes in the C API test harness.
Retain action dictionaries on ActionNodeRecord so node payloads can be read on demand. Implement EPDFAction_GetNodeDest, EPDFAction_GetNodeURI, EPDFAction_GetNodeFilePath and EPDFAction_GetNodeName (with header docs) to expose goto/URI/file/name payloads; these getters consult the retained dictionary and may require the originating FPDF_DOCUMENT for name resolution. Update AppendAction to keep the dictionary alive. Make EPDFAnnot_SetAction remove any direct /Dest (ISO 32000-1 compliance) and add EPDFAnnot_RemoveAction and EPDFAnnot_RemoveDest with a shared RemoveLinkDictEntry helper. Add unit tests covering URI, destination, file path and named-action payloads and a missing include required by the tests.
Avoid resource-pruning bugs when content streams are appended by tracking whether this pass regenerated every existing content stream (CPDF_PageContentGenerator: CountExistingContentStreams + UpdateResourcesDict(regenerated_all_streams)).
Rewrite redaction appearance generation to synthesize/flatten a final overlay form when no /RO is present: add helpers to get redact regions/BBox, build Form XObjects (MakeRedactFormStream / BuildRedactOverlayForm), layout overlay text with /DA and /Repeat, and emit overlay ops (AppendRedactOverlayOps). Update GenerateRedactAP to use the new overlay form and commonize resources.
Simplify the public redaction APIs and internal reporting: remove the complex removed-annotation report buffers and replace them with an optional out_removed_annot_count that returns the number of non-REDACT annotations removed as a side-effect. Ensure pages are parsed before applying redactions and resolve overlays (pre-baked /RO wins, otherwise synthesize). Update public header signatures accordingly and add a test PDF (testing/resources/redact_inherited_colorspace.pdf) for inherited colorspace cases.
Misc: minor include cleanups and refactors.
Allow appearance generation for non-persistent targets by creating an ephemeral AcroForm view instead of failing when the document lacks /AcroForm. Relax DR (/DR) handling so a missing or font-less /DR does not veto generation: persistent targets seed or mutate the document's DR/Font to add a fallback, while ephemeral targets use a direct fallback font dict without mutating the doc.
Introduce a reconciled form view and related helpers in epdf_form.cpp: BuildReconciledForm, FinishTxnControl, CollectRawTxnControls, ReconciledFieldByObjNum, CollectReconciledTxnControls and an overload of CollectTxnControls that accepts an optional reconciled CPDF_InteractiveForm. Transactional control collection now prefers the reconciled (merged) widget set and falls back to the raw /Kids walk when needed. Update callers to accept and pass the reconciled view where appropriate (including using a fresh reconciled form during repair/bake steps). These changes improve correctness for multi-plane documents (e.g. recovered fields, twin widgets) and avoid unnecessary document mutation for ephemeral operations.
Add MirrorFieldValueToTwinControls to copy /V, /I and /RV from a promoted field to same-FQN twin control dictionaries (same-name twins living in their own plane) and call it from ApplyTextValue, ApplyChoiceValues and EPDFForm_ResetField so appearance generation sees the value. Update form/embedder tests by adding a two_plane_form.pdf fixture and a TwoPlaneTwinWidgetsFillTogether test that verifies toggles, text commits, and /DR seeding cover both twins. Adjust annotation appearance-related expectations (rect/BBox inflation) and refactor many fpdfsdk tests: rename MemoryFontFileAccess->MemoryFileAccess, replace detailed redaction-report helpers with simpler removed-count helpers, add bitmap/render helpers and numerous redaction overlay tests, and modernize action/form test usage (ScopedPage, null-model handling, widget creation via annot+field attach). Also tweak DestGetPageObjectNumber behavior for out-of-range legacy Dests and various minor test cleanups.
@bobsingor
bobsingor merged commit a39fb54 into embedpdf/feature/read-purityJul 20, 2026
@bobsingor
bobsingor deleted the embedpdf/feature/forms branch August 5, 2026 11:05
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@bobsingor
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Embedpdf/feature/forms - #31

Merged
bobsingor merged 13 commits into
embedpdf/feature/read-purityfrom
embedpdf/feature/forms
Jul 20, 2026
Merged

Embedpdf/feature/forms#31
bobsingor merged 13 commits into
embedpdf/feature/read-purityfrom
embedpdf/feature/forms

Conversation

@bobsingor

Copy link
Copy Markdown
Contributor

No description provided.

Introduce runtime-registered font support and per-annotation font subsetting for FreeText appearance generation. Adds CPDF_AnnotFontMap and CPDF_AnnotFontSubset to route fallback lookups to CFX_FontRegistry, create marker font entries in the AcroForm DR, and produce subsetted Type0/CIDFont dictionaries (using HarfBuzz) that embed only glyphs used by an annotation/layer. Update CPDF_Font::FallbackFontFromCharcode to prefer registered fonts and create runtime fallbacks, and switch FreeText AP generation to use CPDF_AnnotFontMap so resources include any registered fallback/subset fonts actually used. Expose UpdateDefaultAppearanceRegisteredFont to set a DA referencing a registered runtime font. Update BUILD.gn to include the new files and third_party/harfbuzz-ng, and add supporting CFX_FontRegistry and public/epdf_font glue.
Persist registered-font identity in marker font dictionaries and make font registry behavior robust.
- Store registered font id in marker font dict (key "EmbedPDFRegisteredFontId") and add CPDF_AnnotFontSubset::GetRegisteredFontIdFromMarkerFontDict to read it. CPDF_AnnotFontMap now checks the marker dict for identity instead of inferring from BaseFont/resource alias.
- Create marker font dicts with the new id field; make subset base-name comment deterministic.
- Prevent CFX_FontRegistry::ClearRegisteredFonts from resetting next_font_id to avoid reusing ids that may still be referenced by existing document markers.
- Update CPVT_FontMap unicode/charcode logic to use CharCodeFromUnicode checks and safe numeric conversions; preserve upstream appearance font selection behavior.
- Add/adjust tests and helpers in fpdfsdk to validate stable appearance streams, alias-suffix survival, fallback rendering, checksums, and related utilities.
- Update public API docs for font registration to clarify thread/ownership rules and ClearRegisteredFonts semantics.
Also includes small cleanup/refactors and added includes needed by new code and tests.
Prefer registered-font mapping when generating appearance streams for persistent form widgets: if the target is persistent and there are registered fallback fonts or the font dict indicates a registered subset, create a CPDF_AnnotFontMap with registered fallbacks and embed the corresponding Font resources. Refactor duplicated AP generation into a lambda to reduce code duplication and preserve the previous CPVT_FontMap path for non-registered cases. Add CFX_FontRegistry::HasFallbackFonts() and its declaration. Add tests and a DroidSansFallbackFull.ttf test font, plus helpers to register and assert registered fallback behaviour for FreeText, TextField, ComboBox, and ListBox Korean glyphs. Also include small test fixes (initializer_list include, wchar_t usage).
Introduce a session-free EPDF form snapshot API and related utilities to support EmbedPDF use-cases. Adds a large new implementation (fpdfsdk/epdf_form.cpp) and public/epdf_form.h plus embedder tests and test PDF resources. Extend CPDF_InteractiveForm with ResolveCurrentDict and ReconcileWidget to rebind dictionaries to a document's current view and recover widgets reachable from page /Annots but missing from /AcroForm /Fields. Make ExportToFDF honor a skip_empty_required flag to preserve historic omit-empty-required behavior. Add whitespace-exact XML serialization APIs (CFX_XMLNode::SaveCompact and CFX_XMLElement::SaveCompact) to avoid corrupting xml:space="preserve" payloads, and unconditionally include CFX_MemoryStream in the build. Numerous helper routines implement form snapshotting, write transactions (toggles, text, choice), FDF/XFDF import/export, and layer-correctness rules. Update BUILD.gn files to expose new sources and tests. Tests/resources for recovered/orphan widgets and toggle fields are added.
Introduce EmbedPDF PieceInfo support: add public header and full implementation for namespace-scoped document/page PieceInfo metadata (typed values, last-modified timestamps, arrays, clear operations, and page/document variants). Add embedder tests covering save/reload and layer/delta flows. Update BUILD.gn and fpdfsdk/BUILD.gn to expose the new header and include the new sources, and switch component("pdfium") to shared_library("pdfium") while adding resources.rc to its sources.
Introduce EmbedPDF APIs and implementations: adds detached, read-only action model (epdf_action.* + helpers + public/epdf_action.h) with embedder tests; implements layer-safe selective annotation/page flattening (epdf_flatten.cpp) and test resources. Plumbing and API changes: expose CPDF_AnnotContext::GetAnnotIndex(), add CPDF_GenerateAP::GenerateFormAPWithValueOverride and thread value_override through AP generation to allow regenerating widget appearances without changing /V, and adjust CPDF_GenerateAP::GenerateFormAP calls. Fix CPDF_InteractiveForm export logic for skip_empty_required to correctly treat missing/null/array values. Update BUILD.gn entries and public headers to export new APIs and add fpdfsdk build sources and tests. Adds test PDFs/resources for flattening.
Compute the true painted bounds of /InkList by accumulating all ink points into an ink_bounds rectangle and inflating it by half the border width. Only expand the annotation /Rect when the painted bounds would otherwise be clipped, and only then persist the change for persistent targets. This prevents unconditional inflation of /Rect on every regeneration (which could cause unbounded growth) and makes appearance updates idempotent.
Add EmbedPDF attachment extraction APIs and file-attachment appearance generation. Implement EPDFDoc_GetAttachmentKey and EPDFDoc_GetAttachmentIndexByKey, the EPDFAttachmentExtractStatus enum, EPDFAttachment_ExtractFile and EPDFAttachment_ExtractFileToOwnedBuffer, and wire them into the public header. Introduce a streaming inflate helper FlateModule::FlateDecodeToSink (and its SinkDecodeStatus) to decode large/Flate-compressed embedded files without materializing the full output; add corresponding unit tests. Implement ExtractAttachmentFileToSink and supporting logic in fpdfsdk/fpdf_attachment.cpp (filter classification, sink-based and in-memory paths, size capping and error mapping). Add GenerateFileAttachmentSymbolAP/GenerateFileAttachmentAP and rotation/float-handling fixes in cpdf_generateap.cpp so file-attachment icons render correctly. Update API test checks and add extensive embedder tests for the new extraction APIs. Misc: include and build fixes and small helper utilities.
Expose a way to resolve a destination to its page dictionary object number. Implements CPDF_Dest::GetPageObjectNumber (handles numeric page indexes and page dictionary references, validates page visibility and XFA/extension cases) and exports EPDFDest_GetPageObjectNumber in the public API. Adds unit tests covering numeric and dictionary destinations and invalid references, updates headers and includes, and makes minor formatting/whitespace fixes in the C API test harness.
Retain action dictionaries on ActionNodeRecord so node payloads can be read on demand. Implement EPDFAction_GetNodeDest, EPDFAction_GetNodeURI, EPDFAction_GetNodeFilePath and EPDFAction_GetNodeName (with header docs) to expose goto/URI/file/name payloads; these getters consult the retained dictionary and may require the originating FPDF_DOCUMENT for name resolution. Update AppendAction to keep the dictionary alive. Make EPDFAnnot_SetAction remove any direct /Dest (ISO 32000-1 compliance) and add EPDFAnnot_RemoveAction and EPDFAnnot_RemoveDest with a shared RemoveLinkDictEntry helper. Add unit tests covering URI, destination, file path and named-action payloads and a missing include required by the tests.
Avoid resource-pruning bugs when content streams are appended by tracking whether this pass regenerated every existing content stream (CPDF_PageContentGenerator: CountExistingContentStreams + UpdateResourcesDict(regenerated_all_streams)).
Rewrite redaction appearance generation to synthesize/flatten a final overlay form when no /RO is present: add helpers to get redact regions/BBox, build Form XObjects (MakeRedactFormStream / BuildRedactOverlayForm), layout overlay text with /DA and /Repeat, and emit overlay ops (AppendRedactOverlayOps). Update GenerateRedactAP to use the new overlay form and commonize resources.
Simplify the public redaction APIs and internal reporting: remove the complex removed-annotation report buffers and replace them with an optional out_removed_annot_count that returns the number of non-REDACT annotations removed as a side-effect. Ensure pages are parsed before applying redactions and resolve overlays (pre-baked /RO wins, otherwise synthesize). Update public header signatures accordingly and add a test PDF (testing/resources/redact_inherited_colorspace.pdf) for inherited colorspace cases.
Misc: minor include cleanups and refactors.
Allow appearance generation for non-persistent targets by creating an ephemeral AcroForm view instead of failing when the document lacks /AcroForm. Relax DR (/DR) handling so a missing or font-less /DR does not veto generation: persistent targets seed or mutate the document's DR/Font to add a fallback, while ephemeral targets use a direct fallback font dict without mutating the doc.
Introduce a reconciled form view and related helpers in epdf_form.cpp: BuildReconciledForm, FinishTxnControl, CollectRawTxnControls, ReconciledFieldByObjNum, CollectReconciledTxnControls and an overload of CollectTxnControls that accepts an optional reconciled CPDF_InteractiveForm. Transactional control collection now prefers the reconciled (merged) widget set and falls back to the raw /Kids walk when needed. Update callers to accept and pass the reconciled view where appropriate (including using a fresh reconciled form during repair/bake steps). These changes improve correctness for multi-plane documents (e.g. recovered fields, twin widgets) and avoid unnecessary document mutation for ephemeral operations.
Add MirrorFieldValueToTwinControls to copy /V, /I and /RV from a promoted field to same-FQN twin control dictionaries (same-name twins living in their own plane) and call it from ApplyTextValue, ApplyChoiceValues and EPDFForm_ResetField so appearance generation sees the value. Update form/embedder tests by adding a two_plane_form.pdf fixture and a TwoPlaneTwinWidgetsFillTogether test that verifies toggles, text commits, and /DR seeding cover both twins. Adjust annotation appearance-related expectations (rect/BBox inflation) and refactor many fpdfsdk tests: rename MemoryFontFileAccess->MemoryFileAccess, replace detailed redaction-report helpers with simpler removed-count helpers, add bitmap/render helpers and numerous redaction overlay tests, and modernize action/form test usage (ScopedPage, null-model handling, widget creation via annot+field attach). Also tweak DestGetPageObjectNumber behavior for out-of-range legacy Dests and various minor test cleanups.
@bobsingor
bobsingor merged commit a39fb54 into embedpdf/feature/read-purityJul 20, 2026
@bobsingor
bobsingor deleted the embedpdf/feature/forms branch August 5, 2026 11:05
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@bobsingor
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Embedpdf/feature/forms - #31

Merged
bobsingor merged 13 commits into
embedpdf/feature/read-purityfrom
embedpdf/feature/forms
Jul 20, 2026
Merged

Embedpdf/feature/forms#31
bobsingor merged 13 commits into
embedpdf/feature/read-purityfrom
embedpdf/feature/forms

Conversation

@bobsingor

Copy link
Copy Markdown
Contributor

No description provided.

Introduce runtime-registered font support and per-annotation font subsetting for FreeText appearance generation. Adds CPDF_AnnotFontMap and CPDF_AnnotFontSubset to route fallback lookups to CFX_FontRegistry, create marker font entries in the AcroForm DR, and produce subsetted Type0/CIDFont dictionaries (using HarfBuzz) that embed only glyphs used by an annotation/layer. Update CPDF_Font::FallbackFontFromCharcode to prefer registered fonts and create runtime fallbacks, and switch FreeText AP generation to use CPDF_AnnotFontMap so resources include any registered fallback/subset fonts actually used. Expose UpdateDefaultAppearanceRegisteredFont to set a DA referencing a registered runtime font. Update BUILD.gn to include the new files and third_party/harfbuzz-ng, and add supporting CFX_FontRegistry and public/epdf_font glue.
Persist registered-font identity in marker font dictionaries and make font registry behavior robust.
- Store registered font id in marker font dict (key "EmbedPDFRegisteredFontId") and add CPDF_AnnotFontSubset::GetRegisteredFontIdFromMarkerFontDict to read it. CPDF_AnnotFontMap now checks the marker dict for identity instead of inferring from BaseFont/resource alias.
- Create marker font dicts with the new id field; make subset base-name comment deterministic.
- Prevent CFX_FontRegistry::ClearRegisteredFonts from resetting next_font_id to avoid reusing ids that may still be referenced by existing document markers.
- Update CPVT_FontMap unicode/charcode logic to use CharCodeFromUnicode checks and safe numeric conversions; preserve upstream appearance font selection behavior.
- Add/adjust tests and helpers in fpdfsdk to validate stable appearance streams, alias-suffix survival, fallback rendering, checksums, and related utilities.
- Update public API docs for font registration to clarify thread/ownership rules and ClearRegisteredFonts semantics.
Also includes small cleanup/refactors and added includes needed by new code and tests.
Prefer registered-font mapping when generating appearance streams for persistent form widgets: if the target is persistent and there are registered fallback fonts or the font dict indicates a registered subset, create a CPDF_AnnotFontMap with registered fallbacks and embed the corresponding Font resources. Refactor duplicated AP generation into a lambda to reduce code duplication and preserve the previous CPVT_FontMap path for non-registered cases. Add CFX_FontRegistry::HasFallbackFonts() and its declaration. Add tests and a DroidSansFallbackFull.ttf test font, plus helpers to register and assert registered fallback behaviour for FreeText, TextField, ComboBox, and ListBox Korean glyphs. Also include small test fixes (initializer_list include, wchar_t usage).
Introduce a session-free EPDF form snapshot API and related utilities to support EmbedPDF use-cases. Adds a large new implementation (fpdfsdk/epdf_form.cpp) and public/epdf_form.h plus embedder tests and test PDF resources. Extend CPDF_InteractiveForm with ResolveCurrentDict and ReconcileWidget to rebind dictionaries to a document's current view and recover widgets reachable from page /Annots but missing from /AcroForm /Fields. Make ExportToFDF honor a skip_empty_required flag to preserve historic omit-empty-required behavior. Add whitespace-exact XML serialization APIs (CFX_XMLNode::SaveCompact and CFX_XMLElement::SaveCompact) to avoid corrupting xml:space="preserve" payloads, and unconditionally include CFX_MemoryStream in the build. Numerous helper routines implement form snapshotting, write transactions (toggles, text, choice), FDF/XFDF import/export, and layer-correctness rules. Update BUILD.gn files to expose new sources and tests. Tests/resources for recovered/orphan widgets and toggle fields are added.
Introduce EmbedPDF PieceInfo support: add public header and full implementation for namespace-scoped document/page PieceInfo metadata (typed values, last-modified timestamps, arrays, clear operations, and page/document variants). Add embedder tests covering save/reload and layer/delta flows. Update BUILD.gn and fpdfsdk/BUILD.gn to expose the new header and include the new sources, and switch component("pdfium") to shared_library("pdfium") while adding resources.rc to its sources.
Introduce EmbedPDF APIs and implementations: adds detached, read-only action model (epdf_action.* + helpers + public/epdf_action.h) with embedder tests; implements layer-safe selective annotation/page flattening (epdf_flatten.cpp) and test resources. Plumbing and API changes: expose CPDF_AnnotContext::GetAnnotIndex(), add CPDF_GenerateAP::GenerateFormAPWithValueOverride and thread value_override through AP generation to allow regenerating widget appearances without changing /V, and adjust CPDF_GenerateAP::GenerateFormAP calls. Fix CPDF_InteractiveForm export logic for skip_empty_required to correctly treat missing/null/array values. Update BUILD.gn entries and public headers to export new APIs and add fpdfsdk build sources and tests. Adds test PDFs/resources for flattening.
Compute the true painted bounds of /InkList by accumulating all ink points into an ink_bounds rectangle and inflating it by half the border width. Only expand the annotation /Rect when the painted bounds would otherwise be clipped, and only then persist the change for persistent targets. This prevents unconditional inflation of /Rect on every regeneration (which could cause unbounded growth) and makes appearance updates idempotent.
Add EmbedPDF attachment extraction APIs and file-attachment appearance generation. Implement EPDFDoc_GetAttachmentKey and EPDFDoc_GetAttachmentIndexByKey, the EPDFAttachmentExtractStatus enum, EPDFAttachment_ExtractFile and EPDFAttachment_ExtractFileToOwnedBuffer, and wire them into the public header. Introduce a streaming inflate helper FlateModule::FlateDecodeToSink (and its SinkDecodeStatus) to decode large/Flate-compressed embedded files without materializing the full output; add corresponding unit tests. Implement ExtractAttachmentFileToSink and supporting logic in fpdfsdk/fpdf_attachment.cpp (filter classification, sink-based and in-memory paths, size capping and error mapping). Add GenerateFileAttachmentSymbolAP/GenerateFileAttachmentAP and rotation/float-handling fixes in cpdf_generateap.cpp so file-attachment icons render correctly. Update API test checks and add extensive embedder tests for the new extraction APIs. Misc: include and build fixes and small helper utilities.
Expose a way to resolve a destination to its page dictionary object number. Implements CPDF_Dest::GetPageObjectNumber (handles numeric page indexes and page dictionary references, validates page visibility and XFA/extension cases) and exports EPDFDest_GetPageObjectNumber in the public API. Adds unit tests covering numeric and dictionary destinations and invalid references, updates headers and includes, and makes minor formatting/whitespace fixes in the C API test harness.
Retain action dictionaries on ActionNodeRecord so node payloads can be read on demand. Implement EPDFAction_GetNodeDest, EPDFAction_GetNodeURI, EPDFAction_GetNodeFilePath and EPDFAction_GetNodeName (with header docs) to expose goto/URI/file/name payloads; these getters consult the retained dictionary and may require the originating FPDF_DOCUMENT for name resolution. Update AppendAction to keep the dictionary alive. Make EPDFAnnot_SetAction remove any direct /Dest (ISO 32000-1 compliance) and add EPDFAnnot_RemoveAction and EPDFAnnot_RemoveDest with a shared RemoveLinkDictEntry helper. Add unit tests covering URI, destination, file path and named-action payloads and a missing include required by the tests.
Avoid resource-pruning bugs when content streams are appended by tracking whether this pass regenerated every existing content stream (CPDF_PageContentGenerator: CountExistingContentStreams + UpdateResourcesDict(regenerated_all_streams)).
Rewrite redaction appearance generation to synthesize/flatten a final overlay form when no /RO is present: add helpers to get redact regions/BBox, build Form XObjects (MakeRedactFormStream / BuildRedactOverlayForm), layout overlay text with /DA and /Repeat, and emit overlay ops (AppendRedactOverlayOps). Update GenerateRedactAP to use the new overlay form and commonize resources.
Simplify the public redaction APIs and internal reporting: remove the complex removed-annotation report buffers and replace them with an optional out_removed_annot_count that returns the number of non-REDACT annotations removed as a side-effect. Ensure pages are parsed before applying redactions and resolve overlays (pre-baked /RO wins, otherwise synthesize). Update public header signatures accordingly and add a test PDF (testing/resources/redact_inherited_colorspace.pdf) for inherited colorspace cases.
Misc: minor include cleanups and refactors.
Allow appearance generation for non-persistent targets by creating an ephemeral AcroForm view instead of failing when the document lacks /AcroForm. Relax DR (/DR) handling so a missing or font-less /DR does not veto generation: persistent targets seed or mutate the document's DR/Font to add a fallback, while ephemeral targets use a direct fallback font dict without mutating the doc.
Introduce a reconciled form view and related helpers in epdf_form.cpp: BuildReconciledForm, FinishTxnControl, CollectRawTxnControls, ReconciledFieldByObjNum, CollectReconciledTxnControls and an overload of CollectTxnControls that accepts an optional reconciled CPDF_InteractiveForm. Transactional control collection now prefers the reconciled (merged) widget set and falls back to the raw /Kids walk when needed. Update callers to accept and pass the reconciled view where appropriate (including using a fresh reconciled form during repair/bake steps). These changes improve correctness for multi-plane documents (e.g. recovered fields, twin widgets) and avoid unnecessary document mutation for ephemeral operations.
Add MirrorFieldValueToTwinControls to copy /V, /I and /RV from a promoted field to same-FQN twin control dictionaries (same-name twins living in their own plane) and call it from ApplyTextValue, ApplyChoiceValues and EPDFForm_ResetField so appearance generation sees the value. Update form/embedder tests by adding a two_plane_form.pdf fixture and a TwoPlaneTwinWidgetsFillTogether test that verifies toggles, text commits, and /DR seeding cover both twins. Adjust annotation appearance-related expectations (rect/BBox inflation) and refactor many fpdfsdk tests: rename MemoryFontFileAccess->MemoryFileAccess, replace detailed redaction-report helpers with simpler removed-count helpers, add bitmap/render helpers and numerous redaction overlay tests, and modernize action/form test usage (ScopedPage, null-model handling, widget creation via annot+field attach). Also tweak DestGetPageObjectNumber behavior for out-of-range legacy Dests and various minor test cleanups.
@bobsingor
bobsingor merged commit a39fb54 into embedpdf/feature/read-purityJul 20, 2026
@bobsingor
bobsingor deleted the embedpdf/feature/forms branch August 5, 2026 11:05
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@bobsingor
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Embedpdf/feature/forms - #31

Merged
bobsingor merged 13 commits into
embedpdf/feature/read-purityfrom
embedpdf/feature/forms
Jul 20, 2026
Merged

Embedpdf/feature/forms#31
bobsingor merged 13 commits into
embedpdf/feature/read-purityfrom
embedpdf/feature/forms

Conversation

@bobsingor

Copy link
Copy Markdown
Contributor

No description provided.

Introduce runtime-registered font support and per-annotation font subsetting for FreeText appearance generation. Adds CPDF_AnnotFontMap and CPDF_AnnotFontSubset to route fallback lookups to CFX_FontRegistry, create marker font entries in the AcroForm DR, and produce subsetted Type0/CIDFont dictionaries (using HarfBuzz) that embed only glyphs used by an annotation/layer. Update CPDF_Font::FallbackFontFromCharcode to prefer registered fonts and create runtime fallbacks, and switch FreeText AP generation to use CPDF_AnnotFontMap so resources include any registered fallback/subset fonts actually used. Expose UpdateDefaultAppearanceRegisteredFont to set a DA referencing a registered runtime font. Update BUILD.gn to include the new files and third_party/harfbuzz-ng, and add supporting CFX_FontRegistry and public/epdf_font glue.
Persist registered-font identity in marker font dictionaries and make font registry behavior robust.
- Store registered font id in marker font dict (key "EmbedPDFRegisteredFontId") and add CPDF_AnnotFontSubset::GetRegisteredFontIdFromMarkerFontDict to read it. CPDF_AnnotFontMap now checks the marker dict for identity instead of inferring from BaseFont/resource alias.
- Create marker font dicts with the new id field; make subset base-name comment deterministic.
- Prevent CFX_FontRegistry::ClearRegisteredFonts from resetting next_font_id to avoid reusing ids that may still be referenced by existing document markers.
- Update CPVT_FontMap unicode/charcode logic to use CharCodeFromUnicode checks and safe numeric conversions; preserve upstream appearance font selection behavior.
- Add/adjust tests and helpers in fpdfsdk to validate stable appearance streams, alias-suffix survival, fallback rendering, checksums, and related utilities.
- Update public API docs for font registration to clarify thread/ownership rules and ClearRegisteredFonts semantics.
Also includes small cleanup/refactors and added includes needed by new code and tests.
Prefer registered-font mapping when generating appearance streams for persistent form widgets: if the target is persistent and there are registered fallback fonts or the font dict indicates a registered subset, create a CPDF_AnnotFontMap with registered fallbacks and embed the corresponding Font resources. Refactor duplicated AP generation into a lambda to reduce code duplication and preserve the previous CPVT_FontMap path for non-registered cases. Add CFX_FontRegistry::HasFallbackFonts() and its declaration. Add tests and a DroidSansFallbackFull.ttf test font, plus helpers to register and assert registered fallback behaviour for FreeText, TextField, ComboBox, and ListBox Korean glyphs. Also include small test fixes (initializer_list include, wchar_t usage).
Introduce a session-free EPDF form snapshot API and related utilities to support EmbedPDF use-cases. Adds a large new implementation (fpdfsdk/epdf_form.cpp) and public/epdf_form.h plus embedder tests and test PDF resources. Extend CPDF_InteractiveForm with ResolveCurrentDict and ReconcileWidget to rebind dictionaries to a document's current view and recover widgets reachable from page /Annots but missing from /AcroForm /Fields. Make ExportToFDF honor a skip_empty_required flag to preserve historic omit-empty-required behavior. Add whitespace-exact XML serialization APIs (CFX_XMLNode::SaveCompact and CFX_XMLElement::SaveCompact) to avoid corrupting xml:space="preserve" payloads, and unconditionally include CFX_MemoryStream in the build. Numerous helper routines implement form snapshotting, write transactions (toggles, text, choice), FDF/XFDF import/export, and layer-correctness rules. Update BUILD.gn files to expose new sources and tests. Tests/resources for recovered/orphan widgets and toggle fields are added.
Introduce EmbedPDF PieceInfo support: add public header and full implementation for namespace-scoped document/page PieceInfo metadata (typed values, last-modified timestamps, arrays, clear operations, and page/document variants). Add embedder tests covering save/reload and layer/delta flows. Update BUILD.gn and fpdfsdk/BUILD.gn to expose the new header and include the new sources, and switch component("pdfium") to shared_library("pdfium") while adding resources.rc to its sources.
Introduce EmbedPDF APIs and implementations: adds detached, read-only action model (epdf_action.* + helpers + public/epdf_action.h) with embedder tests; implements layer-safe selective annotation/page flattening (epdf_flatten.cpp) and test resources. Plumbing and API changes: expose CPDF_AnnotContext::GetAnnotIndex(), add CPDF_GenerateAP::GenerateFormAPWithValueOverride and thread value_override through AP generation to allow regenerating widget appearances without changing /V, and adjust CPDF_GenerateAP::GenerateFormAP calls. Fix CPDF_InteractiveForm export logic for skip_empty_required to correctly treat missing/null/array values. Update BUILD.gn entries and public headers to export new APIs and add fpdfsdk build sources and tests. Adds test PDFs/resources for flattening.
Compute the true painted bounds of /InkList by accumulating all ink points into an ink_bounds rectangle and inflating it by half the border width. Only expand the annotation /Rect when the painted bounds would otherwise be clipped, and only then persist the change for persistent targets. This prevents unconditional inflation of /Rect on every regeneration (which could cause unbounded growth) and makes appearance updates idempotent.
Add EmbedPDF attachment extraction APIs and file-attachment appearance generation. Implement EPDFDoc_GetAttachmentKey and EPDFDoc_GetAttachmentIndexByKey, the EPDFAttachmentExtractStatus enum, EPDFAttachment_ExtractFile and EPDFAttachment_ExtractFileToOwnedBuffer, and wire them into the public header. Introduce a streaming inflate helper FlateModule::FlateDecodeToSink (and its SinkDecodeStatus) to decode large/Flate-compressed embedded files without materializing the full output; add corresponding unit tests. Implement ExtractAttachmentFileToSink and supporting logic in fpdfsdk/fpdf_attachment.cpp (filter classification, sink-based and in-memory paths, size capping and error mapping). Add GenerateFileAttachmentSymbolAP/GenerateFileAttachmentAP and rotation/float-handling fixes in cpdf_generateap.cpp so file-attachment icons render correctly. Update API test checks and add extensive embedder tests for the new extraction APIs. Misc: include and build fixes and small helper utilities.
Expose a way to resolve a destination to its page dictionary object number. Implements CPDF_Dest::GetPageObjectNumber (handles numeric page indexes and page dictionary references, validates page visibility and XFA/extension cases) and exports EPDFDest_GetPageObjectNumber in the public API. Adds unit tests covering numeric and dictionary destinations and invalid references, updates headers and includes, and makes minor formatting/whitespace fixes in the C API test harness.
Retain action dictionaries on ActionNodeRecord so node payloads can be read on demand. Implement EPDFAction_GetNodeDest, EPDFAction_GetNodeURI, EPDFAction_GetNodeFilePath and EPDFAction_GetNodeName (with header docs) to expose goto/URI/file/name payloads; these getters consult the retained dictionary and may require the originating FPDF_DOCUMENT for name resolution. Update AppendAction to keep the dictionary alive. Make EPDFAnnot_SetAction remove any direct /Dest (ISO 32000-1 compliance) and add EPDFAnnot_RemoveAction and EPDFAnnot_RemoveDest with a shared RemoveLinkDictEntry helper. Add unit tests covering URI, destination, file path and named-action payloads and a missing include required by the tests.
Avoid resource-pruning bugs when content streams are appended by tracking whether this pass regenerated every existing content stream (CPDF_PageContentGenerator: CountExistingContentStreams + UpdateResourcesDict(regenerated_all_streams)).
Rewrite redaction appearance generation to synthesize/flatten a final overlay form when no /RO is present: add helpers to get redact regions/BBox, build Form XObjects (MakeRedactFormStream / BuildRedactOverlayForm), layout overlay text with /DA and /Repeat, and emit overlay ops (AppendRedactOverlayOps). Update GenerateRedactAP to use the new overlay form and commonize resources.
Simplify the public redaction APIs and internal reporting: remove the complex removed-annotation report buffers and replace them with an optional out_removed_annot_count that returns the number of non-REDACT annotations removed as a side-effect. Ensure pages are parsed before applying redactions and resolve overlays (pre-baked /RO wins, otherwise synthesize). Update public header signatures accordingly and add a test PDF (testing/resources/redact_inherited_colorspace.pdf) for inherited colorspace cases.
Misc: minor include cleanups and refactors.
Allow appearance generation for non-persistent targets by creating an ephemeral AcroForm view instead of failing when the document lacks /AcroForm. Relax DR (/DR) handling so a missing or font-less /DR does not veto generation: persistent targets seed or mutate the document's DR/Font to add a fallback, while ephemeral targets use a direct fallback font dict without mutating the doc.
Introduce a reconciled form view and related helpers in epdf_form.cpp: BuildReconciledForm, FinishTxnControl, CollectRawTxnControls, ReconciledFieldByObjNum, CollectReconciledTxnControls and an overload of CollectTxnControls that accepts an optional reconciled CPDF_InteractiveForm. Transactional control collection now prefers the reconciled (merged) widget set and falls back to the raw /Kids walk when needed. Update callers to accept and pass the reconciled view where appropriate (including using a fresh reconciled form during repair/bake steps). These changes improve correctness for multi-plane documents (e.g. recovered fields, twin widgets) and avoid unnecessary document mutation for ephemeral operations.
Add MirrorFieldValueToTwinControls to copy /V, /I and /RV from a promoted field to same-FQN twin control dictionaries (same-name twins living in their own plane) and call it from ApplyTextValue, ApplyChoiceValues and EPDFForm_ResetField so appearance generation sees the value. Update form/embedder tests by adding a two_plane_form.pdf fixture and a TwoPlaneTwinWidgetsFillTogether test that verifies toggles, text commits, and /DR seeding cover both twins. Adjust annotation appearance-related expectations (rect/BBox inflation) and refactor many fpdfsdk tests: rename MemoryFontFileAccess->MemoryFileAccess, replace detailed redaction-report helpers with simpler removed-count helpers, add bitmap/render helpers and numerous redaction overlay tests, and modernize action/form test usage (ScopedPage, null-model handling, widget creation via annot+field attach). Also tweak DestGetPageObjectNumber behavior for out-of-range legacy Dests and various minor test cleanups.
@bobsingor
bobsingor merged commit a39fb54 into embedpdf/feature/read-purityJul 20, 2026
@bobsingor
bobsingor deleted the embedpdf/feature/forms branch August 5, 2026 11:05
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@bobsingor
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Embedpdf/feature/forms - #31

Merged
bobsingor merged 13 commits into
embedpdf/feature/read-purityfrom
embedpdf/feature/forms
Jul 20, 2026
Merged

Embedpdf/feature/forms#31
bobsingor merged 13 commits into
embedpdf/feature/read-purityfrom
embedpdf/feature/forms

Conversation

@bobsingor

Copy link
Copy Markdown
Contributor

No description provided.

Introduce runtime-registered font support and per-annotation font subsetting for FreeText appearance generation. Adds CPDF_AnnotFontMap and CPDF_AnnotFontSubset to route fallback lookups to CFX_FontRegistry, create marker font entries in the AcroForm DR, and produce subsetted Type0/CIDFont dictionaries (using HarfBuzz) that embed only glyphs used by an annotation/layer. Update CPDF_Font::FallbackFontFromCharcode to prefer registered fonts and create runtime fallbacks, and switch FreeText AP generation to use CPDF_AnnotFontMap so resources include any registered fallback/subset fonts actually used. Expose UpdateDefaultAppearanceRegisteredFont to set a DA referencing a registered runtime font. Update BUILD.gn to include the new files and third_party/harfbuzz-ng, and add supporting CFX_FontRegistry and public/epdf_font glue.
Persist registered-font identity in marker font dictionaries and make font registry behavior robust.
- Store registered font id in marker font dict (key "EmbedPDFRegisteredFontId") and add CPDF_AnnotFontSubset::GetRegisteredFontIdFromMarkerFontDict to read it. CPDF_AnnotFontMap now checks the marker dict for identity instead of inferring from BaseFont/resource alias.
- Create marker font dicts with the new id field; make subset base-name comment deterministic.
- Prevent CFX_FontRegistry::ClearRegisteredFonts from resetting next_font_id to avoid reusing ids that may still be referenced by existing document markers.
- Update CPVT_FontMap unicode/charcode logic to use CharCodeFromUnicode checks and safe numeric conversions; preserve upstream appearance font selection behavior.
- Add/adjust tests and helpers in fpdfsdk to validate stable appearance streams, alias-suffix survival, fallback rendering, checksums, and related utilities.
- Update public API docs for font registration to clarify thread/ownership rules and ClearRegisteredFonts semantics.
Also includes small cleanup/refactors and added includes needed by new code and tests.
Prefer registered-font mapping when generating appearance streams for persistent form widgets: if the target is persistent and there are registered fallback fonts or the font dict indicates a registered subset, create a CPDF_AnnotFontMap with registered fallbacks and embed the corresponding Font resources. Refactor duplicated AP generation into a lambda to reduce code duplication and preserve the previous CPVT_FontMap path for non-registered cases. Add CFX_FontRegistry::HasFallbackFonts() and its declaration. Add tests and a DroidSansFallbackFull.ttf test font, plus helpers to register and assert registered fallback behaviour for FreeText, TextField, ComboBox, and ListBox Korean glyphs. Also include small test fixes (initializer_list include, wchar_t usage).
Introduce a session-free EPDF form snapshot API and related utilities to support EmbedPDF use-cases. Adds a large new implementation (fpdfsdk/epdf_form.cpp) and public/epdf_form.h plus embedder tests and test PDF resources. Extend CPDF_InteractiveForm with ResolveCurrentDict and ReconcileWidget to rebind dictionaries to a document's current view and recover widgets reachable from page /Annots but missing from /AcroForm /Fields. Make ExportToFDF honor a skip_empty_required flag to preserve historic omit-empty-required behavior. Add whitespace-exact XML serialization APIs (CFX_XMLNode::SaveCompact and CFX_XMLElement::SaveCompact) to avoid corrupting xml:space="preserve" payloads, and unconditionally include CFX_MemoryStream in the build. Numerous helper routines implement form snapshotting, write transactions (toggles, text, choice), FDF/XFDF import/export, and layer-correctness rules. Update BUILD.gn files to expose new sources and tests. Tests/resources for recovered/orphan widgets and toggle fields are added.
Introduce EmbedPDF PieceInfo support: add public header and full implementation for namespace-scoped document/page PieceInfo metadata (typed values, last-modified timestamps, arrays, clear operations, and page/document variants). Add embedder tests covering save/reload and layer/delta flows. Update BUILD.gn and fpdfsdk/BUILD.gn to expose the new header and include the new sources, and switch component("pdfium") to shared_library("pdfium") while adding resources.rc to its sources.
Introduce EmbedPDF APIs and implementations: adds detached, read-only action model (epdf_action.* + helpers + public/epdf_action.h) with embedder tests; implements layer-safe selective annotation/page flattening (epdf_flatten.cpp) and test resources. Plumbing and API changes: expose CPDF_AnnotContext::GetAnnotIndex(), add CPDF_GenerateAP::GenerateFormAPWithValueOverride and thread value_override through AP generation to allow regenerating widget appearances without changing /V, and adjust CPDF_GenerateAP::GenerateFormAP calls. Fix CPDF_InteractiveForm export logic for skip_empty_required to correctly treat missing/null/array values. Update BUILD.gn entries and public headers to export new APIs and add fpdfsdk build sources and tests. Adds test PDFs/resources for flattening.
Compute the true painted bounds of /InkList by accumulating all ink points into an ink_bounds rectangle and inflating it by half the border width. Only expand the annotation /Rect when the painted bounds would otherwise be clipped, and only then persist the change for persistent targets. This prevents unconditional inflation of /Rect on every regeneration (which could cause unbounded growth) and makes appearance updates idempotent.
Add EmbedPDF attachment extraction APIs and file-attachment appearance generation. Implement EPDFDoc_GetAttachmentKey and EPDFDoc_GetAttachmentIndexByKey, the EPDFAttachmentExtractStatus enum, EPDFAttachment_ExtractFile and EPDFAttachment_ExtractFileToOwnedBuffer, and wire them into the public header. Introduce a streaming inflate helper FlateModule::FlateDecodeToSink (and its SinkDecodeStatus) to decode large/Flate-compressed embedded files without materializing the full output; add corresponding unit tests. Implement ExtractAttachmentFileToSink and supporting logic in fpdfsdk/fpdf_attachment.cpp (filter classification, sink-based and in-memory paths, size capping and error mapping). Add GenerateFileAttachmentSymbolAP/GenerateFileAttachmentAP and rotation/float-handling fixes in cpdf_generateap.cpp so file-attachment icons render correctly. Update API test checks and add extensive embedder tests for the new extraction APIs. Misc: include and build fixes and small helper utilities.
Expose a way to resolve a destination to its page dictionary object number. Implements CPDF_Dest::GetPageObjectNumber (handles numeric page indexes and page dictionary references, validates page visibility and XFA/extension cases) and exports EPDFDest_GetPageObjectNumber in the public API. Adds unit tests covering numeric and dictionary destinations and invalid references, updates headers and includes, and makes minor formatting/whitespace fixes in the C API test harness.
Retain action dictionaries on ActionNodeRecord so node payloads can be read on demand. Implement EPDFAction_GetNodeDest, EPDFAction_GetNodeURI, EPDFAction_GetNodeFilePath and EPDFAction_GetNodeName (with header docs) to expose goto/URI/file/name payloads; these getters consult the retained dictionary and may require the originating FPDF_DOCUMENT for name resolution. Update AppendAction to keep the dictionary alive. Make EPDFAnnot_SetAction remove any direct /Dest (ISO 32000-1 compliance) and add EPDFAnnot_RemoveAction and EPDFAnnot_RemoveDest with a shared RemoveLinkDictEntry helper. Add unit tests covering URI, destination, file path and named-action payloads and a missing include required by the tests.
Avoid resource-pruning bugs when content streams are appended by tracking whether this pass regenerated every existing content stream (CPDF_PageContentGenerator: CountExistingContentStreams + UpdateResourcesDict(regenerated_all_streams)).
Rewrite redaction appearance generation to synthesize/flatten a final overlay form when no /RO is present: add helpers to get redact regions/BBox, build Form XObjects (MakeRedactFormStream / BuildRedactOverlayForm), layout overlay text with /DA and /Repeat, and emit overlay ops (AppendRedactOverlayOps). Update GenerateRedactAP to use the new overlay form and commonize resources.
Simplify the public redaction APIs and internal reporting: remove the complex removed-annotation report buffers and replace them with an optional out_removed_annot_count that returns the number of non-REDACT annotations removed as a side-effect. Ensure pages are parsed before applying redactions and resolve overlays (pre-baked /RO wins, otherwise synthesize). Update public header signatures accordingly and add a test PDF (testing/resources/redact_inherited_colorspace.pdf) for inherited colorspace cases.
Misc: minor include cleanups and refactors.
Allow appearance generation for non-persistent targets by creating an ephemeral AcroForm view instead of failing when the document lacks /AcroForm. Relax DR (/DR) handling so a missing or font-less /DR does not veto generation: persistent targets seed or mutate the document's DR/Font to add a fallback, while ephemeral targets use a direct fallback font dict without mutating the doc.
Introduce a reconciled form view and related helpers in epdf_form.cpp: BuildReconciledForm, FinishTxnControl, CollectRawTxnControls, ReconciledFieldByObjNum, CollectReconciledTxnControls and an overload of CollectTxnControls that accepts an optional reconciled CPDF_InteractiveForm. Transactional control collection now prefers the reconciled (merged) widget set and falls back to the raw /Kids walk when needed. Update callers to accept and pass the reconciled view where appropriate (including using a fresh reconciled form during repair/bake steps). These changes improve correctness for multi-plane documents (e.g. recovered fields, twin widgets) and avoid unnecessary document mutation for ephemeral operations.
Add MirrorFieldValueToTwinControls to copy /V, /I and /RV from a promoted field to same-FQN twin control dictionaries (same-name twins living in their own plane) and call it from ApplyTextValue, ApplyChoiceValues and EPDFForm_ResetField so appearance generation sees the value. Update form/embedder tests by adding a two_plane_form.pdf fixture and a TwoPlaneTwinWidgetsFillTogether test that verifies toggles, text commits, and /DR seeding cover both twins. Adjust annotation appearance-related expectations (rect/BBox inflation) and refactor many fpdfsdk tests: rename MemoryFontFileAccess->MemoryFileAccess, replace detailed redaction-report helpers with simpler removed-count helpers, add bitmap/render helpers and numerous redaction overlay tests, and modernize action/form test usage (ScopedPage, null-model handling, widget creation via annot+field attach). Also tweak DestGetPageObjectNumber behavior for out-of-range legacy Dests and various minor test cleanups.
@bobsingor
bobsingor merged commit a39fb54 into embedpdf/feature/read-purityJul 20, 2026
@bobsingor
bobsingor deleted the embedpdf/feature/forms branch August 5, 2026 11:05
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@bobsingor
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Embedpdf/feature/forms - #31

Merged
bobsingor merged 13 commits into
embedpdf/feature/read-purityfrom
embedpdf/feature/forms
Jul 20, 2026
Merged

Embedpdf/feature/forms#31
bobsingor merged 13 commits into
embedpdf/feature/read-purityfrom
embedpdf/feature/forms

Conversation

@bobsingor

Copy link
Copy Markdown
Contributor

No description provided.

Introduce runtime-registered font support and per-annotation font subsetting for FreeText appearance generation. Adds CPDF_AnnotFontMap and CPDF_AnnotFontSubset to route fallback lookups to CFX_FontRegistry, create marker font entries in the AcroForm DR, and produce subsetted Type0/CIDFont dictionaries (using HarfBuzz) that embed only glyphs used by an annotation/layer. Update CPDF_Font::FallbackFontFromCharcode to prefer registered fonts and create runtime fallbacks, and switch FreeText AP generation to use CPDF_AnnotFontMap so resources include any registered fallback/subset fonts actually used. Expose UpdateDefaultAppearanceRegisteredFont to set a DA referencing a registered runtime font. Update BUILD.gn to include the new files and third_party/harfbuzz-ng, and add supporting CFX_FontRegistry and public/epdf_font glue.
Persist registered-font identity in marker font dictionaries and make font registry behavior robust.
- Store registered font id in marker font dict (key "EmbedPDFRegisteredFontId") and add CPDF_AnnotFontSubset::GetRegisteredFontIdFromMarkerFontDict to read it. CPDF_AnnotFontMap now checks the marker dict for identity instead of inferring from BaseFont/resource alias.
- Create marker font dicts with the new id field; make subset base-name comment deterministic.
- Prevent CFX_FontRegistry::ClearRegisteredFonts from resetting next_font_id to avoid reusing ids that may still be referenced by existing document markers.
- Update CPVT_FontMap unicode/charcode logic to use CharCodeFromUnicode checks and safe numeric conversions; preserve upstream appearance font selection behavior.
- Add/adjust tests and helpers in fpdfsdk to validate stable appearance streams, alias-suffix survival, fallback rendering, checksums, and related utilities.
- Update public API docs for font registration to clarify thread/ownership rules and ClearRegisteredFonts semantics.
Also includes small cleanup/refactors and added includes needed by new code and tests.
Prefer registered-font mapping when generating appearance streams for persistent form widgets: if the target is persistent and there are registered fallback fonts or the font dict indicates a registered subset, create a CPDF_AnnotFontMap with registered fallbacks and embed the corresponding Font resources. Refactor duplicated AP generation into a lambda to reduce code duplication and preserve the previous CPVT_FontMap path for non-registered cases. Add CFX_FontRegistry::HasFallbackFonts() and its declaration. Add tests and a DroidSansFallbackFull.ttf test font, plus helpers to register and assert registered fallback behaviour for FreeText, TextField, ComboBox, and ListBox Korean glyphs. Also include small test fixes (initializer_list include, wchar_t usage).
Introduce a session-free EPDF form snapshot API and related utilities to support EmbedPDF use-cases. Adds a large new implementation (fpdfsdk/epdf_form.cpp) and public/epdf_form.h plus embedder tests and test PDF resources. Extend CPDF_InteractiveForm with ResolveCurrentDict and ReconcileWidget to rebind dictionaries to a document's current view and recover widgets reachable from page /Annots but missing from /AcroForm /Fields. Make ExportToFDF honor a skip_empty_required flag to preserve historic omit-empty-required behavior. Add whitespace-exact XML serialization APIs (CFX_XMLNode::SaveCompact and CFX_XMLElement::SaveCompact) to avoid corrupting xml:space="preserve" payloads, and unconditionally include CFX_MemoryStream in the build. Numerous helper routines implement form snapshotting, write transactions (toggles, text, choice), FDF/XFDF import/export, and layer-correctness rules. Update BUILD.gn files to expose new sources and tests. Tests/resources for recovered/orphan widgets and toggle fields are added.
Introduce EmbedPDF PieceInfo support: add public header and full implementation for namespace-scoped document/page PieceInfo metadata (typed values, last-modified timestamps, arrays, clear operations, and page/document variants). Add embedder tests covering save/reload and layer/delta flows. Update BUILD.gn and fpdfsdk/BUILD.gn to expose the new header and include the new sources, and switch component("pdfium") to shared_library("pdfium") while adding resources.rc to its sources.
Introduce EmbedPDF APIs and implementations: adds detached, read-only action model (epdf_action.* + helpers + public/epdf_action.h) with embedder tests; implements layer-safe selective annotation/page flattening (epdf_flatten.cpp) and test resources. Plumbing and API changes: expose CPDF_AnnotContext::GetAnnotIndex(), add CPDF_GenerateAP::GenerateFormAPWithValueOverride and thread value_override through AP generation to allow regenerating widget appearances without changing /V, and adjust CPDF_GenerateAP::GenerateFormAP calls. Fix CPDF_InteractiveForm export logic for skip_empty_required to correctly treat missing/null/array values. Update BUILD.gn entries and public headers to export new APIs and add fpdfsdk build sources and tests. Adds test PDFs/resources for flattening.
Compute the true painted bounds of /InkList by accumulating all ink points into an ink_bounds rectangle and inflating it by half the border width. Only expand the annotation /Rect when the painted bounds would otherwise be clipped, and only then persist the change for persistent targets. This prevents unconditional inflation of /Rect on every regeneration (which could cause unbounded growth) and makes appearance updates idempotent.
Add EmbedPDF attachment extraction APIs and file-attachment appearance generation. Implement EPDFDoc_GetAttachmentKey and EPDFDoc_GetAttachmentIndexByKey, the EPDFAttachmentExtractStatus enum, EPDFAttachment_ExtractFile and EPDFAttachment_ExtractFileToOwnedBuffer, and wire them into the public header. Introduce a streaming inflate helper FlateModule::FlateDecodeToSink (and its SinkDecodeStatus) to decode large/Flate-compressed embedded files without materializing the full output; add corresponding unit tests. Implement ExtractAttachmentFileToSink and supporting logic in fpdfsdk/fpdf_attachment.cpp (filter classification, sink-based and in-memory paths, size capping and error mapping). Add GenerateFileAttachmentSymbolAP/GenerateFileAttachmentAP and rotation/float-handling fixes in cpdf_generateap.cpp so file-attachment icons render correctly. Update API test checks and add extensive embedder tests for the new extraction APIs. Misc: include and build fixes and small helper utilities.
Expose a way to resolve a destination to its page dictionary object number. Implements CPDF_Dest::GetPageObjectNumber (handles numeric page indexes and page dictionary references, validates page visibility and XFA/extension cases) and exports EPDFDest_GetPageObjectNumber in the public API. Adds unit tests covering numeric and dictionary destinations and invalid references, updates headers and includes, and makes minor formatting/whitespace fixes in the C API test harness.
Retain action dictionaries on ActionNodeRecord so node payloads can be read on demand. Implement EPDFAction_GetNodeDest, EPDFAction_GetNodeURI, EPDFAction_GetNodeFilePath and EPDFAction_GetNodeName (with header docs) to expose goto/URI/file/name payloads; these getters consult the retained dictionary and may require the originating FPDF_DOCUMENT for name resolution. Update AppendAction to keep the dictionary alive. Make EPDFAnnot_SetAction remove any direct /Dest (ISO 32000-1 compliance) and add EPDFAnnot_RemoveAction and EPDFAnnot_RemoveDest with a shared RemoveLinkDictEntry helper. Add unit tests covering URI, destination, file path and named-action payloads and a missing include required by the tests.
Avoid resource-pruning bugs when content streams are appended by tracking whether this pass regenerated every existing content stream (CPDF_PageContentGenerator: CountExistingContentStreams + UpdateResourcesDict(regenerated_all_streams)).
Rewrite redaction appearance generation to synthesize/flatten a final overlay form when no /RO is present: add helpers to get redact regions/BBox, build Form XObjects (MakeRedactFormStream / BuildRedactOverlayForm), layout overlay text with /DA and /Repeat, and emit overlay ops (AppendRedactOverlayOps). Update GenerateRedactAP to use the new overlay form and commonize resources.
Simplify the public redaction APIs and internal reporting: remove the complex removed-annotation report buffers and replace them with an optional out_removed_annot_count that returns the number of non-REDACT annotations removed as a side-effect. Ensure pages are parsed before applying redactions and resolve overlays (pre-baked /RO wins, otherwise synthesize). Update public header signatures accordingly and add a test PDF (testing/resources/redact_inherited_colorspace.pdf) for inherited colorspace cases.
Misc: minor include cleanups and refactors.
Allow appearance generation for non-persistent targets by creating an ephemeral AcroForm view instead of failing when the document lacks /AcroForm. Relax DR (/DR) handling so a missing or font-less /DR does not veto generation: persistent targets seed or mutate the document's DR/Font to add a fallback, while ephemeral targets use a direct fallback font dict without mutating the doc.
Introduce a reconciled form view and related helpers in epdf_form.cpp: BuildReconciledForm, FinishTxnControl, CollectRawTxnControls, ReconciledFieldByObjNum, CollectReconciledTxnControls and an overload of CollectTxnControls that accepts an optional reconciled CPDF_InteractiveForm. Transactional control collection now prefers the reconciled (merged) widget set and falls back to the raw /Kids walk when needed. Update callers to accept and pass the reconciled view where appropriate (including using a fresh reconciled form during repair/bake steps). These changes improve correctness for multi-plane documents (e.g. recovered fields, twin widgets) and avoid unnecessary document mutation for ephemeral operations.
Add MirrorFieldValueToTwinControls to copy /V, /I and /RV from a promoted field to same-FQN twin control dictionaries (same-name twins living in their own plane) and call it from ApplyTextValue, ApplyChoiceValues and EPDFForm_ResetField so appearance generation sees the value. Update form/embedder tests by adding a two_plane_form.pdf fixture and a TwoPlaneTwinWidgetsFillTogether test that verifies toggles, text commits, and /DR seeding cover both twins. Adjust annotation appearance-related expectations (rect/BBox inflation) and refactor many fpdfsdk tests: rename MemoryFontFileAccess->MemoryFileAccess, replace detailed redaction-report helpers with simpler removed-count helpers, add bitmap/render helpers and numerous redaction overlay tests, and modernize action/form test usage (ScopedPage, null-model handling, widget creation via annot+field attach). Also tweak DestGetPageObjectNumber behavior for out-of-range legacy Dests and various minor test cleanups.
@bobsingor
bobsingor merged commit a39fb54 into embedpdf/feature/read-purityJul 20, 2026
@bobsingor
bobsingor deleted the embedpdf/feature/forms branch August 5, 2026 11:05
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@bobsingor