7974 Commits

Author SHA1 Message Date
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
Tim van der Meij
5b100c4509
Merge pull request #21525 from calixteman/20504_skia_followup
Apply the appearance-stream scale factor when text is shown, not on setFont
2026-07-03 20:17:53 +02:00
calixteman
0cc1718b02
Merge pull request #21527 from Snuffleupagus/issue-21523
Add basic support for non-embedded TrebuchetMS fonts (issue 21523)
2026-07-03 10:21:11 +02:00
calixteman
d5dafc3fb3
Merge pull request #21522 from spokodev/w32/pdfjs-escapepdfname
Fix escapePDFName producing malformed name escapes for control characters
2026-07-02 18:11:21 +02:00
Jonas Jenwald
15969fbe19 Add basic support for non-embedded TrebuchetMS fonts (issue 21523) 2026-07-02 15:13:01 +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
Calixte Denizet
d9999dcedd Apply the appearance-stream scale factor when text is shown, not on setFont
The font size (Tf) and the text matrix (Tm) can appear in any order in an
appearance stream. Applying the scale factor eagerly in setFont missed the
case where Tf precedes Tm (e.g. Skia-generated FreeText), yielding a wrong
guessed font size.
2026-07-02 14:51:10 +02: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
calixteman
89836b76f0 Take into account the current transform when getting font size for FreeText
Fixes issue #20504.

And the text position in Arabic FreeText annotations.
2026-07-02 11:04: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
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
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
8bdd159699
Merge pull request #21505 from Snuffleupagus/StructTreeRoot-rm-init
Inline the `init` method in the `StructTreeRoot` constructor
2026-06-26 20:14:46 +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
Tim van der Meij
d8526132f5
Merge pull request #21487 from calixteman/issue17333
Render non-empty glyph 0 for char code 0
2026-06-26 20:08:51 +02:00
Jonas Jenwald
82324408cd Inline the init method in the StructTreeRoot constructor
Currently the constructor only set various class fields and the class instance thus needs to be "manually" initialized, which seems unnecessary.
Given how short/simple the `init` and `readRoleMap` methods are we can just inline their code in the constructor, thus simplifying the code overall.
2026-06-26 14:19:35 +02:00
Jonas Jenwald
10844326c7
Merge pull request #21497 from Snuffleupagus/substring-tweaks
Tweak some `String.prototype.substring()` usage
2026-06-24 20:32:34 +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
Jonas Jenwald
6718c2924c Tweak some String.prototype.substring() usage
In a few spots the `indexEnd` parameter is explicitly set to the string-length, which is unnecessary since that's the default value if the parameter is omitted; note https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring#description

In the `XMLParserBase.prototype._resolveEntities` method the `substring` usage can be replaced with an updated (and cached) regular expression that directly finds numbers.
2026-06-24 18:52:46 +02:00
Jonas Jenwald
44e637a064 Remove explicit xref usage in the ScreenAnnotation.prototype.#renditionActions method
Rather than fetching "raw" dictionary-data and then manually resolving any references, we can simply use `Dict.prototype.get` and `Dict`-iteration to access the needed data *directly* instead.
2026-06-24 10:46:07 +02:00
Jonas Jenwald
15d93e1f34 Introduce a helper method, in the Annotation class, for determining the attachment fileId
This avoids duplication between the `FileAttachmentAnnotation` and `MediaAnnotation` classes, since they currently include essentially the same code for determining the attachment `fileId`.
2026-06-24 10:45:52 +02:00
Jonas Jenwald
8a2c112c20 Simplify the Annotation.prototype.setAppearance method a tiny bit
It's not necessary to check if the /AS entry exists first, and it can just be fetched directly, since in that case the existing "is stream"-check won't be true anyway.

