4743 Commits

Author SHA1 Message Date
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
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
2ed018ec2d
Merge pull request #21460 from Snuffleupagus/autolinking-check-every-LinkAnnotation
Check every LinkAnnotation when testing if inferred links overlap (issue 21458)
2026-06-16 22:32:07 +02:00
calixteman
eae42379f2
Merge pull request #21462 from calixteman/bluescale-small-zones
Don't clamp BlueScale up when a font genuinely has small zones
2026-06-16 21:52:25 +02:00
calixteman
d28030f838
Merge pull request #21463 from calixteman/fix_unit_test
Adjust the 'BaseException' unit-test for the 'Error.stack' changes in Firefox
2026-06-16 21:43:49 +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
Calixte Denizet
5432642250 Adjust the 'BaseException' unit-test for the 'Error.stack' changes in Firefox
Firefox 154 no longer walks the prototype chain in the `Error.stack`
getter, so `BaseException`-derived instances return an empty string
rather than the prototype `Error`'s stack (see bug 1946559).
2026-06-16 21:30:41 +02:00
calixteman
bc99fc0678
Don't clamp BlueScale up when a font genuinely has small zones
The lower BlueScale clamp from #21343 guarded foundry fonts via
`blueScale < DEFAULT_BLUE_SCALE`, but that lets a near-default value
(e.g. 0.037) with small zones get raised to `0.5 / maxZoneHeight`. On
macOS' Core Text rasterizer this collapses the overshooting glyphs, so
most text disappears (not reproducible on Linux/Windows).
2026-06-16 19:34:48 +02:00
Calixte Denizet
082ad21387 Draw non-isolated blend-mode groups against their backdrop (bug 1873345)
A non-isolated transparency group must blend with its backdrop, but a group
containing a blend mode was forced onto a transparent intermediate canvas;
e.g. a /Multiply highlight then painted opaquely over the text behind it,
 making that text invisible.
2026-06-16 15:09:39 +02:00
Calixte Denizet
2550b91be9 Resolve checkbox/radio export values from the 'Opt' entry
For checkbox and radio button fields, the export value can differ from the
appearance-state name: the field's inheritable `Opt` array holds the real
export values (used for non-Latin text, or values shared between buttons).
We previously exposed the appearance-state name as the export value.
2026-06-15 18:23:26 +02:00
Tim van der Meij
0ea67ed96f
Upgrade eslint-plugin-unicorn to version 66.0.0
This is a major version bump, but the changelog at
https://github.com/sindresorhus/eslint-plugin-unicorn/releases/tag/v66.0.0
doesn't indicate any breaking changes that should impact us.

However, improved rules do require a small number of changes here:

- The `prefer-array-some` rule no longer reports a false positive after
  https://github.com/sindresorhus/eslint-plugin-unicorn/issues/3198 got
  fixed, so the ignore line that was added in commit 68a5ec1 is removed.

- The `prefer-ternary` rule triggers on more cases now, in particular
  `let` declarations with `if` reassignments, so a number of changes are
  made to make it pass again.

- The `prefer-at` rule triggers on more cases now, in particular
  `substring` calls that just extract a single character, so one change
  is made to make it pass again.
2026-06-14 20:20:34 +02:00
Tim van der Meij
26b4206d87
Configure Puppeteeer to not download Chrome/Firefox by default
We currently download Chrome/Firefox immediately on `npm install`
invocations because Puppeteer's postinstall script does that by default.
However, this is wasteful if the user/workflow doesn't actually need to
run Puppeteer or its browsers, for example in GitHub Actions workflows
that do linting, static analysis or other tasks like updating locales or
publishing artifacts.

This commit therefore makes sure no browser binaries get pulled in by
default anymore, and defers doing that until it's actually necessary,
which is when we want to start the browsers in the `startBrowsers`
function of `test.mjs`.

