5170 Commits

Author SHA1 Message Date
Tim van der Meij
93958e4ff6
Merge pull request #21640 from Snuffleupagus/defaultOptions-Map
Change `defaultOptions`, in the `web/app_options.js` file, to a Map
2026-07-28 20:18:03 +02:00
calixteman
1609bd87c5
Merge commit from fork
Harden the XFA layer and restrict scripting updates to known fields
2026-07-27 19:38:24 +02:00
Jonas Jenwald
5406d3159b Change defaultOptions, in the web/app_options.js file, to a Map
Compared to regular Objects there's a number of advantages to using Maps, e.g. they support proper iteration.

Additionally the conditionally defined options are moved into the main list, to maintain alphabetical order for each individual `OptionKind`.
Finally, the `enableSelectionRendering` option is moved to its "correct" position and the `enableFakeMLManager` option is limited to TESTING builds (since that's consistent with its usage in `web/app.js`).

*Note:* Despite making the source-code larger, the size of the `gulp mozcentral` bundle is *reduced* by `686` bytes.
2026-07-27 12:53:13 +02:00
Calixte Denizet
f195bec9b2
Add the Firefox features notification bar to the viewer (bug 2057608)
The bar itself (`<pdf-features-notification>`) ships from mozilla-central, so
the viewer only hosts it.

Finally the maximum number of preferences is raised to 60, to match the change
made in mozilla-central in bug 2056102, since this adds a 51st one.
2026-07-25 08:43:01 +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
4ea07c2431
Only handle scripting updates that target a known field
Collect the ids of the document field annotations and ignore any id
coming from the scripting sandbox that isn't among them.
2026-07-22 16:11:57 +02:00
Tim van der Meij
be89d6475d
Merge pull request #21585 from Snuffleupagus/Iterator-join
Start using `Iterator.prototype.join` in the code-base
2026-07-19 13:48:06 +02:00
Jonas Jenwald
47f2b22842 Use Iterator methods to avoid some unnecessary Array creation
Currently there are some spots in the code-base where intermediate Arrays are unnecessarily created from Iterators, before `filter` and `map` is used to create a final Array.
Thanks to newer Iterators methods, see e.g. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/filter, that can be now be avoided.
2026-07-17 21:23:08 +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
Jonas Jenwald
6d7bca521b Use Map.prototype.getOrInsertComputed more in the web/ folder 2026-07-16 19:37:13 +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
Calixte Denizet
125f692589 Commit the current editing session before saving (bug 2047516)
When saving or downloading a document, an annotation that was still
being edited (e.g. an in-progress ink drawing) wasn't committed first,
so its content was missing from the saved file.
2026-07-13 19:08:42 +02:00
Jonas Jenwald
c46720d893 Use for...of even more in the code-base
This replaces a couple of "standard" `for` loops with the shorter `for...of` format instead.
2026-07-11 13:15:36 +02:00
Jonas Jenwald
6689097a0a
Merge pull request #21543 from Snuffleupagus/FakeSignatureVerifier
Add a `FakeSignatureVerifier` for development mode and TESTING builds (PR 21247 follow-up)
2026-07-05 23:20:58 +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
c188012280 Add a FakeSignatureVerifier for development mode and TESTING builds (PR 21247 follow-up)
Despite the `enableSignatureVerification` option/preference being enabled in development mode and TESTING builds, the lack of any `SignatureVerifier` implementation still renders the UI disabled.
This seems unfortunate, since it makes it more difficult to check that the digital signature UI works correctly:
 - That the button is visible when it's supposed to be, and that the panel can be opened/closed.
 - That the UI looks correct, w.r.t. the HTML elements and their CSS rules.
 - Currently the viewer JS code is effectively uncovered, with overall test-coverage dropping from `90` to `89` percent when PR 21247 landed.

To improve the current situation this patch adds a `FakeSignatureVerifier` class, limited to only development mode and TESTING builds, that treats every digital signature as invalid.
This allows easier manual testing, and also the addition of a few *very rudimentary* integration-tests.

*Note:* It probably wouldn't be all that difficult to add additional integration-tests for *valid* certificates, by having the test-cases instruct (during setup) the `FakeSignatureVerifier` how to respond to simulate verified certificates.
2026-07-05 13:43:25 +02:00
Tim van der Meij
4fd232a124
Update dependencies to the most recent versions
Note that the `prettier` update introduces a handful of formatting
changes (see https://prettier.io/blog/2026/06/27/3.9.0).

Moreover, the `tsc-alias` update requires explicitly defining the root
URL in the compiler options now, otherwise it errors with `tsc-alias
error: compilerOptions.rootDir is required with implicit baseUrl` (see
https://github.com/justkey007/tsc-alias/pull/259/changes).
2026-07-04 14:49:36 +02:00
Jonas Jenwald
046e68d140 Extend the unicorn/logical-assignment-operators rule to if-statements
Please see https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/logical-assignment-operators.md and https://eslint.org/docs/latest/rules/logical-assignment-operators#enforceforifstatements
2026-07-04 12:25:57 +02:00
Tim van der Meij
32f3906960
Merge pull request #21533 from Snuffleupagus/SignaturePropertiesManager-#bannerState
Move the `bannerStateForResults` helper into the `SignaturePropertiesManager` class (PR 21247 follow-up)
2026-07-03 20:13:58 +02:00
Tim van der Meij
e414f74375
Merge pull request #21534 from Snuffleupagus/addPasteButton-#getPageL10nArgs
Use the `#getPageL10nArgs` helper in the `PDFThumbnailView.prototype.addPasteButton` method
2026-07-03 20:11:49 +02:00
Tim van der Meij
70c52132af
Merge pull request #21514 from nicolo-ribaudo/remove-selection-conflict-chrome
Avoid text selection workaround in modern Chromium
2026-07-03 20:10:28 +02:00
Jonas Jenwald
0c076f5f0b Use the #getPageL10nArgs helper in the PDFThumbnailView.prototype.addPasteButton method
Rather than effectively duplicating code, we can re-use the existing helper here as well.
2026-07-03 16:18:25 +02:00
Jonas Jenwald
14f4cce29d Move the bannerStateForResults helper into the SignaturePropertiesManager class (PR 21247 follow-up)
This has a couple of advantages:
 - It allows accessing and iterating `this.#results` directly, without having to (needlessly) create a temporary array.

 - By moving the "worst status" computation into its own getter, it can be re-used from the `#updateButtonState` method as well which reduces code duplication.
2026-07-03 12:41:15 +02:00
calixteman
ab90210aa4
Merge pull request #21531 from Snuffleupagus/PDFThumbnailViewer-#updateStatus-isCopy
Reduce duplication when updating undoButton/undoCloseButton in `PDFThumbnailViewer.prototype.#updateStatus`
2026-07-03 08:14:23 +02:00
calixteman
44ae5b0e9a
Merge pull request #21529 from Snuffleupagus/SignaturePropertiesManager-geckoview
[GeckoView] Add `web-digital_signature_properties_manager` import map (PR 21247 follow-up)
2026-07-03 08:13:08 +02:00
Jonas Jenwald
f373fbfa5b Reduce duplication when updating undoButton/undoCloseButton in PDFThumbnailViewer.prototype.#updateStatus 2026-07-03 00:03:17 +02:00
Benjamin Beurdouche
34629bd2cf Deduplicate the signature-properties warn/error toolbar icon
The warn and error state badges shipped as byte-identical files (an
X-in-circle glyph). Drop the redundant
toolbarButton-signaturePropertiesWarn.svg and point the warn state at
the error icon instead; the amber-vs-red distinction is preserved via
background-color (--sig-icon-warn vs --sig-icon-error), not the glyph.
2026-07-02 23:00:08 +02:00
Jonas Jenwald
12691fdf50 Remove unnecessary class-field resetting in SignaturePropertiesManager.prototype.setDocument (PR 21247 follow-up)
This corresponds to the initial values of these fields, and they were *already* reset when a (previous) PDF document was closed.
2026-07-02 19:44:35 +02:00
Jonas Jenwald
a1f1a56080 [GeckoView] Add web-digital_signature_properties_manager import map (PR 21247 follow-up)
Currently the GeckoView development viewer, i.e. http://localhost:8888/web/viewer-geckoview.html, is completely broken with the following error:
```
Uncaught TypeError: The specifier “web-digital_signature_properties_manager” was a bare specifier, but was not remapped to anything. Relative module specifiers must start with “./”, “../” or “/”. app.js:97:44
```
2026-07-02 19:44:28 +02:00
Jonas Jenwald
fa207b4ce8 A couple of SignaturePropertiesManager improvements (PR 21247 follow-up)
- Replace the `loadFromDocument` and `reset` methods with a single `setDocument` method, since that's consistent with many other viewer components.

 - Replace the internal `#loadToken` field with simple `pdfDocument` checks, when checking if the document is still current, which again is consistent with (all) other viewer components.

 - Remove a couple of comments, which didn't add a lot of value and sounded a whole lot like "AI speak".
2026-07-02 14:07:04 +02:00
Nicolò Ribaudo
ea43bb43fb
Avoid text selection workaround in modern Chromium
Chromium 148+ improved their selection behavior when it comes to absolutely
positioned elements, thus making text selectino in PDF.js much better.

Unfortunately this does not only mean that the workaround we currently have
for Chromium is unnecessary, but it actually become harmful. It conflicts
with Chromium's new behavior, making text selection *worse* on mobile.

As the change has been released in Chrome only a month ago, this patch keeps
the workaround for older Chromium versions. There is no easy way to
feture-detect is, so unfortunately we need to do user agent version detection.
2026-07-01 13:14:34 +02: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
d142fd2451 Remove the BOM from html files (bug 2051221)
Add add a linter in order to avoid future regressions.
2026-06-29 11:20:34 +02:00
Jonas Jenwald
b7b3a4c454 Use more optional chaining in the src/ and web/ folders
There's a few spots where we check if something is either undefined or if its length is zero, which can be simplified by instead using optional chaining.
2026-06-27 12:20:36 +02:00
Tim van der Meij
195226e3a6
Merge pull request #21500 from calixteman/bug2050191
Disable selection rendering when backdrop-filter is unsupported (bug 2050191)
2026-06-26 20:12:48 +02:00
Nicolò Ribaudo
5d81fe5098
Move SVG text selection styles to pdf_viewer.css
draw_layer_builder.css, which originally included these styles, is not
loaded in GECKOVIEW. This is because it also includes all the styles
related to highlights and drawing, which are only supported in the main
viewer.

The new SVG-based highlights are also used in GECKOVIEW, so even though
the JS logic for them lives in the DrawLayer builder, we need to move the CSS
somewhere where we know it's going to be loaded.
2026-06-25 15:55:26 +02:00
Calixte Denizet
7f9c54a259 Disable selection rendering when backdrop-filter is unsupported (bug 2050191)
Selection rendering relies on the CSS backdrop-filter property, so it must
be gated on browser support for it.
2026-06-24 20:16:44 +02:00
Calixte Denizet
d8ea2afe47 Add support for Screen annotations playing embedded media
Screen annotations whose rendition action resolves to an embedded audio/video
file now play through the same play-button overlay as RichMedia.
Factor the shared resolution logic into a MediaAnnotation base (used by both RichMedia and Screen).

It fixes #6078 and #2787.
2026-06-23 20:48:35 +02:00
Calixte Denizet
d537f5ba4b
Add support for RichMedia annotations
Render `/Subtype /RichMedia` annotations so embedded video and audio can
be played in the viewer.

The core layer parses the `RichMediaContent` dictionary to locate the
primary playable asset and its MIME type. The display layer overlays a
play button on the annotation's poster; clicking it swaps in a
`<video>`/`<audio>` element backed by a `blob:` URL. Presentation mode
lets events reach the media controls instead of advancing the page.

It fixes #2787.
2026-06-22 21:27:52 +02:00
Jonas Jenwald
a911ce22e5 Stop event propagation, for the Enter key, in the passwordPrompt input
**Steps to reproduce:**
 1. Open the viewer.
 2. Show the sidebar, and switch to the "Pages" view if necessary.
 3. Click on the "Add file" button.
 4. Choose a password-protected PDF, e.g. the `issue6010_1.pdf` file, via the "File Upload" dialog opened by the browser.
 5. Enter the password, i.e. `abc`, and press the <kbd>Enter</kbd> key.

**Expected result:**
That the new PDF document is merged into the existing one, without UI side-effects.

**Actual result:**
Merging works, *however* the "File Upload" dialog is re-opened.

---

It seems that when the passwordPrompt dialog closes, the <kbd>Enter</kbd> key press (from the input) is forwarded to the previously focused element which naturally is the "Add file" button.

*Note:* This doesn't seem (easily) possible to test, since the integration-tests directly populate the `viewsManagerAddFilePicker` and doesn't actually "click" on the `viewsManagerAddFileButton` first.
2026-06-21 15:30:05 +02:00
Calixte Denizet
ece1e2ed0c Add a 'supportsDownloading' browser option to gate saving/downloading
Introduces a 'supportsDownloading' browser option (defaulting to false)
that lets embedders disable the save/download paths entirely. When
disabled:
  - the toolbar and secondary-toolbar download buttons are hidden;
  - PDFViewerApplication.{download,save,downloadOrSave} and the
    "beforeunload" save prompt bail out early;
  - the BaseDownloadManager helpers (download, downloadData,
    openOrDownloadData) and the Firefox/generic _triggerDownload
    implementations no-op.
2026-06-18 14:51:32 +02:00
Jonas Jenwald
cbefb334fd Check every LinkAnnotation when testing if inferred links overlap (issue 21458)
Currently we only check LinkAnnotations with URLs, but completely ignore e.g. internal destinations, named actions, attachments, SetOCGState actions, JS actions, and ResetForm actions when testing if inferred links overlap any existing annotation.
This seems conceptually wrong, since it may easily break intended functionality by overlaying the *correct* DOM element with an inferred link (as was the case in issue 21458).
2026-06-16 21:35:44 +02:00
Jonas Jenwald
2dc73ad2a7 Collect coverage data from all workers when closing integration-tests
The "Merge PDF" integration-tests will (indirectly) invoke `PDFViewerApplication.open` as part of loading the new PDF document, which will end up creating a new `PDFWorker` instance.
Currently worker coverage is only collected at the end of each integration-test, which means that in these cases we miss the coverage data from any "previous" workers.
2026-06-14 13:27:06 +02:00
Jonas Jenwald
ffa7ac7a91 Use Map.prototype.getOrInsertComputed() more in the code-base 2026-06-12 23:21:16 +02:00
Calixte Denizet
069b757998 Use the checkboxes and radio button appearances as defined in the pdf to render them in the annotation layer (bug 1802506)
The idea is to generate two operator lists for the Yes/Off states and render them on a separate canvas.
These canvases are then attached the annotation and we modify their display depending on the input state.

It fixes #18021.
2026-06-12 20:10:56 +02:00
calixteman
ce08a803c4
Merge pull request #21416 from calixteman/drop-css-unsafe-inline
Drop 'unsafe-inline' from the CSP style-src directives
2026-06-09 23:16:38 +02:00
calixteman
a13f2aa793
Merge pull request #21413 from calixteman/improve_comb
Improve rendering of comb text fields
2026-06-09 23:10:49 +02:00
Calixte Denizet
fe5eb0f779
Improve rendering of comb text fields
Center each glyph within its comb cell instead of left-aligning it,
both in the HTML annotation layer and in the printed/saved appearance,
to match Acrobat. Cell width is now the single source of truth via the
--comb-width CSS variable, and field text-alignment (center/right) is
applied as a whole-cell --comb-offset that stays in sync on input,
blur, resetform and updatefromsandbox. The field no longer grows on
focus; trailing letter-spacing is clipped and cell dividers are drawn
on focus.
2026-06-09 22:15:40 +02:00