Skip to content

Shared CPDF_Parser + per-layer overlay holder#23

Open
bobsingor wants to merge 57 commits into
embedpdf/mainfrom
embedpdf/feature/read-purity
Open

Shared CPDF_Parser + per-layer overlay holder#23
bobsingor wants to merge 57 commits into
embedpdf/mainfrom
embedpdf/feature/read-purity

Conversation

@bobsingor

Copy link
Copy Markdown
Contributor

No description provided.

bobsingor added 26 commits May 8, 2026 23:07
Harden layer read-purity by preventing layer page lookup and name-tree read APIs from entering mutable PDF graph paths.

This change:

- Adds a CPDF_LayerDocument::GetPageDictionary() override so unresolved layer page slots fail closed instead of running PDFium’s mutable page-tree fallback.
- Adds CPDF_NameTree::CreateForReading() and moves named destinations, attachments, JavaScript actions, and form-fill JavaScript scanning onto const traversal.
- Keeps mutating name-tree operations on the existing mutable creation path.
- Expands read-only layer canaries across render/cache, annotation, catalog, name-tree, malformed page-tree, and sibling-layer isolation cases.
- Verifies read-only layer workflows save empty deltas while peer layer mutations remain isolated.
Make `CPDF_Creator::WriteNewObjs()` reachability-aware so newly allocated indirect objects that are no longer referenced do not get written into saved PDFs. The save reachability set now includes normal document graph references plus trailer-owned roots such as `/Info` and non-inline `/Encrypt`, avoiding dangling trailer references while still pruning true orphans.

Also refactor `EPDF_SetEncryption()` to use an inline encryption dictionary so it follows CPDF_Creator’s existing trailer-owned encrypt path, and update Bug1206 to assert render-only saves remain stable while reopened rendering still matches.
Introduce EPDF_LoadMemBaseDocument to load a shareable base PDF document from a memory buffer. Refactor loading logic into LoadBaseDocumentImpl that accepts a RetainPtr<IFX_SeekableReadStream> so both file-access and in-memory paths share parsing code. Implement the in-memory path using CFX_ReadOnlySpanStream and UNSAFE_BUFFERS, and update public/fpdfview.h with the new API and documentation. Add test coverage: register the C API symbol in fpdf_view_c_api_test and add an embedder test that loads a PDF from memory. Also add the necessary include headers.
Introduce a size_t-based API for loading base documents from memory: add internal LoadMemBaseDocumentImpl and a public EPDF_LoadMemBaseDocument64 that accepts size_t. Preserve the existing EPDF_LoadMemBaseDocument(int) for backward compatibility but add a guard to reject negative sizes. Update tests to exercise the new API and register it in the C API test. Also add documentation for EPDF_LoadMemBaseDocument64 in the public header and update the release comment to reference both variants.
Introduce EPDFDoc_GetPageObjectNumberByIndex to return a page dictionary's indirect object number by zero-based page index without constructing a CPDF_Page (returns 0 for invalid indices, XFA pages, or direct objects). Add the function declaration to public/fpdfview.h, implement it in fpdfsdk/fpdf_view.cpp (with PDF_ENABLE_XFA guard), register it in the C API test, and add an embedder test verifying null/invalid inputs, non-parsing behavior, and consistency with EPDFPage_GetObjectNumber after loading the page.
Make annotation dictionary parameters const-correct by changing GetAnnotAP, GetAnnotAPNoFallback, and HasAPStream to accept const CPDF_Dictionary*. Update FPDFAnnot_GetColor to use the const-returning GetAnnotDictFromFPDFAnnotation and pass the const dict to HasAPStream. Add an annot_index parameter to RawAnnotContext, forward it to the CPDF_AnnotContext base, and update the creation site to pass the index. These changes improve const-safety and propagate the annotation index into the annot context.
Add ObjectTreeReferenceResolveMode to control how CPDF_Reference targets are resolved (through their holder or via the traversed document). Update ObjectTreeTraverser and GetObjectsWithReferences to accept this mode (defaulting to the previous behavior). Use kEffectiveDocument when collecting reachable objects for layer documents so overlay/promoted objects from a layer override the frozen base graph and are included in saves. Also add a unit test (LayerArtifactIncludesNewAnnotObjectBodies) to verify layer artifacts include newly created annotation object bodies, and add a clarifying comment in CPDF_Creator::WriteOldObjs about incremental vs full saves.
Introduce EmbedPDF redaction support and a reusable helper to append Form XObjects to a page.

