3893 Commits

Author SHA1 Message Date
Tim van der Meij
7a0e2e7203
Merge pull request #21717 from calixteman/fix/pdf-editor-image-only-metadata
Handle image-only PDF exports
2026-08-06 22:10:00 +02:00
Tim van der Meij
f43ce86470
Merge pull request #21719 from Snuffleupagus/loadType3Data-async
Convert `TranslatedFont.prototype.loadType3Data` to an asynchronous method
2026-08-06 21:52:45 +02:00
Jonas Jenwald
74fe316f31 Convert TranslatedFont.prototype.loadType3Data to an asynchronous method
The Type3 glyphs are parsed in series, which was implemented by chaining the `getOperatorList` promises together one after another.
Thanks to modern JavaScript this can be simplified a little bit, since we can just `await` within the loop instead.
2026-08-05 23:01:28 +02:00
Jonas Jenwald
71c5839b03 Use the MathClamp helper in the src/core/annotation.js file 2026-08-05 15:22:15 +02:00
Calixte Denizet
e2df5f4d18 Handle image-only PDF exports 2026-08-05 12:52:43 +02:00
Tim van der Meij
5f181fd8b0
Merge pull request #21707 from calixteman/fix/pdf-editor-copy-new-annotations
Give copied annotations distinct references
2026-08-04 21:30:19 +02:00
Tim van der Meij
8e3a1fd4ad
Merge pull request #21699 from calixteman/fix/pdf-editor-field-parent-cycle
Avoid an infinite loop on cyclic field Parent chains
2026-08-04 20:58:25 +02:00
calixteman
16f5691df7
Remove the ambiguity from the PostScript number regex
`\d+\.?\d*` can split a run of digits in as many ways as it is long, so
it would backtrack polynomially if anything following it could reject.
The optional exponent can't, hence no bug today, but `\d+(?:\.\d*)?`
accepts the same numbers unambiguously.
2026-08-04 18:48:25 +02:00
Calixte Denizet
bf7c9258c9 Give copied annotations distinct references
When a viewer page was copied, each copy got its own annotationStorage
entry, but newAnnotationsByPage was keyed only by source page. As a
result, every output copy received all entries and reused their memoized
references.

Tag each entry with its rank among output copies of the same source page.
The display and worker compute this rank independently; inserted documents
preserve the order of copies. Keep unextracted entries at rank -1 so shared
stamp bitmaps remain available without being written. Without ranks, new
annotations are applied only to the first copy.
2026-08-04 17:32:43 +02:00
calixteman
a7a99fdbd6
Avoid an infinite loop on cyclic field Parent chains
When an AcroForm has no Fields entry, #fixFields rebuilds it by walking
each widget's Parent chain up to its root field. A chain looping back on
itself made that walk spin forever and hung the worker.
2026-08-04 10:19:58 +02:00
calixteman
f21fe34747
Safely serialize CSS font family names 2026-08-03 18:02:10 +02:00
calixteman
ba7bf7b26c
Merge pull request #21683 from calixteman/fix/quad-regex-writer
Don't write numbers in exponential notation when saving a pdf
2026-08-03 17:49:23 +02:00
calixteman
1da36fb6bf
Merge pull request #21686 from calixteman/fix/quad-regex-xfa-path
Anchor the regex used to extract the XFA path positions
2026-08-03 17:46:24 +02:00
calixteman
92d027eaeb
Anchor the regex used to extract the XFA path positions
Matching the name with a leading `.+` is quadratic in the length of
a component which doesn't end with a position, and every AcroForm
field name goes through this.
2026-08-03 17:07:48 +02:00
calixteman
5375bff642
Don't write numbers in exponential notation when saving a pdf
`toFixed(10)` switches to the exponential notation from 1e21 on, which isn't
valid PDF syntax, and removing the trailing zeros then dropped a digit of the
exponent: 1e30 was written "1e+3" and 1e100 "1e+1". Such a number, necessarily
an integer, is now written with all its digits.

The trailing zeros are removed with a backward scan, since `toFixed(10)` always
produces exactly 10 decimals. Below the 1e21 limit its output is at most 33
characters long, so the previous `$`-anchored regex wasn't a performance issue.
2026-08-03 16:59:12 +02:00
Tim van der Meij
ae976b924b
Merge pull request #21671 from Snuffleupagus/getFieldObjects-Map
[api-minor] Convert `getFieldObjects` to return data in a Map
2026-08-02 22:37:22 +02:00
Jonas Jenwald
82624a5e50 [api-minor] Convert getFieldObjects 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.

