1683 Commits

Author SHA1 Message Date
Calixte Denizet
ac75b10be1 Detect inherited signature fields in form info 2026-07-24 21:43:32 +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
6c18df5768
Restrict the elements, attributes and styles the XFA layer can render
Only create a known set of HTML/SVG elements, and only apply a known set
of attributes and CSS properties, when building the XFA/rich-text DOM;
anything else is now ignored.
2026-07-22 12:12:08 +02:00
Calixte Denizet
f0bbfa6f9e Preserve indirect AcroForm resources 2026-07-21 19:41:45 +02:00
Jonas Jenwald
028c02f539
Merge pull request #21607 from Snuffleupagus/viewerPreferences-Map
[api-minor] Convert `getViewerPreferences` to return data in a Map
2026-07-20 22:14:55 +02:00
calixteman
997dabf5a9
Merge pull request #21606 from calixteman/fix/ambiguous-date-format
Fix parsing of ambiguous date formats like `Hm`
2026-07-20 17:05:01 +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
calixteman
09a45ad2af
Merge pull request #21601 from uwezkhan/fix-postscript-wasm-i32const-sleb128
Encode i32.const immediates as signed LEB128 in the PostScript Wasm compiler
2026-07-20 15:29:20 +02:00
Calixte Denizet
d5661f801f Fix parsing of ambiguous date formats like Hm
We support having hours/minutes numbers with one or two digits for strings like "1:30:31" but
if the format is for example Hm, then "12" is really ambiguous.
So the idea is to match the longest string as possible.
2026-07-20 15:23:23 +02:00
uwezkhan
778aa450d9 Encode i32.const immediates as signed LEB128 in the PostScript Wasm compiler
The Type-4 PostScript -> Wasm compiler emitted i32.const immediates with the
unsigned LEB128 encoder (_emitULEB128). Wasm decodes i32.const as a *signed*
LEB128, so any immediate whose final 7-bit group has bit 0x40 set is
mis-decoded (e.g. 64 -> single byte 0x40 -> read back as -64).

The output-store address for the i-th result is emitted as i32.const (i*8).
For a function with >= 9 outputs the 9th offset is 64, which decodes as -64, so
f64.store targets 0xFFFFFFC0 and traps (memory access out of bounds). The module
still validates and instantiates, so the JS fallback in function.js is not
engaged; the trap only surfaces at render time (the affected shading / tint
transform silently fails to render). The same mis-encoding affects the constant
bitshift amount.

Add a signed-LEB128 emitter (_emitSLEB128) and use it for the three i32.const
immediate sites; local/import/type indices remain unsigned (correct). Add a unit
test covering functions with 9+ outputs, and a reference test rendering a shading
whose colour function has 9 outputs.
2026-07-20 14:56:04 +05:30
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
Tim van der Meij
fd77b3ea9f
Merge pull request #21591 from calixteman/fix/pdf-editor-missing-acroform-fields
Rebuild missing AcroForm fields
2026-07-19 14:08:40 +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
Jonas Jenwald
9a7335d26b Start using Iterator.prototype.join in the code-base
This is an upcoming JavaScript feature, which helps avoid creating intermediate Arrays in some cases; see https://github.com/tc39/proposal-iterator-join