Locally this brings the `npm install` runtime down from 8.998 to 1.800
seconds, and as a bonus it results in better log output too because it
now shows which browser versions were used in the run (whereas
previously with `npm install` this information was not sent to stdout).
2026-06-14 17:15:47 +02:00
Tim van der Meij
8560125056
Merge pull request #21448 from timvandermeij/comment-intermittent
Fix intermittent failure in the `must check that the comment sidebar is resizable` comment integration test
2026-06-14 16:35:20 +02:00
Tim van der Meij
ed1b2f91be
Merge pull request #21440 from Snuffleupagus/putBinaryImageData-convertRGBToRGBA
Use the `convertRGBToRGBA` helper with RGB images in `putBinaryImageData`
2026-06-14 14:20:11 +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
feec28583d Add an integration-test for merging a password-protected PDF
Looking at the coverage data the password-handling part of the merge functionality wasn't being tested; see e75a7cfd62/blob/src/core/worker.js (L652)
2026-06-14 13:17:33 +02:00
Jonas Jenwald
e1c930adfe Add an integration-test for merging a corrupt PDF
Currently when opening a PDF document the following code is used, where `checkFirstPage`/`checkLastPage` helps detect XRef corruption; note 86a18bd5fe/src/core/worker.js (L167-L176)

However when merging a PDF into an existing document the parsing is only "partial"; note 86a18bd5fe/src/core/worker.js (L632-L634)

It seems a little strange to not support corrupt PDFs in a consistent manner in the code-base, hence this patch adds a new `BasePdfManager` helper that handles all the relevant parsing/checking and re-uses that when merging PDFs.
2026-06-14 09:49:23 +02:00
Tim van der Meij
d305b542df
Fix intermittent failure in the must check that the comment sidebar is resizable comment integration test
We use the generic `page.mouse.move(x, y, { steps }` API, but that purely
performs the mouse move steps without having knowledge about if/how the
application handles any events caused by it, so it doesn't wait for the
sidebar to render before moving on. This causes intermittent failures if
the sidebar didn't get enough time to render before the next mouse move
is initiated (which can happen in slower environments).

This commit fixes the issue by doing the mouse move steps ourselves and
by waiting for a browser trip between each of them to make sure that the
sidebar got a chance to render.

Fixes #21447.
Relates to #21044 / #21045 / 24e5377.
2026-06-13 21:32:00 +02:00
Jonas Jenwald
55c8516944 Use the convertRGBToRGBA helper with RGB images in putBinaryImageData
This removes a little bit of code duplication, which only exist since the `src/display/canvas.js` code pre-dates the helper function by many years.

Note: Given that `OffscreenCanvas` is enabled by default there's currently not a lot of test coverage for this code-path, hence the added browser-test.
2026-06-13 13:14:50 +02:00
calixteman
35d275d3b1
Merge pull request #18907 from calixteman/bug1802506
Use the checkboxes and radio button appearances as defined in the pdf to render them in the annotation layer (bug 1802506)
2026-06-12 22:04:29 +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
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
d1926fb179 Use the convertBlackAndWhiteToRGBA helper with grayscale images in putBinaryImageData
This removes a little bit of code duplication, which only exist since the `src/display/canvas.js` code pre-dates the helper function by many years.

*Note:* Given that `OffscreenCanvas` is enabled by default there's currently not a lot of test coverage for this code-path, hence the added browser-test.
2026-06-10 18:31:07 +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
Calixte Denizet
5ca6026d80
Drop 'unsafe-inline' from the CSP style-src directives
The print service injected the per-PDF `@page { size }` rule as an inline
<style> element, which required 'unsafe-inline' on style-src-elem.

