Currently the code only updates the position when the length is defined, and it seems that this has "always" been wrong. Originally I believe that the `ChunkedStream` class was essentially a copy of the `Stream` class, and that implementation had the same problem until PR 20593.
Hopefully there's no code that relies on the current incorrect behaviour[1], since testing every aspect of the `ChunkedStream` implementation can be tricky given that these things are timing dependant.
---
[1] If there are, fixing those call-sites may be as easy calling `ChunkedStream.prototype.reset`.
Nowadays there's a lot of places in the code-base where we need to initialize or reset bounding boxes. Rather than spelling this out repeatedly, this patch adds new `Array`/`Float32Array` constants that can be copied or used as-is where appropriate.
We try to detect in the worker if some patterns or groups need to be drawn or not in isolation.
When they don't, we just draw them on the main canvas instead of drawing on a new canvas.
A pattern or a group is considered as being in isolation if it has some compositing rules or some transparency.
It improves the rendering performance of the pdf in bug 1731514.
It's possible to compute the final index-data size upfront, thus avoiding a bunch of intermediate allocations during index compilation.
This also means that a TypedArray can be used, rather than a plain Array, making it more efficient to insert the `objects` data.
This helps PDFs with large and complex CFF fonts the most, for example the PDFs in https://bugs.ghostscript.com/show_bug.cgi?id=706451 render ~40 percent faster (based on quick measurements in the viewer with `#pdfBug=Stats`).
Currently the `CFFCompiler.prototype.compile` implementation seem a bit inefficient, since the data is stored in a plain Array that needs to grow (a lot) during compilation. Additionally, adding a lot of entries isn't very efficient either and requires special handling of the "too many elements" case.
Some of the "helper" methods that use TypedArrays internally currently need to convert their return data to plain Arrays, via the `compileTypedArray` method, which adds even more intermediate allocations.
Note also that the `OpenTypeFileBuilder` has a special-case for writing plain Array data, which is only needed because of how the CFF compilation is implemented.
To improve this situation the `CFFCompiler.prototype.compile` method is re-factored to store its data in a TypedArray, whose initial size is estimated from the "raw" file size.
This removes the need for most intermediate allocations, and it also handles adding of "many elements" more efficiently.
This avoids effectively re-implementing an existing helper function, and the code is also simplified a tiny bit by building the final TypedArray header directly.
One drawback of the current implementation is that the GPU device can be
unavailable at the time of the first pattern fill, which causes the
GPU-accelerated canvas to be move on the main thread because of putImageData.
Most of the shading patterns stuff will be moved to the GPU and in order
to avoid creating some useless data we've to know if the GPU is available or not.
So in this patch we create the GPU device during the worker initialization
and pass a flag to the evaluator to know if the GPU is available or not.
This improves readability by removing "magic" numbers, and matches what
we already have for e.g. annotation and shading types.
Note that function type 1 does not exist in the specification, but that
also applies to everything higher than 4, so we can also remove the
specific handling of function type 1 and instead just let it fall
through to throwing an exception for unknown function types, in which we
now also log the provided function type to aid debugging.
It seems just as easy to lookup the needed data in the original arrays, rather than having to first create (and allocate) nested arrays for that purpose.
These classes, and various related code, became unused after PR 21023 with only unit-tests actually running that code now.
Also removes the `isEvalSupported` API option, since the `PostScriptCompiler` was the only remaining code where `eval` was used.
- Use the same `PartialEvaluator` instance for all annotations on the page, to reduce unnecessary object creation.
- Use `Object.hasOwn` to check if the annotations were already parsed, to avoid having to keep a separate boolean variable in-sync with the actual code.
The idea with this helper function is that once https://github.com/tc39/proposal-math-clamp/ becomes stable, all its call-sites should then be replaced by the native functionality.
It fixes#5046.
We just generate a mesh for the pattern rectangle where the color of each vertex is computed from the function.
Since the mesh is generated in the worker we don't really take into account the current transform when it's drawn.
That being said, there are maybe some possible improvements in using directly the gpu for the shading creation
which could then take into account the current transform, but it could only work with ps function we can convert
ino wgsl language and simple enough color spaces (gray and rgb).
The main goal is to remove the eval-based interpreter.
In order to have some good performances, the new parser performs some optimizations
on the AST (similar to the ones in the previous implementation),
and the Wasm compiler generates code for the optimized AST.
For now, in case of errors or unsupported features, the Wasm compiler returns null
and the old interpreter is used as a fallback.
Few things are still missing:
- a wasm-based interpreter using a stack (in case the ps code isn't stack-free);
- a better js implementation in case of disabled wasm.
but they will be added in follow-up patches.
This code already has an integration-test, however also having a unit-test shouldn't hurt since those are often easier to run and debug (and it nicely complements the existing `outline` unit-tests).
The patch also makes the following smaller changes to the method itself:
- Avoid creating and parsing an empty Array, when doing the `pageRef` search.
- Use `XRef.prototype.fetch` directly, when walking the parent chain, since the check just above ensures that the value is a Reference.
- Use the `lookupRect` helper when parsing the /BBox entry.