In the Firefox PDF Viewer sending Maps to the scripting-implementation should be fine, since it uses the browser `Cu.cloneInto` functionality; see https://searchfox.org/firefox-main/source/toolkit/components/pdfjs/content/PdfSandbox.sys.mjs
However with QuickJS, used by the GENERIC viewer, all data needs to be stringified and Maps are converted into regular Objects (see also PR 21664). Hence the `objects` property, in the scripting-implementation, is converted back into a Map using the (renamed) `createMap` helper function.
2026-08-02 21:27:07 +02:00
calixteman
f7f30dd844
Exclude "&" from the XML entity names
Scanning to the end of the string for every "&" made the entity
resolution quadratic. Stopping at the next "&" also fixes a bare
ampersand swallowing the reference which follows it.
2026-08-02 18:59:19 +02:00
Tim van der Meij
f73978083d
Merge pull request #21680 from calixteman/fix/quad-regex
Fix the regex used to normalize css fonts in XFA
2026-08-02 12:43:14 +02:00
calixteman
cec8d2eed6
Don't throw on an invalid XML character reference
`String.fromCodePoint` throws on anything which isn't a code point,
so e.g. "&#xZZ;" or "�" aborted the whole parsing. Such a
reference is now kept as-is, like an unknown named entity.
2026-08-01 16:24:03 +02:00
calixteman
491792f0e2
Fix the regex used to normalize css fonts in XFA
The regex was quadratic in the number of consecutive spaces,
which caused performance issues when normalizing fonts with
a large number of spaces.
2026-08-01 15:11:43 +02:00
Jonas Jenwald
ee59db5018 Replace simple return if statements with ternary operators
In a couple of cases, where a boolean is returned, it's also possible to use an OR operator rather a ternary.

*Note:* This patch reduces the size of the `gulp mozcentral` bundle by `960` bytes.
2026-07-31 12:24:08 +02:00
Jonas Jenwald
ce4ff55faa
Merge pull request #21664 from Snuffleupagus/getJSActions-api
[api-minor] Convert `getJSActions` to return data in a Map
2026-07-31 11:29:21 +02:00
Tim van der Meij
0163438e1a
Merge pull request #21660 from calixteman/fix/pdf-editor-preserve-widget-parent
Avoid mutating source widget parents
2026-07-30 21:02:29 +02:00
Tim van der Meij
f70f55d743
Merge pull request #21658 from calixteman/fix/pdf-editor-clone-reference-race
Avoid duplicate shared object clones
2026-07-30 20:52:35 +02:00
Jonas Jenwald
803c9d7d21 [api-minor] Convert getJSActions 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.

Note also how in the scripting-implementation the `actions` were already converted into a Map, via the `createActionsMap` helper.
In the Firefox PDF Viewer sending `Map`s to the scripting-implementation should be fine, since it uses the browser `Cu.cloneInto` functionality; see https://searchfox.org/firefox-main/source/toolkit/components/pdfjs/content/PdfSandbox.sys.mjs
However with QuickJS, used by the GENERIC viewer, all data needs to be stringified and unfortunately `JSON.stringify()` doesn't support Maps. Hence we convert Maps to Objects, via a [`replacer` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#replacer), since the existing `createActionsMap` usage will convert the actions-Objects back to Maps.
2026-07-30 16:04:58 +02:00
Jonas Jenwald
1813ab0774 Use more more optional chaining in the src/ folder 2026-07-29 18:28:41 +02:00
Calixte Denizet
aa812b531a Avoid mutating source widget parents 2026-07-29 16:03:15 +02:00
Calixte Denizet
3a19a20d50 Avoid duplicate shared object clones 2026-07-28 22:39:35 +02:00
Tim van der Meij
0365cbde02
Merge pull request #21654 from calixteman/fix/cycles
Avoid cycles when walking some trees
2026-07-28 21:34:49 +02:00
Tim van der Meij
f704f2ef02
Merge pull request #21652 from Snuffleupagus/signatures-async-helpers
Update the signatures-helpers to actually handle `MissingDataException`s
2026-07-28 21:34:14 +02:00
Tim van der Meij
01ba4c476d
Merge pull request #21646 from calixteman/update/pdf.js.qcms
Update qcms wrapper
2026-07-28 20:25:15 +02:00
Calixte Denizet
ac51b29777 Avoid cycles when walking some trees 2026-07-28 19:51:34 +02:00
Jonas Jenwald
8d1afad39b Shorten the Catalog.prototype.jsActions getter, and related code, a tiny bit
This is possible thanks to modern language features.
2026-07-28 19:01:47 +02:00
Jonas Jenwald
c9eaf13ae4 Lookup more data in parallel in the PDFDocument.prototype.#parseSignatureDict method 2026-07-28 16:18:01 +02:00
Jonas Jenwald
1ce8e8a320 Move the ByteRange validation earlier when parsing signatures
Given that these checks are synchronous, we can avoid a little bit of unnecessary data-fetching if the `ByteRange` is invalid.
2026-07-28 16:18:01 +02:00
Jonas Jenwald
f38e8b659e Update the signatures-helpers to actually handle MissingDataExceptions
The `PDFDocument.prototype.signatures` getter returns a (shadowed) Promise, however the way that it invokes various helper-methods can lead to *intermittent* failures to parse the signature data.
These helper-methods will lookup a fair amount of Dictionary data, however any one of those cases could throw `MissingDataException` during document loading.