Inject it through a constructable CSSStyleSheet attached to
document.adoptedStyleSheets instead. Constructable stylesheets aren't
subject to style-src's inline restrictions in browsers.
2026-06-09 22:08:08 +02:00
Tim van der Meij
c541d24ac3
Merge pull request #21407 from calixteman/fix_hidden_updated_field
Fix form fields with their own canvas updated on non-rendered pages
2026-06-09 20:03:20 +02:00
Tim van der Meij
8a80f1b8b7
Merge pull request #21418 from Snuffleupagus/getAttachments-Map
[api-minor] Convert `getAttachments` to return data in a `Map`
2026-06-09 19:42:23 +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
Calixte Denizet
473b53fe3c Handle TR2 with /Default entry
It fixes #21406.
2026-06-08 19:09:45 +02:00
Calixte Denizet
ecd43bc8e1 Fix form fields with their own canvas updated on non-rendered pages
When a read-only field (which has its own canvas) is updated by the
sandbox while its page isn't rendered, showElementAndHideCanvas
isn't called, so once the page is finally rendered the field still
shows its outdated canvas instead of the new value.

Replace the imperative canvas/element toggling with a `sandboxModified`
class, set from the annotation storage both at render time and on
sandbox updates, and let the CSS show the element and hide the canvas.
2026-06-08 17:22:11 +02:00
Tim van der Meij
f12c463452
Merge pull request #21393 from Snuffleupagus/PDFCursorTools-tests
Add basic integration-tests for the `PDFCursorTools` functionality
2026-06-06 19:51:52 +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
Tim van der Meij
f4d6b4ef85
Merge pull request #21391 from Snuffleupagus/getDocument-Node-fs-unit-test
Add a unit-test for passing a filesystem URL-string (in Node.js) to `getDocument`
2026-06-06 19:45:26 +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
ae30748956 Add basic integration-tests for the PDFCursorTools functionality 2026-06-06 14:32:15 +02:00
Jonas Jenwald
08b704d4b1 Add one more unit-test case for invalid email domains in the Autolinker class
This improves coverage for a branch of the `Autolinker` class that wasn't previously tested.
2026-06-06 11:57:22 +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
9c437e6ab4
Merge pull request #21388 from calixteman/strip_jbig2_header
Strip the JBIG2 file header from JBIG2Decode streams
2026-06-05 20:06:02 +02:00
calixteman
173e083c71
Merge pull request #21350 from calixteman/kb_shortcuts_l10n
Match editor keyboard shortcuts by event.code as a fallback
2026-06-05 17:19:17 +02:00
Calixte Denizet
88c52a1523 Strip the JBIG2 file header from JBIG2Decode streams
It's rendering correctly in Acrobat and PdfBox.
2026-06-05 16:31:44 +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
Tim van der Meij
7f15bd6591
Merge pull request #21383 from calixteman/ko_inner_bd
Add knockout_inner_backdrop ref test
2026-06-04 20:41:50 +02:00
Jonas Jenwald
dc602ae543 Extend the AppOptions unit-tests to also cover the EVENT_DISPATCH option-kind 2026-06-04 17:51:41 +02:00
Calixte Denizet
e4a3e91444 Add knockout_inner_backdrop ref test
Non-isolated subgroup needing isolation (Multiply BM) nested in a KO
group, exercising the inner-backdrop blend path.
2026-06-04 09:13:43 +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
836a08084e Match editor keyboard shortcuts by event.code as a fallback
So that Ctrl+A, Ctrl+Z, etc. still fire on non-US keyboard layouts where
the physical "A" key produces a non-Latin character (Cyrillic, Greek,
some AZERTY combinations, ...). KeyboardManager now tries event.key first
and falls back to a US-layout translation of event.code (KeyA => a,
Digit1 => 1, Numpad1 => 1) when no shortcut is bound on event.key.

Also refactors KeyboardManager to store modifiers as a bitmask instead
of a serialized string, and treats a shortcut array without any
"mac+"-prefixed entry as applying on all platforms, letting us drop the
redundant "mac+X" duplicates of bare "X" entries across the editor code.
2026-06-03 10:13:41 +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