- Add public API (public/epdf_redact.h) exposing EPDFAnnot_ApplyRedaction, EPDFAnnot_ApplyRedactionWithReport, EPDFPage_ApplyRedactions, and EPDFPage_ApplyRedactionsWithReport to apply redaction annotations and report removed annotations.
- Implement redaction logic in fpdfsdk/epdf_redact.cpp: collects redaction areas, removes text, flattens optional RO streams, detaches widget entries from AcroForm, cascades popup removals, and writes removal reports with /NM UTF-8 handling.
- Add page content helper (fpdfsdk/epdf_page_content_helpers.*) to append Form XObjects to pages and use it from fpdfsdk/fpdf_annot.cpp (replacing inlined flattening code).
- Update BUILD.gn to include new sources and update public/fpdf_annot.h to expose the new API header.
- Add tests and resources to cover redaction behaviors (removal, reporting, popup cascade, widget handling, preservation of sibling REDACTs, and touch-only annotations).

These changes centralize redaction behavior, provide reporting for removed annotations, and factor Form XObject flattening into a reusable helper.
@pmg1991

pmg1991 commented May 23, 2026

Copy link
Copy Markdown

@bobsingor
Add redaction API Wow thanks for the new API's would it be possible to have 2 more APIs like to 1. To get all actual list of streams/objects/text/image from ApplyRedaction* apis and 2. RestoreRedaction where we can pass previously redacted streams/objects/text/image list full or partial.

bobsingor added 3 commits May 24, 2026 18:33
Introduce a streaming API to write layer artifacts without materializing the whole artifact in memory.

- Add HashingTempFileWriter, a temporary-file-based FPDF_FILEWRITE that computes SHA-256 while writing, can finalize to get the digest, and can replay its contents to another FPDF_FILEWRITE.
- Add BuildLayerArtifactHeader and WriteBytes helpers to assemble the artifact header and safely write byte spans to an FPDF_FILEWRITE.
- Implement EPDFLayer_SaveLayerArtifact which saves a layer delta into a temp writer, finalizes the SHA-256, builds the layer artifact header, and streams header+delta to the provided FPDF_FILEWRITE while reporting status.
- Refactor EPDFLayer_SaveLayerArtifactToOwnedBuffer to reuse BuildLayerArtifactHeader.
- Add the public declaration and docs for EPDFLayer_SaveLayerArtifact to public/fpdf_save.h.
- Update tests and test registry: add check for EPDFLayer_SaveLayerArtifact in fpdf_view_c_api_test.c and extend LayerOwnedBufferAndArtifactReplay test to exercise streaming save and replay validation; also a minor formatting tweak in another test.
- Add <cstdio> include where needed.

This change enables native/server code paths to write artifacts without holding the full artifact in memory and ensures the delta is integrity-protected via SHA-256.
Introduce non-mutating password probe and a per-handle runtime owner-unlocked override. Adds CPDF_SecurityHandler::GetPermissionsForPasswordProbe, CheckPasswordNoMutate, and SetRuntimeOwnerUnlocked, plus public C APIs EPDF_CheckPasswordPermissions and EPDF_SetRuntimeOwnerPermissions. Implementations in fpdf_view.cpp and header declarations in public/fpdfview.h; tests updated/added in cpdf_security_handler_embeddertest.cpp and fpdf_view_c_api_test.c. These changes let embedders verify what permissions a password proves without changing the document's owner-unlocked state and allow embedder-managed sessions to temporarily treat a handle as owner-unlocked.
Introduce support for an /EMBD_Metadata dictionary on annotations and provide a full API to read/write app-specific metadata. Adds helpers to access EMBD_Metadata keys (Rotation, UnrotatedRect, VerticalAlignment, CustomJSON) and integrates them into shape rotation, vertical alignment, stamp-fitting and rendering paths (GetShapeRotationInfo, EPDFAnnot_UpdateAppearanceToRect, EPDF_RenderAnnotBitmapUnrotated, etc.).