Also, move the `appearance` field definition to the top of the class instead.
2026-06-24 10:42:38 +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
calixteman
078b96229d
Render non-empty glyph 0 for char code 0
It fixes #17333.
2026-06-23 21:38:57 +02:00
calixteman
e6539f6516
Merge pull request #21490 from calixteman/screen_rendition
Add support for Screen annotations playing embedded media
2026-06-23 21:34:30 +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
Tim van der Meij
4117b75a10
Merge pull request #21486 from Snuffleupagus/getTextContent-sink-fixes
Improve the `sink` handling in `getTextContent` for Highlight annotations (PR 20019 follow-up)
2026-06-23 20:02:34 +02:00
Jonas Jenwald
813d1949ba
Merge pull request #21491 from Snuffleupagus/readCmapTable-sort-last
Sort the mappings *last* in the `readCmapTable` function (PR 19321 follow-up)
2026-06-23 16:01:09 +02:00
Jonas Jenwald
9ca13c9a23 Sort the mappings *last* in the readCmapTable function (PR 19321 follow-up)
This improves performance of `issue19319.pdf` even more, and locally the rendering time of the second page goes from ~300 ms to ~250 ms, since we avoid sorting a bunch of duplicate entries.
2026-06-23 13:51:37 +02:00
Jonas Jenwald
09c9f7f2fe Remove the AnnotationEditorUIManager and IdManager test-only reset methods (PR 19809 follow-up)
These test-only methods became unused in PR 19809.
2026-06-23 12:09:12 +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
Tim van der Meij
b6469341c1
Merge pull request #21485 from calixteman/bug2046659
Use AES256 for V=5 documents with a mislabeled AESV2 crypt filter (bug 2046659)
2026-06-22 20:44:48 +02:00
Tim van der Meij
7ac6dff4b7
Merge pull request #21483 from calixteman/issue21430
Reset alpha before drawing a colored glyph in type 3 font
2026-06-22 20:40:55 +02:00
Jonas Jenwald
22871eef23 Improve the sink handling in getTextContent for Highlight annotations (PR 20019 follow-up)
Currently there's a couple of issues related to the `sink` handling:
 - The `Page.prototype.extractTextContent` method is invoked with options that it doesn't actually use; note 1ddf6449ac/src/core/document.js (L669-L676)

 - When parsing "nested" textContent, i.e. /Form /XObjects, we end up wrongly treating repeated /XObjects as empty for the annotations use-case since `enqueue` is never invoked; note 1ddf6449ac/src/core/evaluator.js (L3439) and 1ddf6449ac/src/core/evaluator.js (L3449-L3451)

 - The `getTextContent` method might become ever so slightly slower by having to defer parsing at every step, given the "bad" fallback value when comparing with the `TEXT_CONTENT_CHUNK_SIZE` constant (in the API), note 1ddf6449ac/src/display/api.js (L1705) and 1ddf6449ac/src/core/evaluator.js (L3566)

 - Having the `sink` now be effectively optional, in the `getTextContent` method, does complicate the code slightly overall.

To address these things this patch ensures that a `sink` will always be available, by re-using the `sinkWrapper` structure from the "nested" textContent case, and with reasonable default values.
2026-06-22 14:56:17 +02:00
Calixte Denizet
7f7e63333d Use AES256 for V=5 documents with a mislabeled AESV2 crypt filter (bug 2046659)
Some producers wrongly set the crypt filter CFM to AESV2 for V=5 documents;
per the spec these must be decrypted with AES256 using the file encryption key directly.
2026-06-22 14:54:24 +02:00
calixteman
1ddf6449ac
Merge pull request #21478 from calixteman/comb-field-vertical-centering
Vertically center the glyphs in comb text fields
2026-06-22 09:57:55 +02:00
calixteman
623e6d9476
Reset alpha before drawing a colored glyph in type 3 font
It fixes #21430.
2026-06-21 23:06:43 +02:00
Jonas Jenwald
9c9b465fd2 A couple of small tweaks of the StructElementNode.prototype.mathML getter
- Use `FileSpec.pickPlatformItem` when getting the fileStream, to ensure that /EF-entries are handled in a consistent way across the code-base.

 - Combine a couple of the data-validation steps, to reduce a tiny bit of duplication. Also, use the `isDict` helper a little more.

 - Finally, avoid using a temporary variable when returning data in the `Page.prototype.getStructTree` method.
