465 Commits

Author SHA1 Message Date
Jonas Jenwald
82624a5e50 [api-minor] Convert getFieldObjects to return data in a Map
Compared to regular Objects there's a number of advantages to using Maps:
 - They support proper iteration.
 - They have a simple way to check for the existence of data.
 - They have a simple/efficient way to check the number of elements.

If this functionality was added today, I cannot imagine that we'd choose an Object for this data.

In the Firefox PDF Viewer sending Maps to the scripting-implementation should be fine, since it uses the browser `Cu.cloneInto` functionality; see https://searchfox.org/firefox-main/source/toolkit/components/pdfjs/content/PdfSandbox.sys.mjs
However with QuickJS, used by the GENERIC viewer, all data needs to be stringified and Maps are converted into regular Objects (see also PR 21664). Hence the `objects` property, in the scripting-implementation, is converted back into a Map using the (renamed) `createMap` helper function.
2026-08-02 21:27:07 +02:00
Jonas Jenwald
ce4ff55faa
Merge pull request #21664 from Snuffleupagus/getJSActions-api
[api-minor] Convert `getJSActions` to return data in a Map
2026-07-31 11:29:21 +02:00
Tim van der Meij
0163438e1a
Merge pull request #21660 from calixteman/fix/pdf-editor-preserve-widget-parent
Avoid mutating source widget parents
2026-07-30 21:02:29 +02:00
Jonas Jenwald
803c9d7d21 [api-minor] Convert getJSActions to return data in a Map
Compared to regular Objects there's a number of advantages to using Maps:
 - They support proper iteration.
 - They have a simple way to check for the existence of data.
 - They have a simple/efficient way to check the number of elements.

If this functionality was added today, I cannot imagine that we'd choose an Object for this data.

Note also how in the scripting-implementation the `actions` were already converted into a Map, via the `createActionsMap` helper.
In the Firefox PDF Viewer sending `Map`s to the scripting-implementation should be fine, since it uses the browser `Cu.cloneInto` functionality; see https://searchfox.org/firefox-main/source/toolkit/components/pdfjs/content/PdfSandbox.sys.mjs
However with QuickJS, used by the GENERIC viewer, all data needs to be stringified and unfortunately `JSON.stringify()` doesn't support Maps. Hence we convert Maps to Objects, via a [`replacer` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#replacer), since the existing `createActionsMap` usage will convert the actions-Objects back to Maps.
2026-07-30 16:04:58 +02:00
Calixte Denizet
aa812b531a Avoid mutating source widget parents 2026-07-29 16:03:15 +02:00
Calixte Denizet
3a19a20d50 Avoid duplicate shared object clones 2026-07-28 22:39:35 +02:00
Tim van der Meij
150fbba6e0
Merge pull request #21628 from calixteman/fix/pdf-editor-inherited-signature-flags
Preserve inherited signature flags
2026-07-26 11:56:38 +02:00
Jonas Jenwald
62d211ee8d Use the toBeTrue() matcher consistently in the unit/font/integration tests
This replaces all `toEqual(true)` and `toBe(true)` occurrences.
2026-07-25 23:52:28 +02:00
Jonas Jenwald
6963b0ef4f Use the toBeFalse() matcher consistently in the unit/integration tests
This replaces all `toEqual(false)` and `toBe(false)` occurrences.
2026-07-25 22:49:03 +02:00
Jonas Jenwald
b75ca17e85
Merge pull request #21636 from Snuffleupagus/test-toThrowError
Use the `toThrowError()` matcher consistently in the unit tests
2026-07-25 22:34:59 +02:00
Jonas Jenwald
dd41cd487d
Merge pull request #21633 from Snuffleupagus/test-toBeUndefined
Use the `toBeUndefined()` matcher consistently in the unit tests
2026-07-25 22:34:29 +02:00
Jonas Jenwald
432d5c57a4 Use the toThrowError() matcher consistently in the unit tests
Currently we mostly use `toThrow()`, which seems intended for things that throw non-Errors (something that we "forbid" with ESLint).
Hence `toThrowError()` seems more appropriate, and it also simplifies things slightly; see https://jasmine.github.io/api/edge/matchers.html#toThrowError
2026-07-25 14:30:55 +02:00
Jonas Jenwald
a9672298fc Use the toBeUndefined() matcher consistently in the unit tests
This replaces all `toEqual(undefined)` and `toBe(undefined)` occurrences.
2026-07-25 13:30:13 +02:00
Jonas Jenwald
60340d9f28 Use the toBeNull() matcher consistently in the unit/integration tests
This replaces all `toEqual(null)` and `toBe(null)` occurrences.
2026-07-25 12:58:43 +02:00
Calixte Denizet
27cf9e24f3 Preserve inherited signature flags 2026-07-24 20:42:26 +02:00
Tim van der Meij
05e100c76e
Merge pull request #21626 from calixteman/fix/pdf-editor-inherited-default-appearance
Preserve inherited text field appearances
2026-07-24 20:35:14 +02:00
Calixte Denizet
a97939b0d7 Preserve inherited text field appearances 2026-07-24 18:58:01 +02:00
Jonas Jenwald
675e9219b5 Remove the objectSize helper function
Given that Maps are used a lot more these days, this helper function is now used very sparingly and inlining the necessary code seems reasonable.