To avoid having to re-factor those methods a lot, and adding a bunch more `pdfManager.ensureDoc()` calls, they are instead made asynchronous and the Dictionary lookups changed to use `Dict.prototype.getAsync` (similar to the existing `fieldObjects` handling).
Technically this additional asynchronicity may be ever so slightly slower, however I don't think it matters in practice since: most PDFs don't have any signatures, the signature-UI is initialized lazily in the viewer, and finally fetching/parsing of signatures do not block rendering.
Also, note how multiple values are being fetched in parallel in order to attempt to reduce overall asynchronicity.

*Note:* The unit-test changes are essentially fixing pre-existing bugs, that this patch exposed, since the test-only `Dict` instances weren't able to fetch indirect objects.
2026-07-28 16:17:52 +02:00
calixteman
e7acffcef3
Update qcms wrapper
Few performance improvements have been made in the qcms wrapper, see:
2ae4ee7233
2026-07-27 20:33:49 +02:00
Jonas Jenwald
63a0f285b8 Reduce a tiny bit of duplication in the normalizeBlendMode helper 2026-07-27 13:59:38 +02:00
Tim van der Meij
2ea8820d92
Merge pull request #21641 from calixteman/perf/pattern-color
Convert shading colors in bulk, rather than one at a time
2026-07-26 17:49:24 +02:00
calixteman
526b69651f
Convert shading colors in bulk, rather than one at a time
The axial/radial ramps and the function-based lattice converted one color per
call, i.e. one Wasm round-trip each for `IccColorSpace` (hence for
`/DeviceCMYK`). Add `ColorSpace.getRgbItems`, overridden by `IccColorSpace` and
`AlternateCS`, to convert a whole batch at once.
2026-07-26 17:02:22 +02:00
calixteman
a0f100c4a8
Convert the /Indexed palette in a single base color space call
`IndexedCS` invoked the base color space once per palette entry, which is
cheap for e.g. `DeviceRgbCS` but not for `IccColorSpace` where every call
is a Wasm round-trip.
2026-07-26 14:54:24 +02:00
Tim van der Meij
d246a6c495
Merge pull request #21630 from calixteman/fix/formInfo-inherited-document-signatures
Detect inherited signature fields in form info
2026-07-26 11:57:59 +02:00
Tim van der Meij
150fbba6e0
Merge pull request #21628 from calixteman/fix/pdf-editor-inherited-signature-flags
Preserve inherited signature flags
2026-07-26 11:56:38 +02:00
Jonas Jenwald
a7b7cec2e7 Re-factor the "nested trailer dictionary" check (PR 4731 follow-up)
In the `pr4731.pdf` document the trailer is actually a Stream, rather than the expected Dictionary, hence update the "nested trailer dictionary" check to make that clearer.

*Note:* This is something that I happened to noticed while working on the previous patch.
2026-07-25 12:18:45 +02:00
Jonas Jenwald
1ee8705093 Re-factor the XRef class to use private fields
Part of this is very old code, hence modernizing it a little bit more really shouldn't hurt.
This patch also shortens some `XRef` code by using nullish coalescing assignment respectively ternary operators more.

Finally, adds the recently introduced `countUpdatesAfter` method to the `XRefMock`/`XRefWrapper` classes to avoid having to check for its existence.
2026-07-25 12:18:43 +02:00
Calixte Denizet
ac75b10be1 Detect inherited signature fields in form info 2026-07-24 21:43:32 +02:00
Calixte Denizet
27cf9e24f3 Preserve inherited signature flags 2026-07-24 20:42:26 +02:00
Tim van der Meij
05e100c76e
Merge pull request #21626 from calixteman/fix/pdf-editor-inherited-default-appearance
Preserve inherited text field appearances
2026-07-24 20:35:14 +02:00
Calixte Denizet
a97939b0d7 Preserve inherited text field appearances 2026-07-24 18:58:01 +02:00