2026-06-21 22:47:13 +02:00
Tim van der Meij
8ebc2382e3
Merge pull request #21479 from Snuffleupagus/Annotation-#setOptionalContent-MissingDataException
Don't swallow `MissingDataException`s in the `Annotation.prototype.#setOptionalContent` method (PR 21313 follow-up)
2026-06-21 19:11:54 +02:00
Tim van der Meij
38daede697
Merge pull request #21481 from Snuffleupagus/metadata-isDict
Use the `isDict` helper in the `Catalog.prototype.metadata` getter
2026-06-21 19:10:54 +02:00
Tim van der Meij
86b901fcde
Merge pull request #21470 from Snuffleupagus/AnnotationEditorUIManager-rm-isSelected
Remove the unused `AnnotationEditorUIManager.prototype.isSelected` method
2026-06-21 19:09:32 +02:00
Jonas Jenwald
a46ee2b647 Use the isDict helper in the Catalog.prototype.metadata getter 2026-06-21 12:26:21 +02:00
Jonas Jenwald
bd6541864b Don't swallow MissingDataExceptions in the Annotation.prototype.#setOptionalContent method (PR 21313 follow-up)
Unless the entire document has been loaded, the dictionary lookups in `parseMarkedContentProps` may throw `MissingDataException`s and in that case we need to re-parse the current Annotation rather than ignoring the optionalContent.
2026-06-21 09:13:33 +02:00
Calixte Denizet
34516bcec3 Vertically center the glyphs in comb text fields 2026-06-20 18:47:24 +02:00
Jonas Jenwald
00e1aabe93 Remove unnecessary explicit return statements in CanvasGraphics.prototype.showText 2026-06-19 10:58:14 +02:00
Jonas Jenwald
786019eb0d Remove the unused AnnotationEditorUIManager.prototype.isSelected method
According to the coverage data this method is unused, see e20c810dd4/blob/src/display/editor/tools.js (L2552), and searching through the entire code-base reveals no call-site invoking an `isSelected` method.
2026-06-18 23:21:53 +02:00
calixteman
e20c810dd4
Merge pull request #21469 from calixteman/issue21466
Avoid too long BlueScale value when rewriting a CFF font
2026-06-18 21:43:05 +02:00
calixteman
07d4c1018a
Avoid too long BlueScale value when rewriting a CFF font
It fixes #21466.
2026-06-18 20:48:13 +02:00
Jonas Jenwald
b4b0a3fa04 Remove the unused ImageData branch in the putBinaryImageData function
This branch isn't covered by any tests, and looking at the two existing call-sites we only ever pass in a `CanvasRenderingContext2D` interface to this function.
Based on the git history this branch was added in PR 3312, however as far as I can tell it doesn't actually appear to have been necessary even back then!?
2026-06-18 18:22:55 +02:00
Jonas Jenwald
a443a635a1 Remove the unused HTMLElement branch in the paintInlineImageXObject method
This branch isn't covered by any tests, and as far as I can tell it's been unused ever since PR 11601 which simplified the JPEG image handling.
Prior to that we'd create an `Image` instance in one case, see [this code](https://github.com/mozilla/pdf.js/pull/11601/changes#diff-082d6b37ad01db7ac97cc07c6ddb0dc52040484c5ef91b110b072f50144d9f39L2312-L2314), which is why that branch was necessary since `new Image()` creates a `HTMLImageElement` instance which in itself is an instance of `HTMLElement`; note [this](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image) respectively [this](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement).
2026-06-18 17:47:26 +02:00