*Note:* Once [this proposal](https://github.com/tc39/proposal-object-keys-length) makes it into Firefox, we should be able to simplify all `Object.keys(...).length` call-sites.
2026-07-24 12:49:44 +02:00
Tim van der Meij
47969a5953
Merge pull request #21620 from calixteman/improve_modif_detections
Improve the detection of the changes made after a document has been signed
2026-07-23 20:57:59 +02:00
Jonas Jenwald
c474a97932 [api-minor] Convert getOpenAction to return data in a Map
Compared to regular Objects there's a number of advantages to using Maps:
 - They support proper iteration.
 - They have a simple way to check for the existence of data.
 - They have a simple/efficient way to check the number of elements.

If this functionality was added today, I cannot imagine that we'd choose an Object for this data.
2026-07-23 13:52:02 +02:00
Calixte Denizet
ed81227557 Improve the detection of the changes made after a document has been signed 2026-07-23 12:44:20 +02:00
Calixte Denizet
f0bbfa6f9e Preserve indirect AcroForm resources 2026-07-21 19:41:45 +02:00
Jonas Jenwald
de3eecca11 [api-minor] Convert getViewerPreferences to return data in a Map
Compared to regular Objects there's a number of advantages to using Maps:
 - They support proper iteration.
 - They have a simple way to check for the existence of data.
 - They have a simple/efficient way to check the number of elements.

If this functionality was added today, I cannot imagine that we'd choose an Object for this data.
2026-07-20 16:52:36 +02:00
Jonas Jenwald
ee56dc7719 Ignore Annotations with fieldValue = null when saving (issue 21582)
Some Annotations, e.g. `SignatureWidgetAnnotation`, set `fieldValue = null` which may causing saving to fail during `writeXFADataForAcroform`, hence we simply ignore any such Annotation-data during saving.
2026-07-19 23:00:31 +02:00
Jonas Jenwald
eddd70a2ca
Merge pull request #21597 from Snuffleupagus/destinations-Map
[api-minor] Convert `getDestinations` to return data in a Map
2026-07-19 16:06:12 +02:00
Tim van der Meij
b83274803c
Merge pull request #21588 from calixteman/fix/pdf-editor-struct-attribute-revisions
Handle revisioned structure attributes
2026-07-19 14:11:08 +02:00
Jonas Jenwald
6fbd2227db [api-minor] Convert getDestinations to return data in a Map
Compared to regular Objects there's a number of advantages to using Maps:
 - They support proper iteration.
 - They have a simple way to check for the existence of data.
 - They have a simple/efficient way to check the number of elements.

If this functionality was added today, I cannot imagine that we'd choose an Object for this data.
2026-07-19 12:07:08 +02:00
Calixte Denizet
922d57631b Rebuild missing AcroForm fields 2026-07-17 13:51:08 +02:00
Calixte Denizet
eb58ccc100 Handle revisioned structure attributes 2026-07-16 22:18:26 +02:00
Calixte Denizet
914545dea3 Fix AcroForm appearance resources when merging pages
Merging pages with conflicting AcroForm /DR must inline the resources
each field's appearance relies on, since only one /DR survives in the
output. That fixup:
- resolved the appearance /Resources ref against the source document's
  xref instead of the merged one, so the lookup failed and merging threw
  (null.has(...));
- skipped checkbox/radio widgets, whose /AP /N is a sub-dictionary of
  appearance states rather than a single stream;
- threw on a non-dictionary /Resources (e.g. a stray name) instead of
  falling back to the default resources.
2026-07-15 16:56:04 +02:00
Calixte Denizet
8070e9dce1 Preserve OBJR children without restoring deleted pages
Skip OBJR entries whose targets were not copied with a retained page.
2026-07-13 22:25:28 +02:00
Calixte Denizet
dae773d74a Handle indirect and dangling structure tree root kids
Preserve indirect root kids and marked content from removed link annotations. Ignore dangling kid references instead of throwing.
2026-07-13 21:48:30 +02:00
Calixte Denizet
850dccbc17 Preserve Unicode destination and attachment names
Name-tree keys are PDF text strings, so encode named destinations with
stringToAsciiOrUTF16BE when writing the /Dests tree; otherwise a non-ASCII
name (e.g. "名") is truncated to a single byte and lost on round-trip. Sort
the name/number tree by byte value rather than localeCompare, matching the
order used when the tree is read back.

Apply the same encoding to deduplicated /EmbeddedFiles names: those are
rebuilt from a decoded display string, so a non-ASCII attachment name would
otherwise be corrupted when its duplicate is written.
2026-07-13 21:19:23 +02:00
Calixte Denizet
a36e5acb30 Preserve non-local PDF link destinations 2026-07-13 14:27:47 +02:00
Jonas Jenwald
ac101f0381 Add API unit-tests for getSignatures and getSignatureData (PR 21247 follow-up)
Note that PR 21247 did include "local" unit-tests, however they don't cover all of the relevant API/Worker code-paths (which is noticeable in the coverage data).
The new unit-test added here uses a PDF document already present in the test-suite, and generally speaking testing a real-world PDF shouldn't hurt.
2026-07-04 17:08:39 +02:00
Calixte Denizet
9d9fb06d7f Re-derive annotation attachment content from the xref after cleanup
Annotation-local attachments (those not in the catalog `/Names` tree) were
resolved through a dictionary cache that `Catalog.cleanup` clears, so their
content became unreachable once the idle cleanup had run.

Encode the reference of the embedded content in the attachment id and re-fetch
it from the xref on demand instead of caching the dictionary, so the content
stays reachable without anything having to survive cleanup.

It fixes a regression introduced by #21351.
2026-06-18 16:03:32 +02:00
Jonas Jenwald
131d6b7d38 Handle corrupt PDFs that lack /Kids array and just inline the /Page dictionary (issue 21436)
This basically extends PR 9549 to the fallback `getAllPageDicts` method, which didn't exist at the time, in order to support more cases of corrupt PDF documents.
2026-06-12 12:04:58 +02:00
Jonas Jenwald
f3f5acc418 Fix the unit-tests for on-demand password handling of encrypted attachments (issue 21425)
These unit-tests used a PDF that prompted for password on document load, which meant that the on-demand password handling wasn't actually being tested as intended.

Updating the unit-tests also caused the "re-prompts for encrypted attachments after incorrect passwords" test to fail, since the `INCORRECT_PASSWORD` password reason was being accidentally "swallowed" in the worker-thread.
2026-06-10 23:08:34 +02:00
Jonas Jenwald
ea139e7df1 [api-minor] Convert getAttachments to return data in a Map
Compared to regular `Object`s there's a number of advantages to using `Map`s:
 - They support "proper" iteration.
 - They have a simple way to check for the existence of data.
 - They have a simple/efficient way to check the number of elements.

If this functionality was added today, I cannot imagine that we'd choose an `Object` for this sort of data.
Furthermore, in PR 21351 the data returned by `getAttachments` changed slightly and third-party users will need to update their code anyway (hence why `[api-minor]` should be fine here).
2026-06-09 10:17:23 +02:00
Tim van der Meij
81f15c3437
Merge pull request #21390 from Snuffleupagus/getDocument-binary-string-unit-test
Add a unit-test for passing a binary string to `getDocument`
2026-06-06 19:46:45 +02:00
Jonas Jenwald
a5333f2a92 Add a unit-test for passing a binary string to getDocument
This format is obviously not very efficient however it's been supported since "forever" and there's even examples using, hence it seems like a good idea to actually test this.
2026-06-06 14:37:25 +02:00
Jonas Jenwald
a7d32f4518 Add a unit-test for passing a filesystem URL-string (in Node.js) to getDocument
This improves coverage for a part of the API that previously wasn't tested.
2026-06-05 23:17:11 +02:00
Tim van der Meij
23ea0810d9
Merge pull request #21379 from calixteman/dedup_stream_merging
Deduplicate shared font/image streams when merging PDFs
2026-06-04 20:58:22 +02:00
Titus Wormer
4db9e45b8c
Add support for /AuthEvent, on-demand decryption
Normally entire PDFs are encrypted (or not).
But it is also possible to only encrypt attachments.
It is then also possible to *only* prompt for a password when the user opens
them.

In the existing flow, prompting for passwords happens because things are decrypted.
A specific error is thrown, caught, and the user is prompted.
To keep this flow working, this PR changes to decrypting attachments on demand,
instead of eagerly.
This sounds logical: to not read attachments on startup.

I’ve extensively tested this, not only with regular attachments, but also with outline items
and attachments in annotations.

This PR builds on GH-21234.
It’s an alternative to the naïve GH-20732.

Closes GH-20049.
2026-06-03 16:44:57 +02:00
Calixte Denizet
1a7821ab13 Deduplicate shared font/image streams when merging PDFs
Identical embedded fonts and images across the merged documents are now
written once and shared, instead of being copied per source file.
And avoid to compress already compressed stream with Brotli.
2026-06-02 22:08:21 +02:00
Calixte Denizet
600986b51d Allow inserting an image as a new page when editing a PDF
Image files dropped on or selected via the thumbnail viewer's
"add file" picker are now accepted alongside PDFs and inserted
as synthetic pages sized to the document's modal page dimensions.

The image-encoding helper previously embedded in StampAnnotation has
moved to src/core/editor/pdf_images.js so it can be shared between
stamp annotations and page synthesis.
2026-05-28 22:11:13 +02:00
Titus Wormer
45cdb5d3e8
Add support for encrypted attachments
This PR is related to GH-20732, which is about `AuthEvent` (to delay
promting for a password), but instead adds the actual support for
encrypted attachments.
“Encrypted attachments” means that the main things are plain text.
Note that some PDF viewers, like Preview/QuickLook/Safari or Chrome,
do not support attachments at all.
Note that the file checked into the tests is the same as
`output-no-auth-event.pdf` referenced in
<https://github.com/mozilla/pdf.js/issues/20139#issuecomment-3952462166>.

Closes GH-20139.
2026-05-28 10:30:37 +02:00
Calixte Denizet
8f85e3f20b Load the predefined CMap for composite fonts that omit the FontDescriptor
and add font substitutions for the standard Acrobat CJK families.
2026-05-25 14:44:48 +02:00
Jonas Jenwald
eda97fe8fc Move the PageViewport class into its own file
This is necessary to prevent import cycles with the next patch.

It also shouldn't hurt to reduce the size of `src/display/display_utils.js` a little bit, since utility-files have a tendency to increase in size over time.
2026-05-16 12:31:40 +02:00
Jonas Jenwald
949497a3c4 Add a simple API unit-test for /BrotliDecode
This is a new feature in PDF documents, hence it shouldn't hurt to complement the existing ref-test with a simple unit-test as well.
This should also improve test coverage for the `external/` folder, which can't hurt since the other external decoders are already fairly well covered.
2026-05-14 15:44:42 +02:00