Looking at the `BinaryCMapStream` implementation, it's basically a "regular" `Stream` but with added functionality for reading compressed CMap data.
Hence, by letting `BinaryCMapStream` extend `Stream`, we can remove an effectively duplicate method and simplify/shorten the code a tiny bit.
Currently the `customNames` are read one byte at a time, in a loop, and at every iteration converted to a string.
This can be replaced with the `BaseStream.prototype.getString` method, which didn't exist back when this function was written.
This method is usually used with loops, and it should be a tiny bit more efficient to use an iterator directly rather than first iterating through ` Map`-values to create a temporary `Array` that we finally iterate through at the call-site.
Note that the `getRawValues` method is old code, and originally the `Dict` class stored its data in a regular `Object`, hence why the old code was written that way.
This method is usually used with loops, and it should be a tiny bit more efficient to use an iterator directly rather than first iterating through ` Map`-keys to create a temporary `Array` that we finally iterate through at the call-site.
Note that the `getKeys` method is old code, and originally the `Dict` class stored its data in a regular `Object`, hence why the old code was written that way.
This changes a number of loops currently using `Dict.prototype.{getKeys, getRaw}`, since it should be a tiny bit more efficient to use an iterator directly rather than first iterating through `Map`-keys to create a temporary `Array` that we finally iterate through at the call-site.
Note that the `getKeys` method is much older than `getRawEntries`, and originally the `Dict` class stored its data in a regular `Object`, hence why the old code was written that way.
This behaviour comes from the initial pdf.js commit but is wrong and
doesn't match other PDF readers like muPDF or pdfium.
From PDF Spec 7.3.3:
A PDF writer shall not use the PostScript language syntax for numbers with non-decimal radices (such
as 16#FFFE) or in exponential format (such as 6.02E23).
Change all these cases to use `Map.prototype.getOrInsertComputed()` instead, in combination with a helper function for creating the `Array`s (similar to the previous patch).
With the exception of the first invocation the callback function is unused, which means that a lot of pointless functions may be created.
To avoid this we introduce helper functions for simple cases, such as creating `Map`s and `Objects`s.
There's a number of classes where the constructors can be removed completely by instead using class fields, which help to slightly shorten the code.
It seems that `unicorn/prefer-class-fields` ESLint plugin, see PR 20657, unfortunately isn't able to detect all of these cases.
Rather than assigning it manually in every extending class, we can utilize the fact that the `AnnotationType`-entries are simply the upper-case version of the `/Subtype` (when it exists) in the Annotation dictionary.
This is not only shorter, but (in my opinion) it also simplifies the code.
*Note:* In order to keep the *five* different `BasePDFStreamRangeReader` implementations consistent, we purposely don't re-factor the `PDFWorkerStreamRangeReader` class to support `for await...of` iteration.
This leads to slightly shorter code[1] when initializing classes, and in some cases we can even remove the constructors, which shouldn't hurt; see https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-class-fields.md
It's probably possible to also change a lot of these class fields to private ones[2], however it's often difficult to tell at a glance if that's safe hence this patch only does this for the `PDFRenderingQueue`.
---
[1] This reduces the size of the `gulp mozcentral` output by 999 bytes, for a mostly mechanical code change.
[2] That sort of re-factoring should generally be done separately, on a class-by-class basis, to reduce the risk of regressions.
While we don't dispatch the actual range request after PR 10694 we still parse the returned data, which ends up being an *empty* `ArrayBuffer` and thus cannot affect the `ChunkedStream.prototype._loadedChunks` property.
Given that no actual data arrived, it's thus pointless[1] to invoke the `ChunkedStreamManager.prototype.onReceiveData` method in this case (and it also avoids sending effectively duplicate "DocProgress" messages).
---
[1] With the *possible* exception of `disableAutoFetch === false` being set, see f24768d7b4/src/core/chunked_stream.js (L499-L517) however that never happens when streaming is being used; note f24768d7b4/src/core/worker.js (L237-L238)
In all cases where we currently use `Response.prototype.arrayBuffer()` the result is immediately wrapped in a `Uint8Array`, which can be avoided by instead using the newer `Response.prototype.bytes()` method; see https://developer.mozilla.org/en-US/docs/Web/API/Response/bytes
We tried to lookup the font metrics using the font name as-is, which didn't work since the PDF file in question has non-embedded fonts with names that include commas.
Hence the font names need to be normalized here as well, similar to elsewhere in the font code.