Public API additions: EPDFAnnot_HasEmbedMetadata, EPDFAnnot_ClearEmbedMetadata, EPDFAnnot_ClearEmbedMetadataKey, EPDFAnnot_Set/GetEmbedMetadataString/Number/Boolean/Rect, EPDFAnnot_Set/GetEmbedMetadataJSON and EPDFDocument_ClearEmbedMetadata. Adds tests exercising the new metadata API and fixes minor formatting/whitespace issues. Deprecated/removed older EPDFRotate/EPDFUnrotatedRect/EPDF:VerticalAlignment helpers in favor of the unified EMBD_Metadata approach.
bobsingor added 28 commits May 30, 2026 23:43
Add EPDF_GetPageBoxByIndex and EPDF_GetPageUserUnitByIndex to query page box rectangles and /UserUnit without loading or parsing a page. Implement helper functions (GetPageDictionaryByIndex, GetInheritedPageRotation, GetPageBoxKey, GetEffectiveMediaBox) and reuse inherited-attribute walking for MediaBox/CropBox and rotation resolution. MediaBox falls back to PDFium default (612x792) when absent; CropBox falls back to MediaBox; Bleed/Trim/Art boxes are optional and return false if absent. /UserUnit returns the page value when present and positive, otherwise defaults to 1.0. Update EPDF_GetPageRotationByIndex to use the inherited-rotation helper. Add API enum and declarations to public/fpdfview.h, register new APIs in the C API test, and include unit tests in fpdf_view_embeddertest.cpp to validate behavior.
Ensure document /Info dictionaries are correctly promoted into layer overlays and serialized in deltas. CPDF_Creator now uses the current_info when writing the trailer and skips copying parser /Info entries; it only writes /Info if the current_info has a valid objnum. CPDF_Document::GetOrCreateInfo delegates to GetMutableInfo so layer behavior is honored. CPDF_LayerDocument::GetMutableInfo now returns/promotes the base /Info into the layer and IngestCurrentDelta imports a delta /Info (with validation) into the cached info. Added unit and embedder tests to cover promotion, creating layer-local Info when base has none, metadata updates, and saving/replaying deltas; also added a missing include for cpdf_string.
Embed pending security state inside CPDF_Document instead of using a global map and mutex. Add PendingSecurity struct, enum, and Set/Get/Clear methods to CPDF_Document; store an optional pending_security_ member. Update EPDF_SetEncryption/EPDF_RemoveEncryption and DoDocSave to use the document-owned pending state and remove the fpdfsdk_pending_security global storage and headers. Add a test to validate removal-of-encryption round-trip using the document-owned pending state. Cleanup includes and references to the deleted pending security header.
Introduce optional per-thread PDFium globals to support a thread-confined runtime for server worker pools. Adds core/fxcrt/epdf_tls.h (EPDF_TLS) and converts numerous process-global singletons to be thread-local when embedpdf_thread_local_globals is enabled. Exposes EPDF_InitThread/EPDF_ShutdownThread as lifecycle entry points, makes localtime usage thread-safe, and adjusts RNG/errno/timer/render/color/font/module globals accordingly. Adds a thread-soak test harness (testing/tools:epdf_thread_soak), build/test scripts (scripts/embedpdf-runtime/*), GN flag (embedpdf_thread_local_globals) and a GitHub Actions workflow (pdfium-tsan-thread-soak.yml) to run the TSAN-backed soak. Default behavior remains unchanged (flag off) so builds are byte-for-byte compatible unless explicitly enabled.
Mark the parser's static recursion depth variable as thread-local (EPDF_TLS) in both the header and source. Adds an #include for core/fxcrt/epdf_tls.h. This ensures each thread has its own s_CurrentRecursionDepth to avoid cross-thread interference when parsing concurrently; kParserMaxRecursionDepth is unchanged.
Add two PDF fixtures under testing/resources/pixel to exercise ICC profile parsing: icc_profile_bad_component.pdf embeds an ICCBased color space with N=1 (one component instead of the expected 3) but still triggers DetectSRGB(); icc_profile_bad_value.pdf contains a profile/value (0x80000000) that overflows when multiplied by 255. These files are used by pixel tests to validate robustness and error handling of ICC profile processing.
Add platform-specific defines for gmtime variants in BUILD.gn (HAVE_GMTIME_R on Linux/ChromeOS/Android/mac/iOS, HAVE_GMTIME_S on Windows). Update cmsplugin.c::_cmsGetTime to guard against gmtime returning NULL: copy the result into ptr_time only if non-NULL and return a boolean success value, avoiding a NULL dereference inside the critical section.
Add clarifying comments about concurrency and ThreadSanitizer findings in two lcms sources. In cmsplugin.c note that gmtime()'s shared static result is copied while holding the LCMS mutex to avoid TSan-reported races when creating ICC profiles concurrently. In cmswtpnt.c document that the D50 XYZ constant is safe for concurrent readers and that the xyY value is computed in a thread-confined way to avoid writing to a shared static on each call.
Introduce new EmbedPDF extension APIs to operate on pages by PDF object number. LoadPageByValidatedIndex gains a `normalize` flag to override page rotation to 0 for normalized coordinates, and EPDFDoc_LoadPageByObjectNumberNormalized is exported. Add EPDFDoc_DeletePageByObjectNumber to delete the first visible page matching an indirect object number (with XFA-backed documents rejected), and EPDFDoc_SetPageRotationByObjectNumber to update a page's /Rotate value (validates rotate in 0..3). Update public/fpdfview.h with API docs, add tests and test registrations in fpdf_view_embeddertest.cpp and fpdf_view_c_api_test.c, and include fpdf_edit.h where needed.
Prevent layer documents from promoting or null-replacing base /Page objects when deleting pages. Introduces GetNodeTypeForTraversal and uses const access during page-tree traversal to avoid unnecessary promotion; only request mutable dicts for branch /Pages nodes that will be edited. Adds virtual CPDF_Document::ShouldReplaceDeletedPageWithNull (default true) and overrides it in CPDF_LayerDocument to skip null-replacement for objects that exist in the base parser (deletion is represented by removing references from the promoted page tree). DeletePage now uses the mutable catalog path for proper layer edits, and SetPageToNullObject consults ShouldReplaceDeletedPageWithNull. Adds a unit test that verifies layer deletion saves a promoted page tree without null replacement.
Add overrides to CPDF_LayerDocument to ensure correct behavior for roots and page dictionaries in layer documents. Implement GetRoot() to return a local indirect root (so const reads observe overlays after delta ingest) and add GetMutablePageDictionary() that promotes a moved page object before returning a mutable dictionary. Update the header to declare the new methods. Add a unit test (LayerMovePagesPromotesMovedPageAndReplays) that verifies moving pages promotes the page object and that saved deltas replay correctly. Also adjust some test line breaks for readability.
Store the set of reachable objects in CPDF_Creator as objects_with_refs_ and use it when writing old/new objects instead of recomputing locally. Initialize and clear the cache in Create() via CollectSaveReachableObjects(document_, ...). Add the corresponding std::set include and member, plus minor header reorder and comment wrap. Add unit test LayerFullSavePrunesDeletedBasePageButKeepsSharedObjects (with helpers and CPDF_Reference include) to verify layer full-save prunes a deleted base page while preserving shared resource/content objects.
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.
Sign up for free to 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.

2 participants