Firefox implemented this in [bug 2004803](https://bugzilla.mozilla.org/show_bug.cgi?id=2004803), and it was enabled by default in [bug 2047995](https://bugzilla.mozilla.org/show_bug.cgi?id=2047995).

This patch changes two Objects to Maps, in the XFA-parsing respectively the find-implementation, to make use of the new feature.
2026-07-16 20:45:01 +02:00
Tim van der Meij
d473678201
Merge pull request #21577 from calixteman/fix/pdf-editor-acroform-resource-xref
Fix AcroForm appearance resources when merging pages
2026-07-16 20:13:44 +02:00
Tim van der Meij
f472cb081c
Merge pull request #21575 from calixteman/fix/signature-fields-with-widget-kids
Fix signature fields with widget children
2026-07-16 20:08:35 +02:00
Calixte Denizet
2ea9c26d77 Support SASLprep for AES-256 revision 6 passwords 2026-07-16 16:58:58 +02:00
Calixte Denizet
5f09f797ab Fix decryption of AES-256 revision 5 PDFs with non-ASCII passwords
It fixes #21579.
2026-07-16 16:34:15 +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
Jonas Jenwald
a3a7247366 Add a makeSet helper, to reduce function creation
This replaces inline `() => new Set()` statements, and also makes some `getOrInsertComputed` calls slightly shorter.
2026-07-15 15:24:25 +02:00
Jonas Jenwald
a18b581f00 Add a getOrPutComputed method in the RefSetCache class
This is equivalent to the native `Map.prototype.getOrInsertComputed()` method, and it helps simplify/shorten some existing code.
2026-07-15 15:24:22 +02:00
calixteman
82c6046e1d
Fix signature fields with widget children 2026-07-14 22:38:43 +02:00
Jonas Jenwald
2cf7d30763 Skip setFillColorN/setStrokeColorN operators without valid arguments (issue 21570)
The PDF document in question is corrupt, and note that even Adobe Reader (i.e. the PDF reference implementation) cannot render it correctly.

Also, guard all other set fill/stroke color operators similarly.
2026-07-14 16:08:59 +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
Tim van der Meij
67d591f413
Implement unit tests for the getRotationMatrix core utility function
This function is mostly covered indirectly by higher-level tests, but
unlike the other core utility functions it lacked dedicated unit tests.
This commit implements unit tests for it that also cover the previously
uncovered exception case, which brings coverage of the function to 100%
and ever so slighly increases coverage of the overarching file.
2026-07-06 20:43:03 +02:00
Tim van der Meij
f0818c1860
Implement a unit test for passing unsupported data types to MurmurHash3_64.update()
This commit brings the coverage of `src/shared/murmurhash3.js` to 100%.
2026-07-05 19:55:06 +02:00
calixteman
bf924ff31b
Merge pull request #21521 from calixteman/issue21520
Use `Intl.Segmenter` for the entire-word search matching
2026-07-05 19:20:36 +02:00
Tim van der Meij
e148b154cd
Merge pull request #21538 from greymoth-jp/fix/font-encodeString-fffe-fffff
Do not drop the character after U+FFFE or U+FFFF in Font.prototype.encodeString
2026-07-05 16:13:19 +02:00
Calixte Denizet
0c97aa7555
Use Intl.Segmenter for the entire-word search matching
`getCharacterType` was a port of the old `WordBreaker::GetClass`,
which has been removed and replaced with ICU4X word segmentation.
Use `Intl.Segmenter` instead, testing each match boundary on the two
adjacent grapheme clusters in isolation like Firefox's find.

It fixes #21520.
2026-07-05 14:37:21 +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
greymoth-jp
2bbf32d83d Do not drop the character after U+FFFE or U+FFFF in Font.prototype.encodeString
encodeString has the same surrogate-pair guard that encodeToXmlString had
before #21526: `unicode > 0xd7ff && (unicode < 0xe000 || unicode > 0xfffd)`.
That predicate is also true for U+FFFE and U+FFFF, which are single UTF-16
code units, not surrogate pairs. The extra `i++` then steps over the
character that follows them, so it is silently dropped from the
font-encoded output used when saving or printing a PDF.

For example, encoding a string that is U+FFFF followed by "A", with a font
that has a glyph for both, returns an encoded result ending in "A" on this
branch but drops the "A" on master.

Same fix as #21526: the correct test for a real surrogate pair is
`unicode > 0xffff`, since codePointAt only returns a value at or above
0x10000 for an actual pair. This keeps existing behavior for real surrogate
pairs (e.g. emoji) and the U+FFFD boundary, and only stops the character
after U+FFFE/U+FFFF from being dropped.

Added test/unit/fonts_spec.js, since Font.prototype.encodeString had no
direct unit test. It calls the method on a minimal fake `this` (only
toUnicode/cMap are read), since building a full Font requires a complete
properties/font-file setup that this bug doesn't depend on.
2026-07-04 21:37:12 +09:00
Tim van der Meij
9c46f48f88
Merge pull request #21526 from spokodev/w33/pdfjs-encodexml-surrogate
Do not drop the character after U+FFFE or U+FFFF in encodeToXmlString
2026-07-04 13:38:22 +02:00
Yarchik
0aee1d5382 Do not drop the character after U+FFFE or U+FFFF in encodeToXmlString
encodeToXmlString skips surrogate pairs with the guard
`char > 0xd7ff && (char < 0xe000 || char > 0xfffd)` and then does `i++` to step
over the low surrogate. That predicate is also true for U+FFFE and U+FFFF, which
are single UTF-16 code units, not surrogate pairs. The `i++` then skips the
character that follows them, so it is silently dropped.

For example, encodeToXmlString of U+FFFF followed by "A" returned "&#xFFFF;"
instead of "&#xFFFF;A". The function serializes XML text nodes and attribute
values in xml_parser.js and xfa_object.js, so this corrupts round-tripped XML
and XFA content.

The correct test for a surrogate pair is `char > 0xffff`, since codePointAt
returns a value at or above 0x10000 only for a real pair. This preserves the
existing behavior for emoji, the U+FFFD boundary, and lone surrogates, and stops
dropping the character after U+FFFE and U+FFFF.
2026-07-02 14:03:49 +01:00
Yarchik
9710372a1b Fix escapePDFName producing malformed name escapes for control characters
escapePDFName emitted a single hex digit for character codes below 0x10
(TAB became #9, not #09). PDF 32000-1 7.3.5 requires exactly two hex digits
after #. On re-save (annotations, form fields, font names) such a Name is
written malformed and the lexer mis-parses it on reload, dropping bytes.
Pad the hex to two digits; a no-op for codes 0x10 to 0xFF.
2026-07-02 10:48:57 +01:00
Benjamin Beurdouche
07b1c625e1 Add Digital signature properties verification panel
Adds a new "Digital signature properties" doorhanger to the pdf.js
toolbar that lists every digital signature found in the opened PDF,
verifies each one (via NSS in the Firefox build through a new chrome
bridge), and shows per-signature status + certificate state.

The viewer side parses /Sig dicts in the worker
(`PDFDocument.signatures`), strict-validates the /ByteRange offsets
before slicing, and ships only signature metadata across the worker
boundary. The PKCS#7 blob and signed-data byte spans live in a
worker-side map and are fetched lazily one signature at a time via
a new `getSignatureData(id)` RPC, immediately before verification
runs, so the bytes never sit in main-thread memory for the
document's lifetime.

The panel is feature-gated by `pdfjs.enableSignatureVerification`
(true in MOZCENTRAL/TESTING, off by default in the GENERIC build).
External services expose a `createSignatureVerifier()` factory that
the Firefox build wires up to `nsIX509CertDB.asyncVerifyPKCS7Object`;
GENERIC builds return null and the toolbar button stays hidden.

UI summary:
- Toolbar button states: loading dots while in flight, then green
  check, orange `!`, or red `✕` based on the worst aggregate
  signature status.
- Doorhanger contains a banner summarising the document state, then
  one card per signature with status row + certificate row (sub-
  signatures nested under their outer revision via /ByteRange
  containment).
- Icons are mono SVGs themed via `mask-image` + `background-color`
  so they pick up light/dark/HCM via `--sig-icon-*` vars; flipped
  under RTL via `scaleX(var(--dir-factor))`. The HCM mapping reuses
  the alt-text vocabulary (ButtonFace / ButtonText / ButtonBorder /
  GrayText / AccentColor / LinkText) so this panel reads the same
  as the rest of the editor toolbar in high-contrast mode.
- All visible strings are localized via Fluent
  (`pdfjs-digital-signature-properties-*`); status row, banner, and
  certificate row use explicit lookup tables instead of generated
  ids so a grep finds them.
- Esc + outside-click close the panel through the viewer's existing
  handlers; the manager exposes `isOpen`, `close()`, and
  `shouldCloseOnClick(target)` for that.

This commit also adds a `test/pdfs/sig_corpus/` directory holding a
Python generator that produces a corpus of signed PDFs covering
every visible state of the doorhanger (verified / untrusted /
expired / invalid / unknown / multi-signature variants). The corpus
is intentionally NOT part of the automated test suite — it is a
manual-test tool. Generated `.pdf` files are gitignored; only the
generator, README, and a `user.js.example` snippet are tracked.
The generator shells out to mozilla-central's
`security/manager/tools/pycms.py` (resolved via `--mozilla-central
<path>` or the `MOZILLA_CENTRAL_SRC` env var) and the embedded test
trust anchors (`pdf-sign-ca` / `pdf-sign-ca-expired`), gated by
`security.pdf_signature_verification.enable_test_trust_anchors` so
the test certificates never validate in shipping Firefox.
2026-06-30 13:25:09 +02:00
Calixte Denizet
3ccc3ec65c Add support for Sound annotations playing embedded audio
Wrap uncompressed PCM sound streams (Raw/Signed, 8/16-bit, mono/stereo)
in WAV and play them through the shared media overlay.
2026-06-29 12:30:48 +02:00
Jonas Jenwald
f07a106529 Include the catalog instance in the annotationGlobals data
The `FileAttachmentAnnotation` and `MediaAnnotation` code needs to (synchronously) access a `catalog` method, which leads to unnecessarily verbose code.
This can be avoided by including the `catalog` instance in the `annotationGlobals` data, which is safe since it already includes data that's fetched asynchronously from the `catalog` instance.
2026-06-24 10:42:38 +02:00