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.
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.
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).
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.
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.
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
```
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 ""
instead of "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.
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.
- 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".
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.
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.