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.
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.
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.
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.
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.
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.
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.
This avoids duplication between the `FileAttachmentAnnotation` and `MediaAnnotation` classes, since they currently include essentially the same code for determining the attachment `fileId`.
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.
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.
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.
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.
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.
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.
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.
- 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.
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.
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.
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!?
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.